最近在读周志明的《深入理解Java虚拟机2》和《Pratical Java》,结合面试的时候常常考到的一些问题,做一下笔记。
1、Java值传递 by value not by reference
《Pratical Java》第一个问题讲到的就是这个问题,Java中传值传的是值而不是引用。注意,这里所说的值不止普通值,还包括引用值。比如传应用对象的时候,传的就是一份copy的reference。这样说起来有些拗口,也有些强词夺理。但这不是我要关注的,我要关注的是传值过后对原值的影响。
例如
从打印的值可以看出,sf1的值改变了,而sf2的值没有变。通过打印出psf1和psf2前后的hashCode,可以看出,传进去的时候,psf1==sf1 ,psf2==sf2static void changePass(StringBuffer psf1,StringBuffer psf2){ psf1.append(psf2); psf2 = psf1; } public static void main(String[] args) { StringBuffer sf1 = new StringBuffer("A"); StringBuffer sf2 = new StringBuffer("B"); changePass(sf1, sf2); System.out.println(sf1+":"+sf2); //AB:B }
然后经过两行代码后 psf1==psf2 了。结合打印结果,我大胆地断言,Java传的是值而不是reference!
psf1装有sf1的引用,他利用这个引用去修改了sf1,这个很好理解。而psf2经过赋值后,的确装的也是psf1的引用,可是,这跟sf2没有半毛钱关系,它只是传进来的一份复制品而已。所以,但函数回到调用函数的时候,sf1还是它自己。
2、String这个变态!
String在Java中我觉得很像太监,半男不女。是没错,它是引用类型,但是它的+语句会让你崩溃。音乐又有一点基本类型的特点,最要命的是,它居然和int、float这些基本类型一样有常量池!!!好吧,常量池也是个变态,常量池位于方法区(Method Area)。
Java认为,这些常量之类的东西,你们总会用重复的,所以搞了个常量池,凡是基本类型,直接去常量池找,找不到再给你弄一个。这时候String也来凑热闹,凡是用+号或者“”来赋值的String都先去常量池找,有合适的直接把引用返回给它。如果用new 来实例的话,那就肯定是在堆中了,就不去常量池找了。
3、构造函数的初始化过程
class Super { int i = 10; Super(){ print(); i = 20; } void print(){ System.out.print(i); } } public class Sub extends Super{ int j = 30; public Sub() { print(); j = 40; } void print(){ System.out.print(j); } public static void main(String[] args) { System.out.print(new Sub().j);//03040 } }
从这里的打印结果就可以看出,好像并不是那么简单。我debug跟踪调试发现了两点:甲、当子类运行到构造名时,先去父类运行构造函数,同理,父类如果有爷爷类,那么运行到父类的构造名的时候,先去爷爷类运行构造函数,直到运行到java.lang.Object类.然后初始化数据,运行构造本体,类似递归。
乙、在父类的构造函数中,试图运行已被子类覆盖的程序的时候,不好意思,运行的是子类的。
以上,与君共赏!