数组易错题
1.判断以下代码的输出结果:
// 判断以下代码的输出结果
int[] arr1 = new int[] {1 , 2 , 3};
System.out.println(arr1); // 地址
char[] arr2 = new char[] {'a' , 'b' , 'c'};
System.out.println(arr2); // 遍历数组
原因:PrintStream类中实现了print()方法的重写,只有char类型的数组会直接打印。
面向对象易错题
1.多态面试题
class Base {
public void add(int a, int... arr) {
System.out.println("base");
}
}
class Sub extends Base {
public void add(int a, int[] arr) {
System.out.println("sub_1");
}
}
public class InterviewTest1 {
public static void main(String[] args) {
Base base = new Sub();
base.add(1, 2, 3);
}
}
问:在上面的代码中,add()调用的是哪个类中的方法?
解析:这个问题的难点在于子类中的add(int a, int[] arr)是否构成了重写。我们可以在编译器中用重载来试一下public void add(int a, int… arr)和public void add(int a, int[] arr)是否可以共存,如果可以共存,那说明这两个方法是重载方法,不能构成重写。注意重写的概念:子类对父类允许访问的方法,对其实现过程进行重新编写,返回值和形参列表都不变。
其实public void add(int a, int… arr)和public void add(int a, int[] arr)在同一个类中是不可以共存的,编译器认为可变参数int …arr等同于int[] arr。所以我们这里是实现了重写的。
答案:既然已经知道了子类构成了重载,那么我们知道,多态访问方法时,运行的是子类重写后的方法,最后输出的结果就是 sub_1。
此题的变形1:
class Base {
public void add(int a, int... arr) {
System.out.println("base");
}
}
class Sub extends Base {
public void add(int a, int[] arr) {
System.out.println("sub_1");
}
public void add(int a, int b, int c) {
System.out.println("sub_2");
}
}
public class InterviewTest1 {
public static void main(String[] args) {
Base base = new Sub();
base.add(1, 2, 3);
}
}
问:在上面的代码中,add()调用的是哪个类中的哪个方法?
解析:这里子类中的add(int a, int b, int c)是个烟雾弹,上面我已经说过了什么是重写,形参列表是不可变的,但是这里的形参列表发生了变化,这就属于子类方法间的重载。我们知道多态调用方法会调用子类重写后的方法,所以最后输出的还是sub1。
答案:sub1
此题的变形2:
class Base {
public void add(int a, int... arr) {
System.out.println("base");
}
}
class Sub extends Base {
public void add(int a, int[] arr) {
System.out.println("sub_1");
}
public void add(int a, int b, int c) {
System.out.println("sub_2");
}
}
public class InterviewTest1 {
public static void main(String[] args) {
Base base = new Sub()
Sub s = (Sub)base;
s.add(1,2,3);
}
}
问:在上面的代码中,add()调用的是哪个类中的哪个方法?
解析:这个考察的是向下转型,我们已经把base强转成了Sub类,在sub中有两个add方法,当参数个数不确定与参数个数确定的方法都符合调用的条件时,优先调用参数个数确定的方法。
答案:sub_2
2.==和equals有什么区别?
解析:此题最容易出错的地方是equals的说明,我们经常使用String类中的equals方法来比较两个字符串是否相等,但是String类中的equals方法是重写过的。因为经常使用String类中的equals方法,久而久之我们就形成了equals方法是用来比较值是否相等的错误观念。
答案:
- ==可以用来比较基本数据类型和引用数据类型。用来比较基本数据类型时,比较的就是两个变量存储的数值是否相等。如果用来比较引用数据类型,那么比较的就是两个变量的地址值是否相等。
- equals方法是Object类中定义的方法,如果该方法没有被重写过,那么也是用==来比较两个对象。如果要比较的类中重写了equals方法,那么才会比较类中的属性是否相等。
包装类易错题
1.判断下面代码的执行结果
Object o1 = true ? new Integer(1) : new Double(2.0);
System.out.println(o1);
Object o2;
if (true)
o2 = new Integer(1);
else
o2 = new Double(2.0);
System.out.println(o2)
解析:我们很容易认为o1的结果是1,其实不对。这个题的易错点是三目运算符,三目运算符要求返回值类型要一致,根据自动类型转换,会把Integer类型的数值转为Double类型。
答案:
o1:1.0
o2:1
2.判断下面代码的执行结果
Integer i = new Integer(1);
Integer j = new Integer(1);
System.out.println(i == j);//
Integer m = 1;
Integer n = 1;
System.out.println(m == n);//
Integer x = 128;
Integer y = 128;
System.out.println(x == y);//
解析:首先我们要知道==在比较两个对象的时候,比较的是地址值。new的对象地址值都是不一样的,所以第一个输出打印的是false。难点在于第二个和第三个输出。
我们在Integer的源码中可以看到,Integer定义了一个静态内部类IntegerCache,其中有一个属性时cache[]数组,这个数组存储的是-128-127之间的整数。如果我们定义的数值在这个范围之内,就直接去cache[]数组中取这个数。
答案:false、true、false
多线程易错题
1.wait()和sleep()有什么异同?
答案:相同:wait()和sleep()都可以使线程进入阻塞状态。
不同:wait()在使线程进入阻塞状态的同时会释放同步锁,sleep()不会;
wait()声明在Object类中,sleep()声明在Thread类中;
wait()只能使用在同步方法或同步代码块中,sleep()可以使用在任何需要调用的场景下。
2.线程的创建方式有几种?
答案:四种。
1)继承Thread类。
2)实现Runnable接口。
3)实现Callable接口。
4)线程池。
字符串易错题
1.String、StringBuffer、StringBuilder的区别?
答案:
String:不可变的字符序列;底层使用char[] 数组存储;
StringBuffer:可变的字符序列,线程安全的,效率低;底层使用char[] 数组存储;
StringBuilder:可变的字符序列,JDK 5.0新增,线程不安全,效率高;底层使用char[] 数组存储;