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处理成员变量和成员方法的继承时是有区别的。
相关推荐
这是因为静态块是在类加载时执行的,而类的加载顺序是按照继承层次自上而下进行的,所以父类的静态块总是先于子类的静态块执行。 2. **构造函数的执行**:接下来,父类的构造函数会被调用,然后才是子类的构造函数...
- 在子类创建实例时,首先会执行父类的构造函数。这是为了确保父类的成员变量得到正确的初始化。在Java中,如果子类没有显式调用父类的构造器,编译器会自动添加一个默认的`super()`调用,这将调用父类的无参构造器...
如果子类没有显式定义构造函数,它将自动获得一个默认构造函数,调用父类的无参构造函数。若子类需要调用父类的有参构造函数,必须通过`super()`关键字来实现。 6. **构造函数与final字段**:对于声明为`final`的...
2. **父类的非静态初始化块**:接着,如果父类有非静态初始化块(也称为实例初始化块),它会在父类的构造函数执行之前运行。这些块用于初始化父类的实例变量。 3. **父类的默认构造器**:然后,调用父类的默认构造...
从提供的【部分内容】中,我们可以提炼出Java语言中面向对象编程的几个核心概念,包括类的继承、构造函数的执行顺序、静态属性的初始化顺序、以及变量的作用域等方面的知识点。以下是详细解释: 1. 类的继承与构造...
创建`Child`对象时,输出顺序将是:父类静态变量/静态初始化块 -> 子类静态变量/静态初始化块 -> 父类实例变量/实例初始化块 -> 父类构造函数 -> 子类实例变量/实例初始化块 -> 子类构造函数。 接下来,我们转向与...
这类问题通常涉及静态与非静态成员变量、静态初始化块、非静态初始化块以及构造函数的执行顺序。下面我们将深入探讨这些概念及其初始化顺序。 #### 一、基础知识回顾 在Java中,类的成员变量可以分为静态变量和...
Java 代码块与静态代码块加载顺序详解 Java 代码块与静态代码块加载顺序是 Java 语言中一个重要的概念,理解这两个概念对于编写高效、可靠的 Java 代码至关重要。本文将详细介绍 Java 代码块与静态代码块加载顺序的...
在深入探讨Java类的完整构造执行顺序之前,我们先来明确一下Java中构造函数与类初始化的基本概念。构造函数在创建对象时被调用,用于初始化该对象的状态。而类初始化则是指在类首次被使用时,JVM执行的一系列初始化...
在多级继承关系中,静态代码块按照类的加载顺序执行,先加载的类先执行其静态代码块。 例如,在给定的代码中: ```java public class A { static { System.out.print(1); } public A() { System.out.print(2)...
构造函数的调用链遵循“父类优先”原则,即子类构造函数会先调用父类的无参构造函数,然后再执行自身的初始化代码。 在`JvmTest.java`和`JvmTest1.java`中,可能包含了不同层次的类以及它们各自的构造函数,理解...
2. 变量和初始化块:在类的实例被创建时,非静态变量和初始化块会在构造函数执行之前被初始化。它们同样会按照在源码中出现的顺序进行。 3. 构造器:在类的实例创建过程中,构造器是最后被执行的。构造器方法用于...
类的初始化涉及到多个方面,包括静态成员变量、实例成员变量、静态初始化块、实例初始化块以及构造函数等。本文将详细探讨Java中类的初始化过程及其顺序,并通过具体的代码示例来帮助理解这一过程。 #### 二、基础...
需要注意的是,静态初始化块只在类被加载时执行一次,而实例初始化块(构造函数)则会在每次创建类的实例时执行。静态变量的初始化是在类加载时完成的,而实例变量的初始化则在对象创建时进行。 在实际开发中,对...
总之,Java代码的初始化顺序是类加载的必然过程,涉及到静态和实例初始化块、构造函数、成员变量初始化以及继承关系的影响。这个demo是学习和理解这些概念的重要工具,通过实际操作可以加深对Java内存管理和对象生命...
初始化的顺序是:首先是静态初始化块,然后是父类的非静态初始化,接着是子类的非静态初始化,最后是构造函数中的初始化代码。在`Test.java`中,可能展示了这种初始化顺序。 总结,这个压缩包文件提供了关于Java中...
- 在子类中,如果想要调用父类的构造函数或其他方法,可以使用`super()`关键字。 以上就是关于Java中静态代码块的相关基础知识及其使用场景的详细介绍。理解静态代码块的工作原理有助于开发者更好地组织和管理代码...
- 在实例化过程中,按顺序初始化实例成员变量、实例成员函数,最后调用构造函数。 了解这个顺序对于理解和调试涉及多层继承和复杂初始化逻辑的Java代码至关重要。正确掌握这个顺序可以帮助我们避免因初始化顺序不当...
9. **静态块与实例块**:静态初始化块在类加载时执行,而实例初始化块在创建对象时执行,两者都可以用来初始化类或对象的状态,但构造函数更常用。 10. **构造函数与工厂方法**:虽然构造函数是创建对象的标准方式...