一、类的构造函数
1.测试代码:
1 public class Test { 2 public static void main(String[] args) { 3 Foo obj1 = new Foo(); 4 } 5 } 6 7 class Foo{ 8 int value; 9 public Foo(int initValue){ 10 value = initValue; 11 } 12 }
2.测试截图:
以上代码编译无法通过:
错误信息为:“The constructor Foo() is undefined”(构造函数Foo()未定义)
3.结论:
二、类初始化规则:
测试代码一:
1 public class Test { 2 public static void main(String[] args) { 3 InitializeBlockClass obj = new InitializeBlockClass(); 4 System.out.println("field:" + obj.field); 5 } 6 } 7 8 class InitializeBlockClass{ 9 { 10 field = 200; 11 } 12 public int field = 100; 13 /*public InitializeBlockClass(int value){ 14 this.field = value; 15 }*/ 16 /*public InitializeBlockClass(){ 17 field = 300; 18 }*/ 19 }
执行结果:
测试代码二:
1 public class Test { 2 public static void main(String[] args) { 3 InitializeBlockClass obj = new InitializeBlockClass(); 4 System.out.println("field:" + obj.field); 5 } 6 } 7 8 class InitializeBlockClass{ 9 public int field = 100; 10 { 11 field = 200; 12 } 13 /*public InitializeBlockClass(int value){ 14 this.field = value; 15 }*/ 16 /*public InitializeBlockClass(){ 17 field = 300; 18 }*/ 19 }
执行结果:
结论:
如果没有构造函数对成员变量赋值,则成员变量的初值取决于 对该变量赋值的初始化代码块 与 对变量定义初始值 的先后顺序,最终等于最后被赋予的值。
测试代码三:
1 public class Test { 2 public static void main(String[] args) { 3 InitializeBlockClass obj = new InitializeBlockClass(123); 4 System.out.println("field:" + obj.field); 5 } 6 } 7 8 class InitializeBlockClass{ 9 10 public int field = 100; 11 public InitializeBlockClass(int value){ 12 System.out.println("field:" + this.field); 13 this.field = value; 14 } 15 { 16 field = 200; 17 } 18 }
执行结果:
结论:
在本程序代码中,由构造函数输出的field为200,说明程序先执行了初始化代码块,后执行构造函数,再结合测试一、二得出结论:
类初始化顺序为:先是初始化代码块对变量赋值和定义变量时赋值(取决于程序代码中二者先后位置),后执行构造函数。
三、静态初始化块执行顺序:
测试代码:
1 class Root{ 2 static{ 3 System.out.println("Root的静态初始化块"); 4 } 5 { 6 System.out.println("Root的普通初始化块"); 7 } 8 public Root(){ 9 System.out.println("Root的无参数的构造器"); 10 } 11 } 12 class Mid extends Root 13 { 14 static{ 15 System.out.println("Mid的静态初始化块"); 16 } 17 { 18 System.out.println("Mid的普通初始化块"); 19 } 20 public Mid(){ 21 System.out.println("Mid的无参数的构造器"); 22 } 23 public Mid(String msg){ 24 //通过this调用同一类中重载的构造器 25 this(); 26 System.out.println("Mid的带参数构造器,其参数值:" + msg); 27 } 28 } 29 class Leaf extends Mid 30 { 31 static{ 32 System.out.println("Leaf的静态初始化块"); 33 } 34 { 35 System.out.println("Leaf的普通初始化块"); 36 } 37 public Leaf() 38 { 39 //通过super调用父类中有一个字符串参数的构造器 40 super("Java初始化顺序演示"); 41 System.out.println("执行Leaf的构造器"); 42 } 43 44 } 45 46 public class TestStaticInitializeBlock{ 47 public static void main(String[] args) { 48 new Leaf(); 49 } 50 }
执行结果:
结论:
另外,执行顺序为:先从父类到子类依次执行静态初始化块,再从父类到子类依次执行普通初始化块和构造函数。
四、如何在静态方法中访问类的实例成员
测试代码:
1 public class Test { 2 public static void main(String[] args) { 3 B.foo(); 4 } 5 } 6 class B{ 7 public void foo2(){ 8 System.out.println("访问实例成员"); 9 } 10 public static void foo(){ 11 B c = new B(); 12 c.foo2(); 13 } 14 }
执行结果:
五、Integer的诡异特性:
测试代码:
1 public class StrangeIntegerBehavior 2 { 3 public static void main(String[] args) 4 { 5 Integer i1=100; 6 Integer j1=100; 7 System.out.println(i1==j1); 8 Integer i2=129; 9 Integer j2=129; 10 System.out.println(i2==j2); 11 } 12 }
执行结果:
原因分析:
反编译结果:
Integer.java中valueOf()源代码:
1 /** 2 * Returns an {@code Integer} instance representing the specified 3 * {@code int} value. If a new {@code Integer} instance is not 4 * required, this method should generally be used in preference to 5 * the constructor {@link #Integer(int)}, as this method is likely 6 * to yield significantly better space and time performance by 7 * caching frequently requested values. 8 * 9 * This method will always cache values in the range -128 to 127, 10 * inclusive, and may cache other values outside of this range. 11 * 12 * @param i an {@code int} value. 13 * @return an {@code Integer} instance representing {@code i}. 14 * @since 1.5 15 */ 16 public static Integer valueOf(int i) { 17 if (i >= IntegerCache.low && i <= IntegerCache.high) 18 return IntegerCache.cache[i + (-IntegerCache.low)]; 19 return new Integer(i); 20 }
其中,IntegerCache为:
1 /** 2 * Cache to support the object identity semantics of autoboxing for values between 3 * -128 and 127 (inclusive) as required by JLS. 4 * 5 * The cache is initialized on first usage. The size of the cache 6 * may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option. 7 * During VM initialization, java.lang.Integer.IntegerCache.high property 8 * may be set and saved in the private system properties in the 9 * sun.misc.VM class. 10 */ 11 12 private static class IntegerCache { 13 static final int low = -128; 14 static final int high; 15 static final Integer cache[]; 16 17 static { 18 // high value may be configured by property 19 int h = 127; 20 String integerCacheHighPropValue = 21 sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); 22 if (integerCacheHighPropValue != null) { 23 try { 24 int i = parseInt(integerCacheHighPropValue); 25 i = Math.max(i, 127); 26 // Maximum array size is Integer.MAX_VALUE 27 h = Math.min(i, Integer.MAX_VALUE - (-low) -1); 28 } catch( NumberFormatException nfe) { 29 // If the property cannot be parsed into an int, ignore it. 30 } 31 } 32 high = h; 33 34 cache = new Integer[(high - low) + 1]; 35 int j = low; 36 for(int k = 0; k < cache.length; k++) 37 cache[k] = new Integer(j++); 38 39 // range [-128, 127] must be interned (JLS7 5.1.7) 40 assert IntegerCache.high >= 127; 41 } 42 43 private IntegerCache() {} 44 }
通过这两段代码可以看出,在通过valueof方法创建Integer类型对象时,取值范围为[-128,127],数值在这个区间里,指针指向IntegerCache.cache中已经存在的对象引用,当数值超出这个范围,就会创建一个新的对象。而对对象使用“==”是判断两个对象是否是同一个,所以i1 == j1,i2 != j2。