JAVA基础(二):函数执行顺序(构造函数,多态,this指针)

JAVA基础(二):函数执行顺序(构造函数,多态,this指针)

<示例1>
请写出运行结果
1   abstract   class  Glyph {
 
2       Glyph() {
 
3             System.out.println( " Glyph() before draw() " );
 
4             draw();  // 不明白的地方是这里. 
 5            System.out.println( " Glyph() after draw() " );
 
6        }
 
 
7     abstract   void  draw();
 
8  }
 
 
9  
10   class  RoundGlyph  extends  Glyph {
11     private   int  radius  =   1 ;
12     RoundGlyph( int  r) {
13         radius  =  r;
14         System.out.println( " RoundGlyph.RoundGlyph(), radius =  "   +  radius);
15     }
 
16
17    void  draw() {
18       // radius = z; 
19         System.out.println( " RoundGlyph.draw(), radius =  "   +  radius);
20    }
 
21  }
 
22  
23   public   class  PolyConstructors {
24      public   static   void  main(String[] args) {
25              new  RoundGlyph( 5 );
26        }
 
27  }

答案
1  Glyph() before draw()
2  RoundGlyph.draw(), radius  =   0 
3  Glyph() after draw()
4  RoundGlyph.RoundGlyph(), radius  =   5
分析
 1类初始化时构造函数调用顺序:
 2 首先加载类,遇到extends字样会停止加载当前类,加载父类,之后再继续加载。
 3 当把一个类完全加载后,这个类的静态成员将被先加载。之后进行如下流程:
 41)初始化对象的存储空间为零或null值;
 52)调用父类构造函数;
 63)按顺序分别调用类成员变量和实例成员变量的初始化表达式;
 74)调用本身构造函数
 8  
 9构造函数的初始化顺序:
101 .当执行new RoundGlyph( 5 )时,首先会加载‘RoundGlyph. class ’,但是这个时候JVM发现 RoundGlyph  extends (继承于) Glyph ,所以他会加载Glyph. class 
112 .然后会初始化Glyph类的static成员数据,这个类没有static成员数据,所以没有这一步。
123 .会执行Glyph类的构造函数Glyph()
134 .接着初始化RoundGlyph类的成员数据,最后调用RoundGlyph()构造函数来生产对象

<示例2>
题目
 1public   class  Test2  extends  Test1  {
 2    {
 3         System.out.print( "  1  " );
 4    }
 
 5    Test2()  {
 6         System.out.print( "  2  " );
 7    }
 
 8    static   {
 9        System.out.print( "  3  " );
10    }
 
11    {
12        System.out.print( "  4  " );
13    }
 
14     public   static   void  main(String[] args)  {
15         new  Test2();
16     }
 
17}
 
18
19class  Test1  {
20    Test1()  {
21        System.out.print( "  5  " );
22    }
 
23    static   {
24        System.out.print( "  6  " );
25    }
 
26}
答案
1635142
分析
 11 ) 虚拟机试图加载Test2,其父类为Test1
 2 ( 2 ) 虚拟机加载Test1
 3 ( 3 ) Test1静态初始化  ----->  输出 " 6 " 
 4 ( 4 ) 虚拟机加载Test2
 5 ( 3 ) Test2静态初始化  ----->  输出 " 3 " 
 6 ( 5 )  new  Test2()构造Test2首先构造父类Test1
 7 ( 6 ) Test1构造  ----->  输出 " 5 " 
 8 ( 7 ) Test2执行初始化语句块(虚拟机调用Test2初始化方法init)  ----->  输出 " 1 " 和 " 4 " 
 9 ( 8 ) Test2构造  ----->  输出 " 2 " 
10 
11 ================================= 
12 先输出6:
13 因为父类的Static的变量 / 常量会被子类共享
14 所以,首先输出6
15 接着,会先初始化自身的static的变量 / 常量
16 
17 然后,在构造函数中,会首先调用父类的默认构造函数(如果没有显示调用super(args)的话)
18 在调用父类构造函数时,在执行构造函数体中的数据内容时,先执行方法外的程序段,如变量申明,或者程序段。然后再调用构造函数中的程序段。
19 然后再执行自身的构造函数,执行前,也如上述说:在执行本构造函数体中的数据内容时,先执行方法外的程序段,如变量申明,或者程序段。然后再调用构造函数中的程序段。
20 
21 这就是一个对象的实例化过程。

类初始化时构造函数调用顺序:
   首先加载类,遇到extends字样会停止加载当前类,加载父类,之后再继续加载。
  当把一个类完全加载后,这个类的静态成员将被先加载。之后进行如下流程:
1 )初始化对象的存储空间为零或null值;
  2 )调用父类构造函数;
3 )按顺序分别调用类成员变量和实例成员变量的初始化表达式;
  4 )调用本身构造函数

<示例3>this指针
题目
 1public class CalC {
 2    void amethod(){
 3        System.out.println("CalC.amethod");
 4    }

 5    CalC(){
 6        amethod();
 7        System.out.println("Hu?");
 8    }

 9    public static void main(String[] args) {
10        // TODO Auto-generated method stub
11        CalC cc = new CalChild();
12        cc.amethod();
13    }

14}

15class CalChild extends CalC{
16    void amethod(){
17        System.out.println("CalChild.amethod");
18    }

19}
答案
1CalChild.amethod
2Hu?
3CalChild.amethod


实例方法专用于类的对象,但是在内存中只有一份实例方法供类的所有实例共享,因为为每个对象都复制一份所有实例方法代价很昂贵。
所以系统中专门有这样一种机制来保证:当你调用一个方法时,代码是按专用于这个对象的方式进行,这种机制就是this。

每个实例方法都有一个名为this的变量,指的是调用该方法的当前对象。这种机制是当你的方法引用了类的一个实例变量是由编译器隐含使用的。

即使对实例变量的每个引用实质上是有 this. 前缀的

当调用一个实例方法时,this变量将被设置成引用它所起作用的特定类对象。

所以的对象都共享这个备份,为了区分开到底是哪个对象在调用这个方法,关键的地方就是this的使用。this把调用方法的上下文对应到当前对象上。

本例分析:
调用java中的所有成员变量或者成员函数都隐含了this。所以这个地方就很明了了:构造子类,this指针代表的当前对象是子类实例,子类实例为啥不调用自己overriding的方法呢?!

参考分析
CalC cc = new CalChild();这一步也叫“异类搜集”,以父类类型声明变量作为子类对象的引用,此时子类的所有属性方法都失效,只有子类中重写父类的这样一中方法可以被变量调用,而不调用父类的同名方法,从而实现多态!
此程序前后两次打印都是一个原理。。

参考java基础(一)

<示例4>

题目
 1class   super1{   
 2     {   
 3              System.out.println("super1   ok");   
 4      }
   
 5      super1()   {   
 6          System.out.println("3");   
 7      }
   
 8  }
   
 9    
10  class   Employee   extends   super1{   
11            private   String   name;   
12            private   double   salary=1500.00;   
13            private   Date   birthday;   
14            public   Employee(String   n,Date   DoB){   
15                System.out.println("2");   
16                name=n;   
17                birthday=DoB;   
18            }
   
19            public   Employee(String   n){   
20                this(n,null);   
21                System.out.println("4");   
22            }
   
23  }
 
24  class   Manager   extends   Employee{   
25      {   
26          System.out.println("Manager   ok");   
27      }
   
28      private   String   department;   
29      public   Manager(String   n,String   d){   
30            super(n);   
31            department=d;   
32      }
   
33  }
 
34    
35  public   class   test1{   
36      public   static   void   main(String   args[]){   
37            new   Manager("Smith","sales");   
38      }
   
39  }
  
答案
1super1   ok
23
32
44
5Manager   ok
分析:

你总是可以从派生类构造器中调用一个适当的基础类构造器,对基础类构造器的调用必须放在派生类构造器的首位。

 

如果派生类构造器第一个语句不是对基础类构造器的调用,则编译器将替你插入一个对默认基础类构造器的调用:super()

 

如果你自己定义了自己的构造函数,则编译器认为是你会负责一个对象构造的全部细节问题,包括对默认构造器的任何要求,编译器不将管理。

 

如果你构造函数中要使用super() super this() this)等字样,则必须放在第一行。

如果你没有显示指定super() super)字样,系统会在构造函数第一行自动插入super()字样;如果你指定了,系统将按你指定的进行而不是默认的了。

<练习1>

题目
 1class   B{   
 2      B(){   
 3          System.out.println("B()");   
 4      }
   
 5  }
   
 6  class   C   extends   B{   
 7      C(){   
 8          System.out.println("C()");   
 9  }
   
10    
11  public   class   A{   
12      public   static   void   main(String[]   arg){   
13          new   C();   
14      }
   
15  }
 

答案
B()   
C()


<练习2>

题目
 1class   A   {   
 2      public   A()   {   
 3          System.out.println("A's   c   is   here   ");   
 4      }
   
 5      void   println()  {   
 6          System.out.println("A's   v   is   here   ");   
 7      }
   
 8  }
   
 9 class   B   extends   A  {   
10      public   B()   {   
11          System.out.println("B's   c   is   here   ");   
12      }
   
13      void   println()  {   
14          System.out.println("B's   v   is   here   ");   
15      }
   
16  }
   
17  public   class   Chp_4_2  {   
18      public   static   void   main(String[]   args)  {   
19          B   b   =   new   B();  
20      }
   
21 }

 

分析
子类的构造函数,除非显示的写上super或者super(Object),第一行会被插入super()的

因为class  B  
extends  class  A  ,所以你可以这样看B的构造方法   
public   B()   {  
  
super();   
  System.out.println(
"B's c is here");   
}
   
所以A
's c is here会输出


<练习3>

题目
 1public class JRun1 {
 2public JRun1() {
 3System.out.println(" 构造函数");
 4}

 5static{
 6System.out.println("static{}");
 7}

 8{
 9System.out.println("{}");
10}

11public static void main(String[] args) {
12System.out.println("main()");
13new JRun1();
14}

15}

 

答案
static{}
main()
{}
构造函数


题目
import java.util.Calendar;

public class SingletonTest{
    
private static final SingletonTest instance = new SingletonTest();
    
private static final int BIZZ = 100;
    {
        System.out.println(BIZZ);
    }
    
private int size = 0;
    
private static int YEAR = Calendar.getInstance().get(Calendar.YEAR);
    {
        System.out.println(
"after generate instance line");
    }
    
private SingletonTest() {
        System.out.println(
"Constructor");
        size 
= YEAR - 1930;
    }
    
public int getSize() {
        
return size;
    }
    
public static void main(String[] args) {
        System.out.println(instance.getSize());
    }

 

答案
100
after generate instance line
Constructor
-1930
题目
 1 import java.util.Calendar;
 2 
 3 public class SingletonTest{
 4     private static final SingletonTest instance = new SingletonTest();
 5     private int size = 0;
 6     private static int YEAR = Calendar.getInstance().get(Calendar.YEAR);
 7     {
 8         System.out.println("after generate instance line");
 9     }
10     private SingletonTest() {
11         System.out.println("Constructor");
12         size = YEAR - 1930;
13     }
14     public int getSize() {
15         return size;
16     }
17     public static void main(String[] args) {
18         System.out.println(instance.getSize());
19     }
20 
答案
1 after generate instance line
2 Constructor
3 -1930
题目
 1 import java.util.Calendar;
 2 
 3 public class SingletonTest{
 4     private static final int BIZZ = 100;
 5     {
 6         System.out.println(BIZZ);
 7     }
 8     private int size = 0;
 9     private static int YEAR = Calendar.getInstance().get(Calendar.YEAR);
10     private static final SingletonTest instance = new SingletonTest();
11     {
12         System.out.println("after generate instance line");
13     }
14     private SingletonTest() {
15         System.out.println("Constructor");
16         size = YEAR - 1930;
17     }
18     public int getSize() {
19         return size;
20     }
21     public static void main(String[] args) {
22         System.out.println(instance.getSize());
23     }
24 



 <练习>

题目
 1public class Parent {
 2  public void test(){ }
 3  public Parent(){
 4         test();
 5     }

 6  public static void main(String[] args){
 7         new Child();
 8     }

 9}

10
11class Child extends Parent{
12        private int instanceValue = 20;
13    public void test(){
14            System.out.println("instance value is: " + instanceValue);
15       }

16  }

17看输入结果是什么?
答案
0
分析
 1(网友)花之剑:定义实例变量instanceValue(默认为0)->调用父类无参构造方法->调用子类的test()(因多态性,test被重写)->构造方法结束->实例变量的初始化,此时instanceValue=20
 2
 3(网友)花之剑:
 41.如果子类无自己的构造方法,子类默认继承父类无形参构造方法
 5顺序应该是:
 6定义实例变量instanceValue(默认为0)->调用父类无参构造方法->调用子类的test()(因多态性,test被重写)->构造方法结束->实例变量的初始化,此时instanceValue=20
 72.如果子类有自己的构造方法,子类构造方法第一行默认super().
 8顺序应该是:
 9定义实例变量instanceValue(默认为0)->调用父类无参构造方法->调用子类的test()(因多态性,test被重写)->父类无形参构造方法结束->实例变量的初始化,此时instanceValue=20 -->子类的构造方法。
10
11public class Parent{
12  public void test(){}
13  public Parent(){
14    test();
15  }

16  public static void main(String[] args){
17    new Child();
18  }

19}

20
21class Child extends Parent{
22  private int instanceValue = 20;
23  public Child(){
24     //super();
25     System.out.println("instance value is: " + instanceValue);
26  }

27  public void test(){
28     System.out.println("instance value is: " + instanceValue);
29  }

30}

你可能感兴趣的:(JAVA基础(二):函数执行顺序(构造函数,多态,this指针))