关于子类实例化和初始化的不解与猜想

首先来看看下面这段代码:

public class Base {
    private int i=5;
    public Base(){
        System.out.println("I come from "+this.getClass()+"  i="+this.i);
        this.display();
    }
    public int getI(){
        return i;
    }
    public void display(){
        System.out.println(this.i);
    }
}

public class Sub extends Base {
    private int i=22;
    public Sub(){
        i=222;
    }
    public void display(){
        System.out.println("I come from "+this.getClass()+" i="+this.i);
    }
}

public class Test {
    public static void main(String[] args) {
        Sub sub=new Sub();
        System.out.println(sub.getI());
    }
}

打印结果为:

下面我们来分析一下:

在main函数中首先执行

Sub sub=new Sub();

这行代码。而这行代码须分解为两步:

step1:执行new关键字,在执行这个关键字的时候,有一个疑问:new出来的对象中是否包含了父类中的所有变量(包括私有变量);

step2:执行new后面的括号即初始化对象。从Java核心技术卷一P131种可知初始化数据的步骤为:

1、所有数据被初始化为默认值;

2、按照类声明中出现的次序,依次执行所有域的初始化语句和初始化块;

3、如果构造器第一行调用了第二个构造器,则执行第二个构造器主体;

4、执行这个构造器的主体。

我相信这绝对是一个非常简化版的执行过程了。因为作者这里根本没有提到何时,调用父类的构造器。

那我们现在就来细细分析这个初始化的过程(其实在这篇文章中也分析过了,只是也不是很完整)。

为例更清晰的看看初始化的过程我们使用javap工具看看一个简单的类的字节码:

类代码:

    public class SimpleClass {
        {
            i=6;
        }
        private int i=0;
        public SimpleClass(){
            i=5;
        }
    }

    字节码为:

这下很清楚了。当对子类Sub初始化时,会首先调用其父类的构造函数,在这时子类Sub只有变量的声明,没有进行任何的赋值操作。jvm开始初始化父类Base:由上图可知,变量定义时赋值和初始化块中赋值在构造器中赋值之前进行。所以首先jvm执行Base中的i=5;此时Base中的被初始化为5了。然后执行构造函数中的语句(请分清构造器中的语句和构造器中的字节码)。接下来的执行见这篇文章

现在问题是,在Sub初始化进行完之后,Sub包含了父类的那些变量?是不是包含了父类中的所有变量。如果不是(在书上看到是继承了父类非私有的变量),那么执行main函数的这条语句:

    System.out.println(sub.getI());

为什么会打印出5呢?因为sub对象中的i变量的值现在为222啊。

注:在李刚老师的《Java程序员基本功》书中看到,子类继承父类的非私有方法,只是将方法放进了自类中,该方法和该子类中其他方法的唯一区别就是多了一个super的标签。那么是不是就可以得出Sub子类中也把父类中的私有变量放到了自己的内存中了,只是我们无法访问而已。

记下疑点,以便慢慢解决……也希望大神们多多指点……

时间: 2024-11-03 21:53:55

关于子类实例化和初始化的不解与猜想的相关文章

子类实例化,父类构造器中被调用被子类重写的方法,会执行父类还是子类的呢?

public class Test001 { public static void main(String[] args) { new Child(); } }class Father{ private String name = "f"; public Father(){ tell(); } public void tell(){ System.out.println("father "+this.name); }}class Child extends Fath

面向对象(子父类中构造函数的特点-子类实例化过程)

/* 3,子父类中的构造函数. 在对子类对象进行初始化时,父类的构造函数也会运行, 那是因为子类的构造函数默认第一行有一条隐式的语句 super(); super():会访问父类中空参数的构造函数.而且子类中所有的构造函数默认第一行都是super(); 为什么子类一定要访问父类中的构造函数. 因为父类中的数据子类可以直接获取.所以子类对象在建立时,需要先查看父类是如何对这些数据进行初始化的.//指在在父类构造函数初始化 所以子类在对象初始化时,要先访问一下父类中的构造函数. 如果要访问父类中指定

java4android (继承中的子类实例化过程)

生成子类的过程 见代码: class Person { String name; int age; Person(){ System.out.print("Person的无参数构造函数"); } Person(String name,int age){ this.name = name; this.age = age; System.out.print("Person的有2个参数的构造函数"); } void eat(){ System.out.print(&quo

Java类的实例化的初始化过程

A a = new A(); new 创建对象过程: 1.类加载 代码验证 2.给对象在内存(堆)中分配空间(给属性赋值): 3.属性赋默认值: byte,short.int,long ->0 float  ->0.0f double ->0.0 boolean  ->false String ->null char ->'\u0000' 4.给属性赋初始值:(用等号'=') 5.调用构造方法(方法和类名相同,没有返回类型) 6.将对象在堆区中的首地址返回给引用a /*

java基础部分----3.继承、子类实例化、函数的复写

1.继承 java只支持单继承,一个子类只能继承一个父类.一个父类可以有多个子类 关键字:extends 减少重复代码 2.继承的语法特点 class Student extends Preson{ } 如果子类继承父类,同时子类在这个基础上添加自己的成员变量和成员函数 3.子类实例化 1.生成子类的过程 在子类的构造函数中,必须调用父类的构造函数(根据()传入的参数个数以及类型决定) lass Student extends Person{ int grade; Student(){ supe

【好程序员训练营】----子类实例化函数复写对象转型

android培训------我的java笔记,期待与您交流! 一.子类实例化过程 public class Student extends Person{ /* * 继承父类成员和函数,不能继承构造函数 * 在子类构造函数中,须调用父类的构造函数 */ Student(){ super();//用于调用父类构造函数:若写则在第一条语句,若不写,编译器自动添加:可以调用父类有参构造函数super(..,..); System.out.println("student无参数构造函数");

Java父类子类的对象初始化过程

摘要 Java基本的对象初始化过程,子类的初始化,以及涉及到父类和子类的转化时可能引起混乱的情况. 1. 基本初始化过程: 对于一个简单类的初始化过程是: static 修饰的模块(static变量和static 块)  ---> 按照代码顺序依次执行. | 实例变量  及非static模块---> 按照代码顺序依次执行. | 构造函数 ---> 执行对应的构造函数. 子类的初始化过程. 父类static修饰的模块 | 子类static修饰模块 | 父类实例变量和非static块 | 父

子类实例化过程

先看代码 class Person{ int age; String name; Person(){ System.out.println("Person的无参数构造函数"); } Person(int age,String name){ this.age = age; this.name = name; System.out.println("Person的有参数构造函数"); } void eat(){ System.out.println("吃饭&q

11.子类实例化过程

生成子类的过程 子类继承了父类的成员变量,但却无法继承父类的构造函数 当生成子类对象的时候,一定会调用父类的构造函数 如果子类当中没有调用构造函数,编译器会自动添加super(),用于调用父类当中的无参数构造函数 使用super调用父类构造函数的方法 在子类要调用父类函数的话,super()一定要是构造函数的第一条语句 classPerson{ String name; int age; int grade; Person(){ System.out.println("Person的无参数构造函