谈谈Java面试中“陷阱题”

谈谈Java面试中“陷阱题”

前面整理了一些Java的基础知识
这里最后整理了一些笔试面试中经常会犯错的陷阱题

Java中创建实例化对象有哪些方式?
1
2
3
4
5
1,最常见的方式是使用new语句创建一个对象
2,通过工厂方法返回对象(工厂方法涉及到框架)
3,动用反射机制创建实例化对象,Class类的三种方法或者通过类类型的newInstance()实例方法
4,调用对象的clone方法(俗称克隆法)
5,通过IO留的反序列化手段,调用ObjectInputStream对象的readObject方法
关于 a++ 跟 ++a
1
2
3
4
5
6
7
8
// 加号在前,先做加法再使用;加号再后,先使用再做加法
int a = 2;
System.out.println(a++ +","+ ++a); // 2.4
System.out.println(a); // 4
System.out.println(a++); // 4
System.out.println(a); // 5
System.out.println(++a); // 6
System.out.println(a); // 6
switch case 语句陷阱
1
2
3
4
5
6
7
8
9
10
StringBuilder sb = new StringBuilder();
switch(1){
case 1: sb.append("hello");
case 2: sb.append("3");
case 3: sb.append("6");
default : sb.append("9");
}
System.out.println(sb.toString());
// 打印结果:hello369
// 因为没有break所以会继续往下执行
Java中的锁
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 1,普通同步方法,锁是当前实例对象
// 2,静态同步方法,锁是当前类的class对象
// 3,同步方法块,锁是括号里面的对象

public class SynchronizedTest
{
public synchronized void method1(){}
public synchronized void method2(){}
public static synchronized void method3(){}
public static synchronized void method4(){}
}

// 那么,有SynchronizedTest的两个实例a和b,对于一下的几个选项有哪些能被一个以上的线程同时访问呢?
A. a.method1() vs a.method2() [x]
B. a.method1() vs b.method1() [√]
C. a.method3() vs b.method4() [x]
D. a.method3() vs b.method3() [x]
E. a.method1() vs a.method3() [√]
// 正确答案是:B,E
对于“try-catch-finally”,若try语句块中包含“return”语句,finally语句块会执行吗
1
2
3
4
5
答案是会执行。只有两种情况finally块中的语句不会被执行:

调用了System.exit()方法;

JVM“崩溃”了。
能否编译通过,输出结果是什么
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class A{
public static int X;
static{
System.out.println(Test.B);
X = Test.B + 1;
}
}
class C{
public static int Z;
static{
System.out.println("C");
Z = Test.B + 1;
}
}
public class Test
{
public static int B = A.X + 1;
static{System.out.println(A.X);}
public static void main(String[] args)
{
System.out.println(A.X+ "," +Test.B);
int a = C.Z;
}
}
//输出结果,解释见下面类加载的时机。
0
1
1,2
C
类加载的时机
1
2
3
4
5
第一:生成该类对象的时候,会加载该类及该类的所有父类;

第二:访问该类的静态成员的时候;

第三:class.forName("类名");
java中各成员的执行顺序
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
//(1)父类静态成员和静态初始化块,按在代码中出现的顺序依次执行。
//(2)子类静态成员和静态初始化块,按在代码中出现的顺序依次执行。
//(3)父类实例成员和实例初始化块,按在代码中出现的顺序依次执行。
//(4)执行父类构造方法。
//(5)子类实例成员和实例初始化块,按在代码中出现的顺序依次执行。
//(6)执行子类构造方法。

public class Parent
{
{
System.out.println("Parent block");
}
static{
System.out.println("Parent static block");
}
public Parent(){
System.out.println("Parent construct method");
}
}
public class Son extends Parent
{
{
System.out.println("son block");
}
static{
System.out.println("son static block");
}
public Son(){
System.out.println("son construct method");
}
}
public class Test
{
public static void main(String[] args)
{
new Son();
}
}
//输出结果
Parent static block
son static block
Parent block
Parent construct method
son block
son construct method
关于字符串的总结
1
2
3
4
5
6
引号("")创建的字符串在字符串池中

new创建字符串时首先查看池中是否有相同值的字符串
如果有,则拷贝一份到堆中,然后返回堆中地址;
如果池中没有,则在堆中创建一份,然后返回堆中地址
注意:此时不需要从堆中复制到池中,否则,堆中字符串奖永远是池中的子集,浪费池的空间
关于Integer对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
Integer int1 = 88;
Integer int2 = Integer.valueOf(88);
Integer int3 = new Integer(88);

System.out.println(int1 == int2);
System.out.println(int1 == int3);
System.out.println(int2 == int3);

Integer int4 = 188;
Integer int5 = Integer.valueOf(188);
Integer int6 = new Integer(188);

System.out.println(int4 == int5);
System.out.println(int4 == int6);
System.out.println(int5 == int6);

// 输出结果:
true
false
false
false
false
false

// 解析:
// Integer类中维护了一个内部类IntegerCache,它会缓存[-128, 127]之间的数据
// 所以在调用value或者自动装箱时候,会直接返回缓存中的数据,而不会创建新的对象
// Long、Short、Byte也有类似缓存,Float、Double没有

IntegerCache源码如下(jdk1.8)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];

static {
// high value may be configured by property
int h = 127;
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
high = h;

cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);

// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}

private IntegerCache() {}
}
作者

Trainoo

发布于

2018-06-27

更新于

2020-06-02

许可协议