`
luhantu
  • 浏览: 204044 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

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

    博客分类:
  • Java
阅读更多

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

分享到:
评论

相关推荐

    构造函数与静态块的执行顺序

    这是因为静态块是在类加载时执行的,而类的加载顺序是按照继承层次自上而下进行的,所以父类的静态块总是先于子类的静态块执行。 2. **构造函数的执行**:接下来,父类的构造函数会被调用,然后才是子类的构造函数...

    再次详细说明在继承中的程序执行顺序,子类与父类到底哪个先执行

    - 在子类创建实例时,首先会执行父类的构造函数。这是为了确保父类的成员变量得到正确的初始化。在Java中,如果子类没有显式调用父类的构造器,编译器会自动添加一个默认的`super()`调用,这将调用父类的无参构造器...

    14_构造函数 视频

    如果子类没有显式定义构造函数,它将自动获得一个默认构造函数,调用父类的无参构造函数。若子类需要调用父类的有参构造函数,必须通过`super()`关键字来实现。 6. **构造函数与final字段**:对于声明为`final`的...

    javase子类父类继承关系图解

    2. **父类的非静态初始化块**:接着,如果父类有非静态初始化块(也称为实例初始化块),它会在父类的构造函数执行之前运行。这些块用于初始化父类的实例变量。 3. **父类的默认构造器**:然后,调用父类的默认构造...

    【Java】80例及结果

    从提供的【部分内容】中,我们可以提炼出Java语言中面向对象编程的几个核心概念,包括类的继承、构造函数的执行顺序、静态属性的初始化顺序、以及变量的作用域等方面的知识点。以下是详细解释: 1. 类的继承与构造...

    Java中一些基础概念的使用详解

    创建`Child`对象时,输出顺序将是:父类静态变量/静态初始化块 -> 子类静态变量/静态初始化块 -> 父类实例变量/实例初始化块 -> 父类构造函数 -> 子类实例变量/实例初始化块 -> 子类构造函数。 接下来,我们转向与...

    java 代码块与静态代码块加载顺序

    Java 代码块与静态代码块加载顺序详解 Java 代码块与静态代码块加载顺序是 Java 语言中一个重要的概念,理解这两个概念对于编写高效、可靠的 Java 代码至关重要。本文将详细介绍 Java 代码块与静态代码块加载顺序的...

    Java类的完整构造执行顺序

    在深入探讨Java类的完整构造执行顺序之前,我们先来明确一下Java中构造函数与类初始化的基本概念。构造函数在创建对象时被调用,用于初始化该对象的状态。而类初始化则是指在类首次被使用时,JVM执行的一系列初始化...

    java中静态代码块与构造方法的执行顺序判断

    在多级继承关系中,静态代码块按照类的加载顺序执行,先加载的类先执行其静态代码块。 例如,在给定的代码中: ```java public class A { static { System.out.print(1); } public A() { System.out.print(2)...

    java代码初始化流程研究

    构造函数的调用链遵循“父类优先”原则,即子类构造函数会先调用父类的无参构造函数,然后再执行自身的初始化代码。 在`JvmTest.java`和`JvmTest1.java`中,可能包含了不同层次的类以及它们各自的构造函数,理解...

    JAVA面试题答疑解惑

    2. 变量和初始化块:在类的实例被创建时,非静态变量和初始化块会在构造函数执行之前被初始化。它们同样会按照在源码中出现的顺序进行。 3. 构造器:在类的实例创建过程中,构造器是最后被执行的。构造器方法用于...

    java中类的初始化顺序

    类的初始化涉及到多个方面,包括静态成员变量、实例成员变量、静态初始化块、实例初始化块以及构造函数等。本文将详细探讨Java中类的初始化过程及其顺序,并通过具体的代码示例来帮助理解这一过程。 #### 二、基础...

    探究java的ClassLoader及类变量初始化顺序

    需要注意的是,静态初始化块只在类被加载时执行一次,而实例初始化块(构造函数)则会在每次创建类的实例时执行。静态变量的初始化是在类加载时完成的,而实例变量的初始化则在对象创建时进行。 在实际开发中,对...

    java代码的初始化顺序demo

    总之,Java代码的初始化顺序是类加载的必然过程,涉及到静态和实例初始化块、构造函数、成员变量初始化以及继承关系的影响。这个demo是学习和理解这些概念的重要工具,通过实际操作可以加深对Java内存管理和对象生命...

    类和对象的初始化过程.zip

    初始化的顺序是:首先是静态初始化块,然后是父类的非静态初始化,接着是子类的非静态初始化,最后是构造函数中的初始化代码。在`Test.java`中,可能展示了这种初始化顺序。 总结,这个压缩包文件提供了关于Java中...

    静态代码块

    - 在子类中,如果想要调用父类的构造函数或其他方法,可以使用`super()`关键字。 以上就是关于Java中静态代码块的相关基础知识及其使用场景的详细介绍。理解静态代码块的工作原理有助于开发者更好地组织和管理代码...

    java对象的初始化顺序[参考].pdf

    - 在实例化过程中,按顺序初始化实例成员变量、实例成员函数,最后调用构造函数。 了解这个顺序对于理解和调试涉及多层继承和复杂初始化逻辑的Java代码至关重要。正确掌握这个顺序可以帮助我们避免因初始化顺序不当...

    TareaPOO-构造函数CristianPonce

    9. **静态块与实例块**:静态初始化块在类加载时执行,而实例初始化块在创建对象时执行,两者都可以用来初始化类或对象的状态,但构造函数更常用。 10. **构造函数与工厂方法**:虽然构造函数是创建对象的标准方式...

Global site tag (gtag.js) - Google Analytics