logo资料库

BTA 常问的 Java基础39道常见面试题及详细答案.docx

第1页 / 共35页
第2页 / 共35页
第3页 / 共35页
第4页 / 共35页
第5页 / 共35页
第6页 / 共35页
第7页 / 共35页
第8页 / 共35页
资料共35页,剩余部分请下载后查看
最近看到网上流传着,各种面试经验及面试题,往往都是一大堆技术题目贴上去,而没有答 案。 为此我业余时间整理了,Java 基础常见的 40 道常见面试题,及详细答案,望各路大牛,发 现不对的地方,不吝赐教,留言即可。 八种基本数据类型的大小,以及他们的封装类 引用数据类型 Switch 能否用 string 做参数 equals 与==的区别 自动装箱,常量池 Object 有哪些公用方法 Java 的四种引用,强弱软虚,用到的场景 Hashcode 的作用 HashMap 的 hashcode 的作用 为什么重载 hashCode 方法? ArrayList、LinkedList、Vector 的区别 String、StringBuffer 与 StringBuilder 的区别 Map、Set、List、Queue、Stack 的特点与用法 HashMap 和 HashTable 的区别 JDK7 与 JDK8 中 HashMap 的实现 HashMap 和 ConcurrentHashMap 的区别,HashMap 的底层源码 ConcurrentHashMap 能完全替代 HashTable 吗 为什么 HashMap 是线程不安全的 如何线程安全的使用 HashMap 多并发情况下 HashMap 是否还会产生死循环 TreeMap、HashMap、LindedHashMap 的区别 Collection 包结构,与 Collections 的区别 try?catch?finally,try 里有 return,finally 还执行么 Excption 与 Error 包结构,OOM 你遇到过哪些情况,SOF 你遇到过哪些情况 Java(OOP)面向对象的三个特征与含义 Override 和 Overload 的含义去区别 Interface 与 abstract 类的区别 Static?class?与 non?static?class 的区别 foreach 与正常 for 循环效率对比 Java?IO 与 NIO java 反射的作用于原理 泛型常用特点 解析 XML 的几种方式的原理与特点:DOM、SAX Java1.7 与 1.8,1.9,10 新特性 设计模式:单例、工厂、适配器、责任链、观察者等等 JNI 的使用 AOP 是什么 OOP 是什么
AOP 与 OOP 的区别 八种基本数据类型的大小,以及他们的封装类 八种基本数据类型:int、short、float、double、long、boolean、byte、char。 封装类分别是:Integer、Short、Float、Double、Long、Boolean、Byte、Character。 引用数据类型 引用数据类型是由类的编辑器定义的,他们是用于访问对象的。这些变量被定义为不可更改 的特定类型。 例如:Employee, Puppy 等等 类对象和数组变量就是这种引用数据类型。 任何引用数据类型的默认值都为空。 一个引用数据类型可以被用于任何声明类型和兼容类型的对象。 Switch 能否用 string 做参数 jdk7 之前 switch 只能支持 byte、short、char、int 这几个基本数据类型和其对应的封装类型。 switch 后面的括号里面只能放 int 类型的值,但由于 byte,short,char 类型,它们会?自动? 转换为 int 类型(精精度小的向大的转化),所以它们也支持。 jdk1.7 后 整形,枚举类型,boolean,字符串都可以。 原理 switch (expression) case constant1: // 括号里是一个表达式,结果是个整数{ // case 后面的标号,也是个整数 group of statements 1; break; case constant2: group of statements 2; break; ... default: default group of statements } jdk1.7 后,整形,枚举类型,boolean,字符串都可以。
public class TestString { static String string = "123"; public static void main(String[] args) { switch (string) { case "123": System.out.println("123"); break; case "abc": System.out.println("abc"); break; default: System.out.println("defauls"); break; } } } 为什么 jdk1.7 后又可以用 string 类型作为 switch 参数呢? 其实,jdk1.7 并没有新的指令来处理 switch string,而是通过调用 switch 中 string.hashCode, 将 string 转换为 int 从而进行判断。 equals 与==的区别 使用==比较原生类型如:boolean、int、char 等等,使用 equals()比较对象。 1、==是判断两个变量或实例是不是指向同一个内存空间。 equals 是判断两个变量或实例所指向的内存空间的值是不是相同。 2、==是指对内存地址进行比较。 equals()是对字符串的内容进行比较。 3、==指引用是否相同。 equals()指的是值是否相同。 public static void main(String[] args) { String a = new String("ab"); // a 为一个引用 String b = new String("ab"); // b 为另一个引用,对象的内容一样 String aa = "ab"; // 放在常量池中 String bb = "ab"; // 从常量池中查找 System.out.println(aa == bb); // true System.out.println(a == b); // false,非同一对象
System.out.println(a.equals(b)); // true System.out.println(42 == 42.0); // true } public static void main(String[] args) { Object obj1 = new Object(); Object obj2 = new Object(); System.out.println(obj1.equals(obj2));//false System.out.println(obj1==obj2);//false obj1=obj2; System.out.println(obj1==obj2);//true System.out.println(obj2==obj1);//true } 自动装箱,常量池 自动装箱 在 jdk?1.5 之前,如果你想要定义一个 value 为 100 的 Integer 对象,则需要如下 定义: Integer i = new Integer(100); int intNum1 = 100; //普通变量 Integer intNum2 = intNum1; //自动装箱 int intNum3 = intNum2; //自动拆箱 Integer intNum4 = 100; //自动装箱 上面的代码中,intNum2 为一个 Integer 类型的实例,intNum1 为 Java 中的基础数据类型, 将 intNum1 赋值给 intNum2 便是自动装箱;而将 intNum2 赋值给 intNum3 则是自动拆箱。 八种基本数据类型: boolean byte char shrot int long float double ,所生成的变量相当于常 量。 基本类型包装类:Boolean Byte Character Short Integer Long Float Double。 自动拆箱和自动装箱定义: 自动装箱是将一个 java 定义的基本数据类型赋值给相应封装类的变量。 拆箱与装箱是相反的操作,自动拆箱则是将一个封装类的变量赋值给相应基本数据类型的变 量。 Object 有哪些公用方法 Object 是所有类的父类,任何类都默认继承 Object clone 保护方法,实现对象的浅复制,只有实现了 Cloneable 接口才可以调用该方法,否则抛出
CloneNotSupportedException 异常。 equals 在 Object 中与==是一样的,子类一般需要重写该方法。 hashCode 该方法用于哈希查找,重写了 equals 方法一般都要重写 hashCode 方法。这个方法在一些 具有哈希功能的 Collection 中用到。 getClass final 方法,获得运行时类型 wait 使当前线程等待该对象的锁,当前线程必须是该对象的拥有者,也就是具有该对象的锁。 wait() 方法一直等待,直到获得锁或者被中断。 wait(long timeout) 设定一个超时间隔,如果在规定时间内没有获得锁就返回。 调用该方法后当前线程进入睡眠状态,直到以下事件发生 1、其他线程调用了该对象的 notify 方法。 2、其他线程调用了该对象的 notifyAll 方法。 3、其他线程调用了 interrupt 中断该线程。 4、时间间隔到了。 5、此时该线程就可以被调度了,如果是被中断的话就抛出一个 InterruptedException 异常。 notify 唤醒在该对象上等待的某个线程。 notifyAll 唤醒在该对象上等待的所有线程。 toString 转换成字符串,一般子类都有重写,否则打印句柄。 Java 的四种引用,强弱软虚,用到的场景 从 JDK1.2 版本开始,把对象的引用分为四种级别,从而使程序能更加灵活的控制对象的生 命周期。这四种级别由高到低依次为:强引用、软引用、弱引用和虚引用。 1、强引用 最普遍的一种引用方式,如 String s = "abc",变量 s 就是字符串“abc”的强引用,只要强引 用存在,则垃圾回收器就不会回收这个对象。
2、软引用(SoftReference) 用于描述还有用但非必须的对象,如果内存足够,不回收,如果内存不足,则回收。一般用 于实现内存敏感的高速缓存,软引用可以和引用队列 ReferenceQueue 联合使用,如果软引 用的对象被垃圾回收,JVM 就会把这个软引用加入到与之关联的引用队列中。 3、弱引用(WeakReference) 弱引用和软引用大致相同,弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的 生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用 的对象,不管当前内存空间足够与否,都会回收它的内存。 4、虚引用(PhantomReference) 就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象 仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。 虚 引用主要用来跟踪对象被垃圾回收器回收的活动。 虚引用与软引用和弱引用的一个区别在于: 虚引用必须和引用队列 (ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时, 如果发现它还有虚引,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队 列中。 Hashcode 的作用 http://blog.csdn.net/seu_calv... 1、HashCode 的特性 (1)HashCode 的存在主要是用于查找的快捷性,如 Hashtable,HashMap 等,HashCode 经常用于确定对象的存储地址。 (2)如果两个对象相同,?equals 方法一定返回 true,并且这两个对象的 HashCode 一定相 同。 (3)两个对象的 HashCode 相同,并不一定表示两个对象就相同,即 equals()不一定为 true, 只能够说明这两个对象在一个散列存储结构中。 (4)如果对象的 equals 方法被重写,那么对象的 HashCode 也尽量重写。 2、HashCode 作用 Java 中的集合有两类,一类是 List,再有一类是 Set。前者集合内的元素是有序的,元素可
以重复;后者元素无序,但元素不可重复。 equals 方法可用于保证元素不重复,但如果每增加一个元素就检查一次,若集合中现在已经 有 1000 个元素,那么第 1001 个元素加入集合时,就要调用 1000 次 equals 方法。这显然 会大大降低效率。?于是,Java 采用了哈希表的原理。 哈希算法也称为散列算法,是将数据依特定算法直接指定到一个地址上。 这样一来,当集合要添加新的元素时,先调用这个元素的 HashCode 方法,就一下子能定位 到它应该放置的物理位置上。 (1)如果这个位置上没有元素,它就可以直接存储在这个位置上,不用再进行任何比较了。 (2)如果这个位置上已经有元素了,就调用它的 equals 方法与新元素进行比较,相同的话 就不存了。 (3)不相同的话,也就是发生了 Hash key 相同导致冲突的情况,那么就在这个 Hash key 的地方产生一个链表,将所有产生相同 HashCode 的对象放到这个单链表上去,串在一起(很 少出现)。 这样一来实际调用 equals 方法的次数就大大降低了,几乎只需要一两次。 如何理解 HashCode 的作用: 从 Object 角度看,JVM 每 new 一个 Object,它都会将这个 Object 丢到一个 Hash 表中去, 这样的话,下次做 Object 的比较或者取这个对象的时候(读取过程),它会根据对象的 HashCode 再从 Hash 表中取这个对象。这样做的目的是提高取对象的效率。若 HashCode 相同再去调用 equal。 3、HashCode 实践(如何用来查找) HashCode 是用于查找使用的,而 equals 是用于比较两个对象是否相等的。 (1)例如内存中有这样的位置 0 1 2 3 4 5 6 7 而我有个类,这个类有个字段叫 ID,我要把这个类存放在以上 8 个位置之一,如果不用 HashCode 而任意存放,那么当查找时就需要到这八个位置里挨个去找,或者用二分法一类 的算法。 但以上问题如果用 HashCode 就会使效率提高很多 定义我们的 HashCode 为 ID%8,比如我们的 ID 为 9,9 除 8 的余数为 1,那么我们就把该 类存在 1 这个位置,如果 ID 是 13,求得的余数是 5,那么我们就把该类放在 5 这个位置。 依此类推。
(2)但是如果两个类有相同的 HashCode,例如 9 除以 8 和 17 除以 8 的余数都是 1,也就 是说,我们先通过?HashCode 来判断两个类是否存放某个桶里,但这个桶里可能有很多类, 那么我们就需要再通过 equals 在这个桶里找到我们要的类。 请看下面这个例子 public class HashTest { private int i; public int getI() { return i; } public void setI(int i) { this.i = i; } public int hashCode() { return i % 10; } public final static void main(String[] args) { HashTest a = new HashTest(); HashTest b = new HashTest(); a.setI(1); b.setI(1); Set set = new HashSet(); set.add(a); set.add(b); System.out.println(a.hashCode() == b.hashCode()); System.out.println(a.equals(b)); System.out.println(set); } } 输出结果为: true False [HashTest@1, HashTest@1] 以上这个示例,我们只是重写了 HashCode 方法,从上面的结果可以看出,虽然两个对象的 HashCode 相等,但是实际上两个对象并不是相等,因为我们没有重写 equals 方法,那么就 会调用 Object 默认的 equals 方法,显示这是两个不同的对象。
分享到:
收藏