03-类与对象(动手动脑)

一、类的构造函数

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。

原文地址:https://www.cnblogs.com/lzq666/p/7697802.html