java常见题2
6.String作为hashmap的键为什么好?
调用时放到成员变量了 效率会高一点
7.finally和return之间的纠缠
public class Test{
public int add(int a,int b){
try {
return a+b;
}
catch (Exception e) {
System.out.println("catch语句块");
}
finally{
System.out.println("finally语句块");
}
return 0;
}
public static void main(String argv[]){
Test test =new Test();
System.out.println("和是:"+test.add(9, 34));
}
}
链接:https://www.nowcoder.com/questionTerminal/f041115dd21148c981803a203cf13be7
来源:牛客网
先来看一段代码:
public abstract class Test {
public static void main(String[] args) {
System.out.println(beforeFinally());
}
public static int beforeFinally(){
int a = 0;
try{
a = 1;
return a;
}finally{
a = 2;
}
}
}
/**output:
1
*/
从结果上看,貌似finally
里的语句是在return
之后执行的,其实不然,实际上finally
里的语句是在在return
之前执行的。那么问题来了,既然是在之前执行,那为什么a
的值没有被覆盖了?
实际过程是这样的:当程序执行到try{}语句中的return方法时,它会干这么一件事,将要返回的结果存储到一个临时栈中,然后程序不会立即返回,而是去执行finally{}中的程序, 在执行a = 2
时,程序仅仅是覆盖了a的值,但不会去更新临时栈中的那个要返回的值 。执行完之后,就会通知主程序“finally的程序执行完毕,可以请求返回了”,这时,就会将临时栈中的值取出来返回。这下应该清楚了,要返回的值是保存至临时栈中的。
再来看一个例子,稍微改下上面的程序:
public abstract class Test {
public static void main(String[] args) {
System.out.println(beforeFinally());
}
public static int beforeFinally(){
int a = 0;
try{
a = 1;
return a;
}finally{
a = 2;
return a;
}
}
}
/**output:
2
*/
在这里,finally{}里也有一个return,那么在执行这个return时,就会更新临时栈中的值。同样,在执行完finally之后,就会通知主程序请求返回了,即将临时栈中的值取出来返回。故返回值是2.
总结:可以把return时看成一个临时储存了 然后去执行finally,finally过程中新的return可以覆盖旧的。
注意:finally块中的return语句会阻止异常的栈调用传输,使caller认为该方法已经正常返回,让catch中抛的异常失效。
finally块中的throw语句会覆盖try和catch语句中的异常。
8.不会初始化子类的3种情况
-
调用的是父类的static方法或者字段
static是在类构造方法执行初始化的。会触发子类的加载、父类的初始化,不会导致子类初始化
2.调用的是父类的final方法或者字段 子类和父类都不会初始化!
-
final+static修饰:使用ConstantValue属性赋值。
ConstantValue是字节码指令,final修饰的String和基本数据类型都在编译时就初始了
-
仅仅使用static修饰:在类构造方法中赋值。
类构造方法在初始化阶段,final修饰的String和基本数据在这些之前的编译阶段
final修饰,也就是在编译器把结果放入常量池中
- 通过数组来引用
SuperClass[] superClasses = new SuperClass[10];
9.String s = new String(" a ") 到底产生几个对象?
1或者2个
"a"在字符串常量池存在了 就是1个 不存在就是2个
10.String s=“java”+“and”+360 到底产生几个对象?;
1个
通过反编译。
因为字符串字面量拼接操作是在Java编译器编译期间就执行了,也就是说编译器编译时,直接把"java"、"and"和"360 “这三个字面量进行”+"操作得到一个"javaand360 " 常量,并且直接将这个常量放入字符串池中,这样做实际上是一种优化
这是因为在编译期间,应用了编译器优化中一种被称为常量折叠(Constant Folding)的技术,会将编译期常量的加减乘除的运算过程在编译过程中折叠。编译器通过语法分析,会将常量表达式计算求值,并用求出的值来替换表达式,而不必等到运行期间再进行运算处理,从而在运行期间节省处理器资源。
完整满足下面的要求 会常量折叠
- 被声明为
final
- 基本类型或者字符串类型
- 声明时就已经初始化
- 使用常量表达式进行初始化
String s = “java”
如果是 String s = “java”,如果原来字符串常量池有“java”,就直接将s指向字符串常量池的“java”,不会创建新的对象。如果原来字符串常量池没有“java”,则会在字符串常量池创建一个新的“java”对象;