1、静态块和构造方法的执行顺序
题目
写出如下代码的输出。
public class B {
static {
System.out.println("B Static");
}
public B(){
System.out.println("B Constructor");
}
}
public class A extends B {
static {
System.out.println("A Static");
}
public A(){
System.out.println("A Constructor");
}
}
public class Test {
public static void main(String[] args){
A a1 = new A();
A a2 = new A();
}
}
答案
B Static
A Static
B Constructor
A Constructor
B Constructor
A Constructor
解释
在第一次构造类的实例时,类中静态代码块,先于构造函数执行,而且只执行一次。在继承层次中,父类的构造函数先于子类执行。
2、自加运算符
题目
写出如下代码的输出。
public class Test {
public static void main(String[] args){
Test t = new Test();
int i = 0;
t.increment(i);
i = i++;
System.out.println(i);
}
public void increment(int i){
i++;
}
}
答案
0
解释
好多人可能以为结果是1,i = i++
表达式中,赋值完成之后,i自增成了1。而实际上,i++
这个表达式的结果是0,但是这个表达式执行完成之后,i的值编程了1,最后,i又被赋值了i++
表达式的值(也就是0),1的值又被覆盖成了0。这就是为什么,最后的结果是0。
3、字符串
题目
如下两条字符串相关的Java代码分别会创建几个String对象:
(1) String a = new String("asdf");
(2) String b = "zxcv" + "qwer";
答案
(1) 2
(2) 3
解释
Java语言中,String类有一种独特的创建对象的方式,就是通过双引号内括文本的方式来创建字符串对象。和一般new创建出的对象不同,这些通过字符串直接创建的对象,存储在JVM的字符串池中。当通过双引号内括文本的方式创建字符串时,JVM会先检查当前字符串池中是否已经有内容为该文本的字符串对象:如果有的话,直接将该对象的引用返回;如果没有,就在字符串池中创建一个新的字符串对象。通过双引号文本的方式创建的String对象之间使用“+”连接产生的新对象也会被加入字符串池。对于所有包含new方式新建对象(包括null)的“+”连接表达式,它所产生的新对象都不会被加入字符串池中。
第一个语句中"asdf"
在字符串池中创建了一个对象,同时,new String("asdf")
操作,实际上在调用String类接受一个String对象作为参数的构造函数,也创建了一个对象。所以,一共创建了两个对象。
第二个语句中,"zxcv"
和"qwer"
分别在字符串池中创建了一个对象,+
连接操作也在字符串池中创建了一个新的对象,变量b指向这个对象,所以一共创建了三个对象。
另外,Java中String类是不可改变的类。一旦String对象被创建之后,这个对象内存储的文本内容都不能被修改,直到这个对象被销毁。任何对String对象的操作,JVM在实现上实际上都是通过创建新对象,回收旧对象来实现的,效率比较低。所以,涉及频繁修改字符串的情况,推荐使用StringBuffer和StringBuilder。
4、StringBuffer和StringBuilder
题目
简述StringBuffer和StringBuilder的区别。
答案
StringBuffer与StringBuilder中的方法和功能基本是等价的。
StringBuffer中的方法大都采用了synchronized关键字进行修饰,是线程安全的。而StringBuilder没有这个修饰,可以被认为是线程不安全的。
在单线程程序下,StringBuilder效率更快,因为它不需要加锁,不具备多线程安全。而StringBuffer则每次都需要判断锁,效率相对更低。
5、Java中字面常量的默认数据类型
题目
如下的代码会不会有编译报错。
(1) Long a = 3;
(2) float b = 5.6;
答案
(1) 编译报错
(2) 编译报错
解释
Java语言中,对于float,double和long类型的常量,都有指定的后缀标识,如float(3.3f)、double(3.3d)、long类型(4.4L或者4.4l,一般推荐大写L,便于和1区分)。如果没有指定后缀,对于整数是int类型,对于小数是double类型。
第一题中,3是int类型,给封装器类型变量赋值,按说如果赋值给Integer类型的变量会发生自动装箱,成功赋值。但是,这里是赋值给Long类型变量,所以编译报错java: 不兼容的类型: int无法转换为java.lang.Long
。
第二个题中,5.6默认是double类型的,双精度类型,精度是17位有效数字,取值范围是10的-308次方到10的308次方,double占用8个字节的存储空间。而float是单精度类型,精度是8位有效数字,取值范围是10的-38次方到10的38次方,float占用4个字节的存储空间。这种转换称为窄型转换,编译报错java: 不兼容的类型: 从double转换到float可能会有损失
。
6、Java自动装箱和自动拆箱
题目
写出如下代码的执行结果:
public class Test {
public static void main(String[] args){
Integer a = new Integer(33);
Integer b = new Integer(33);
System.out.println(a == b);
Integer c = 789;
Integer d = 789;
System.out.println(c == d);
int e = 85;
Integer f = new Integer(85);
System.out.println(e == f);
int g = 85;
Integer h = new Integer(80);
System.out.println(h < g);
Integer m = 27;
Integer n = 27;
System.out.println(m == n);
}
}
网友评论