java类实现继承时,内存中父类和子类是怎样分配的?

我觉得java的一些特性与对象在内存中的分配方式是密切相关的。
比如说:Java的多态,正是因为new出的对象是在堆中分配的,而这种内存分配方式在编译期无需知道此对象所需要的空间和生存周期。

现在我很困惑的是,java类实现继承时,内存中父类和子类是怎样分配的?或者说有着怎样的联系呢。

例如:
父类:Father
[code="java"]
public class Father {
protected String classname = "Father";

public Father(){
}

public Father(String cn){
    setClassName(cn);
}
protected String getClassName(){
    return classname;
}

protected void setClassName(String cn){
    classname = cn;
}

}
[/code]

子类:Child
[code="java"]
public class Child extends Father{

public Child(){
}

public Child(String cn){
    super(cn);
}

private String cname = "Child";

public String getCname() {
    return cname;
}

public void setCname(String cname) {
    this.cname = cname;
}

}[/code]

此时,我写测试代码:
[code="java"]
public class FatherChildTest {
public static void main(String args[]){
System.out.println(new Child().getClassName());
System.out.println(new Child("be changed in constructor!").getClassName());
}
}
[/code]

输出内容很明显:
Father
be changed in constructor!

想问的是,测试代码中,[code="java"]new Child().getClassName()[/code]动作时,
我创建的是Child对象,而它有父类的方法,且可以返回父类中定义的变量。
那Child继承Father,是不是相当于JVM加载类时,保存的类信息中不仅仅是Child的信息,还包括Father的那些对子类可见的信息?
比如,其实JVM加载类Child时,保存的类信息其实是这样的一个类的信息:
[code="java"]
public class Child{

public Child(){
}

public Child(String cn){
    setClassName(cn);
}

private String cname = "Child";

//-------------来自父类 begin----------------
protected String classname = "Father";

protected String getClassName(){
    return classname;
}

protected void setClassName(String cn){
    classname = cn;
}
//-------------来自父类 End----------------

public String getCname() {
    return cname;
}

public void setCname(String cname) {
    this.cname = cname;
}

}
[/code]
此类留有父类对子类可见的信息。

还是说,有另外一种方式,可以把子类与父类联系起来。

请指点!

我想知道原理,但可能表达的不太清楚,见谅!

[b]问题补充:[/b]
我觉得java的一些特性与对象在内存中的分配方式是密切相关的。
比如说:Java的多态,正是因为new出的对象是在堆中分配的,而这种内存分配方式在编译期无需知道此对象所需要的空间和生存周期。

现在我很困惑的是,java类实现继承时,内存中父类和子类是怎样分配的?或者说有着怎样的联系呢。

例如:
父类:Father

public class Father {
    protected String classname = "Father";
    
    public Father(){
    }
    
    public Father(String cn){
        setClassName(cn);
    }
    protected String getClassName(){
        return classname;
    }
    
    protected void setClassName(String cn){
        classname = cn;
    }
}

子类:Child

public class Child extends Father{

    public Child(){
    }
    
    public Child(String cn){
        super(cn);
    }
    
    private String cname = "Child";
    
    public String getCname() {
        return cname;
    }

    public void setCname(String cname) {
        this.cname = cname;
    }
}
此时,我写测试代码:
public class FatherChildTest {
    public static void main(String args[]){
        System.out.println(new Child().getClassName());
        System.out.println(new Child("be changed in constructor!").getClassName());
    }
}

输出内容很明显:
Father
be changed in constructor!

想问的是,测试代码中,

new Child().getClassName()
动作时,
我创建的是Child对象,而它有父类的方法,且可以返回父类中定义的变量。
那Child继承Father,是不是相当于JVM加载类时,保存的类信息中不仅仅是Child的信息,还包括Father的那些对子类可见的信息?
比如,其实JVM加载类Child时,保存的类信息其实是这样的一个类的信息:
public class Child{
    
    public Child(){
    }
    
    public Child(String cn){
        setClassName(cn);
    }
    
    private String cname = "Child";
    
    //-------------来自父类 begin----------------
    protected String classname = "Father";
    
    protected String getClassName(){
        return classname;
    }
    
    protected void setClassName(String cn){
        classname = cn;
    }
    //-------------来自父类 End----------------
    
    public String getCname() {
        return cname;
    }

    public void setCname(String cname) {
        this.cname = cname;
    }
}

此类留有父类对子类可见的信息。

还是说,有另外一种方式,可以把子类与父类联系起来。

请指点!

我想知道原理,但可能表达的不太清楚,见谅!

-------------------补充------------------

以下是mccxj所说,我没太懂:

【子类里有一个区域放的父类的实例,子类内存区里有一个this指针,指向了这个内存区里包括的父类实例区,当把引用付给父类时,是把子类内存区里面的父类实例区域的引用给了父类的实例.】

子类内存区里this指针不是指向它自己的吗?
而super指针才是指向了父类的实例?
后面那句 【当把引用付给父类时,是把子类内存区里面的父类实例区域的引用给了父类的实例.】,同样不太懂,感觉很模糊。
是不是说,当把引用付给父类时,这个引用体现的其实是子类中父类实例的属性?
[b]问题补充:[/b]
我觉得java的一些特性与对象在内存中的分配方式是密切相关的。
比如说:Java的多态,正是因为new出的对象是在堆中分配的,而这种内存分配方式在编译期无需知道此对象所需要的空间和生存周期。

现在我很困惑的是,java类实现继承时,内存中父类和子类是怎样分配的?或者说有着怎样的联系呢。

例如:
父类:Father

public class Father {
    protected String classname = "Father";
    
    public Father(){
    }
    
    public Father(String cn){
        setClassName(cn);
    }
    protected String getClassName(){
        return classname;
    }
    
    protected void setClassName(String cn){
        classname = cn;
    }
}

子类:Child

public class Child extends Father{

    public Child(){
    }
    
    public Child(String cn){
        super(cn);
    }
    
    private String cname = "Child";
    
    public String getCname() {
        return cname;
    }

    public void setCname(String cname) {
        this.cname = cname;
    }
}
此时,我写测试代码:
public class FatherChildTest {
    public static void main(String args[]){
        System.out.println(new Child().getClassName());
        System.out.println(new Child("be changed in constructor!").getClassName());
    }
}

输出内容很明显:
Father
be changed in constructor!

想问的是,测试代码中,

new Child().getClassName()
动作时,
我创建的是Child对象,而它有父类的方法,且可以返回父类中定义的变量。
那Child继承Father,是不是相当于JVM加载类时,保存的类信息中不仅仅是Child的信息,还包括Father的那些对子类可见的信息?
比如,其实JVM加载类Child时,保存的类信息其实是这样的一个类的信息:
public class Child{
    
    public Child(){
    }
    
    public Child(String cn){
        setClassName(cn);
    }
    
    private String cname = "Child";
    
    //-------------来自父类 begin----------------
    protected String classname = "Father";
    
    protected String getClassName(){
        return classname;
    }
    
    protected void setClassName(String cn){
        classname = cn;
    }
    //-------------来自父类 End----------------
    
    public String getCname() {
        return cname;
    }

    public void setCname(String cname) {
        this.cname = cname;
    }
}

此类留有父类对子类可见的信息。

还是说,有另外一种方式,可以把子类与父类联系起来。

请指点!

我想知道原理,但可能表达的不太清楚,见谅!

问题补充:
我觉得java的一些特性与对象在内存中的分配方式是密切相关的。
比如说:Java的多态,正是因为new出的对象是在堆中分配的,而这种内存分配方式在编译期无需知道此对象所需要的空间和生存周期。

现在我很困惑的是,java类实现继承时,内存中父类和子类是怎样分配的?或者说有着怎样的联系呢。

例如:
父类:Father
<pre name="code" class="java">
public class Father {
protected String classname = "Father";

public Father(){
}

public Father(String cn){
    setClassName(cn);
}
protected String getClassName(){
    return classname;
}

protected void setClassName(String cn){
    classname = cn;
}

}
</pre>

子类:Child
<pre name="code" class="java">
public class Child extends Father{

public Child(){
}

public Child(String cn){
    super(cn);
}

private String cname = "Child";

public String getCname() {
    return cname;
}

public void setCname(String cname) {
    this.cname = cname;
}

}</pre>

此时,我写测试代码:
<pre name="code" class="java">
public class FatherChildTest {
public static void main(String args[]){
System.out.println(new Child().getClassName());
System.out.println(new Child("be changed in constructor!").getClassName());
}
}
</pre>

输出内容很明显:
Father
be changed in constructor!

想问的是,测试代码中,<pre name="code" class="java">new Child().getClassName()</pre>动作时,
我创建的是Child对象,而它有父类的方法,且可以返回父类中定义的变量。
那Child继承Father,是不是相当于JVM加载类时,保存的类信息中不仅仅是Child的信息,还包括Father的那些对子类可见的信息?
比如,其实JVM加载类Child时,保存的类信息其实是这样的一个类的信息:
<pre name="code" class="java">
public class Child{

public Child(){
}

public Child(String cn){
    setClassName(cn);
}

private String cname = "Child";

//-------------来自父类 begin----------------
protected String classname = "Father";

protected String getClassName(){
    return classname;
}

protected void setClassName(String cn){
    classname = cn;
}
//-------------来自父类 End----------------

public String getCname() {
    return cname;
}

public void setCname(String cname) {
    this.cname = cname;
}

}
</pre>
此类留有父类对子类可见的信息。

还是说,有另外一种方式,可以把子类与父类联系起来。

请指点!

我想知道原理,但可能表达的不太清楚,见谅!

-------------------补充------------------

以下是mccxj所说,我没太懂:

【子类里有一个区域放的父类的实例,子类内存区里有一个this指针,指向了这个内存区里包括的父类实例区,当把引用付给父类时,是把子类内存区里面的父类实例区域的引用给了父类的实例.】

子类内存区里this指针不是指向它自己的吗?
而super指针才是指向了父类的实例?
后面那句 【当把引用付给父类时,是把子类内存区里面的父类实例区域的引用给了父类的实例.】,同样不太懂,感觉很模糊。
是不是说,当把引用付给父类时,这个引用体现的其实是子类中父类实例的属性?

-------------------------再补充--------------------------
一下为bohemia 所说:
【super相当于指向父类示例的一个指针; 子类只保存子类的信息和super指针; 具体调用,先查找当前子类,然后查找父类是否有实现; 】

既然先查找子类,为何变量会找到父类呢?
(我查了,跟java的编译期绑定和运行时绑定有关)
想听听大家的理解。

[b]问题补充:[/b]
-------------------补充------------------

以下是mccxj所说,我没太懂:

【子类里有一个区域放的父类的实例,子类内存区里有一个this指针,指向了这个内存区里包括的父类实例区,当把引用付给父类时,是把子类内存区里面的父类实例区域的引用给了父类的实例.】

子类内存区里this指针不是指向它自己的吗?
而super指针才是指向了父类的实例?
后面那句 【当把引用付给父类时,是把子类内存区里面的父类实例区域的引用给了父类的实例.】,同样不太懂,感觉很模糊。
是不是说,当把引用付给父类时,这个引用体现的其实是子类中父类实例的属性?

-------------------------再补充--------------------------
一下为bohemia 所说:
【super相当于指向父类示例的一个指针; 子类只保存子类的信息和super指针; 具体调用,先查找当前子类,然后查找父类是否有实现; 】

既然先查找子类,为何变量会找到父类呢?
(我查了,跟java的编译期绑定和运行时绑定有关)
想听听大家的理解。

oo

6个回答

子类里有一个区域放的父类的实例,子类内存区里有一个this指针,指向了这个内存区里包括的父类实例区,当把引用付给父类时,是把子类内存区里面的父类实例区域的引用给了父类的实例.

除了要能取到父类的东西,而且还要区分哪些是父类的东西。全部都放到一起,不好区分把

mccxj说的对的;

super相当于指向父类示例的一个指针; 子类只保存子类的信息和super指针;
具体调用,先查找当前子类,然后查找父类是否有实现;

概念和语言实现的问题,建议可以看下 <深度探索C++对象模型>,这本书;

应该就对这些机制有了深入的理解和了解了.

当JVM加载一个子类的时候也会把它的父类一同加载的,子类内部通过super保存父类的一个引用,详细情况可以看看《Thinking in java》,里面已经说的非常详尽了

[quote]既然先查找子类,为何变量会找到父类呢? [/quote]

你有点糊涂了把?子类只是有个父类的引用。。那找父类有什么奇怪的?

说到底还是乱七八糟的指针的东西。。。只是虚拟机给偶们屏蔽得很好。。。

貌似bohemia说的那本书很好很强大

Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问