父类子类变量,块,构造函数加载先后顺序

阅读更多

1. 如果B继承A,在new B()时候,java代码的执行顺序:

 

JVM装载

初始化父类的静态成员变量

初始化父类的静态代码块

初始化子类的静态成员变量

初始化子类的静态代码块

初始化父类的非静态成员变量

初始化父类的非静态代码块

调用父类的默认构造方法

初始化子类的非静态成员变量

初始化子类的非静态代码块

调用子类的构造方法

测试代码:

package com;

public class TestHello {

	static class A {
		public int a1 = 21;
	    static int a = 2;
	    {
	         System.out.println("父类的非静态代码块正在运行,非静态变量a1的值为=" + a1 + " 静态变量的a的值为=" + a);
	    }
	    static {
	         System.out.println("父类的静态代码块正在运行,静态变量的a的值为=" + a);
	    }
	    public A() {
	         System.out.println(a1 + "父类构造函数正在运行,非静态变量a1的值为=" + a1 + " 静态变量的a的值为=" + a);
	    }
	}
	
	static class B extends A {
		public int a1 = 31;
	    static int a = 3;
	    
	    {
	    	 System.out.println("子类的非静态代码块正在运行,非静态变量a1的值为=" + a1 + " 静态变量的a的值为=" + a);
	    }
	    static {
	    	System.out.println("子类的静态代码块正在运行,静态变量的a的值为=" + a);
	    }
	    public B() {
	    	 System.out.println(a1 + "子类构造函数正在运行,非静态变量a1的值为=" + a1 + " 静态变量的a的值为=" + a);
	    }
	}
	
	public static void main(String[] args) {
		B b = new B();
    }
}

 执行结果为:

父类的静态代码块正在运行,静态变量的a的值为=2
子类的静态代码块正在运行,静态变量的a的值为=3
父类的非静态代码块正在运行,非静态变量a1的值为=21 静态变量的a的值为=2
21父类构造函数正在运行,非静态变量a1的值为=21 静态变量的a的值为=2
子类的非静态代码块正在运行,非静态变量a1的值为=31 静态变量的a的值为=3
31子类构造函数正在运行,非静态变量a1的值为=31 静态变量的a的值为=3

 2)若果想要显式调用父类的构造方法则可以使用super(),来调用,但是super关键字必须放在构造放的第一行,而且只能放在第一行,不然编译不通过。

3)this 指针指向的是当前的实例

 

package com.base;
class Base {
	private int i = 2 ;
	public Base(){
		this.display() ;
	}
	public void display(){
		System.out.println(i);
	}
}

class Derived extends Base {
	private int i = 22 ;
	public Derived(){
		i = 222 ;
	}
	public void display(){
		System.out.println(i);
	}
}

public class Test {
	public static void main(String[] args) {
		new Derived() ;
	}
}
 输出结果为:0

 

怎么会是0 呢?

当我们调用new Derived() ;创建Derived实例的时候,系统会为Derived对象分配内存空间,Derived会有两个i实例变量,会分配两个空间来保存i的值。分配完空间以后i的值为0,如果有引用类型则引用类型的值为null。

接下来程序在执行Derived的构造器之前会执行Base的构造器,表面上看Base的构造器中只有一行代码,但是在父类中定义i的时候执行的初始值2,因此经过编译之后,该构造方法中应该包含如下两行代码:

i =2 ;

this.display() ;

程序先将Base中的i赋值为2,然后执行display方法。此处有一个关键字this,this到底代表谁呢?表面上看this代表的是Base的当前实例,但是实际上代码是放在Derived的构造器中的,所以this最终代表的是Derived的当前实例(编译类型是Base而实际引用一个Derived对象),所以如果在父类的构造方法中直接输出System.out.println(this.i) ;则输出的结果为2。但是调用this.display()方法,此时调用的是

子类中重写的display方法,输出的变量i也是子类中的i,但是此时子类中的变量i还没有赋值,所以输出结果为0。

为了详细的看清楚this变量到底代表什么实例,我们将Base的构造方法修改如下:

public Base(){

System.out.println(this.i);

System.out.println(this.getClass());

this.display() ;

}

再次运行程序,结果为:

2

class edu.qichao.chapter2.Derived

0

可以看到this代表的是Derived的实例,但是编译的时候类型为Base,所以输出this.i的值为2。

4)继承成员变量和成员方法的区别

package com.base;
class Animal {
	private String desc ;
	public Animal(){
		this.desc = getDesc() ;
	}
	 
	public String getDesc(){
		return "Animal" ;
	}
	public String toString(){
		return desc ;
	}
	
}
public class Wolf extends Animal {
	private String name ;
	private double weight ;
	public Wolf(String name , double weight){
		this.name = name ;
		this.weight = weight ;
	}
	
	public String getDesc(){
		return "Wolf[name=" + name + ",weight=" + weight + "]" ;
	}
	
	 
	
	public static void main(String[] args){
		System.out.println(new Wolf("灰太狼" , 3));
	}
}

程序运行结果为:

2

2

-----------------

20

20

-----------------

2

20

-----------------

2

在上面的程序中,不管是d变量、还是bd变量、还是都d2b变量。只要他们指向一个Derived对象,则不管他们声明时用了什么类型,当通过这些变量调用方法时,方法的行为总是表现出他们的实际类型的行为,但是如果通过这些变量来访问他们所指向对象的实例变量的时候,这些实例变量的值总是表现出声明这些变量所用类型的行为。

由此可见,java处理成员变量和成员方法的继承时是有区别的。

参考:http://www.2cto.com/kf/201110/109053.html

你可能感兴趣的:(java,变量,块,方法)