子类对象是包含整个父类对象仍是仅仅拥有父类对象的引用?

1.问题描述:

子类对象是包含整个父类对象仍是仅仅拥有父类对象的引用?
个人描述:扩展类的实例对象在内存中包含的是基类的一个实例还是实例的引用?

2.问题解释:

首先,这个问题有一个假设:任意一个类的实例必定至少有一个或多个对象组成;
第二,其结构方式类似于列表(包含基类对象)或者链表(持有引用);
总结,扩展类对象与基类对象的关系就是 ExtendsClassObj has a BaseClassObj

3.个人回答:

首先,类的扩展关系和基类实例与扩展类实例的关系是不具有相关性的,类的扩展目的在于代码的复用,而扩展类的对象与基类的对象之间没有任何关系(除非扩展类显式的声明扩展类对象持有一个基类对象的引用)。
所以扩展类实例化并不会实例化一个基类的对象,但是会加载基类并对基类初始化,原因很简单:需要复用基类的属性和方法。
第二,扩展类实例在进行实例方法调用或者对实例属性读写(方法或者属性来自于基类)的时,如果ExtendsClass没有重写BaseClass的方法,那么是不会包含BaseClass的方法信息(可以javap -c ExtendsClass 反编译字节码),那么他是怎么执行的呢?每个类在JVM内有自己的Class(Java用于描述类的类)对象(这个class对象里边有所属父类索引信息,自己的方法表,属性表等信息):在方法执行的时候,会首先检测引用的类型再检测其所指向对象的实际类型(Base base = new ExtendsBase()或者BaseExtends baseExtends = new BaseExtends())1,如果方法在扩展类的方法区里找到就执行扩展类的,2,如果在扩展类的方法中没有找到就会自动寻找它的基类的方法区3,重复1/2步骤;
tip: JVM对于静态方法和实力方法的invoke指令有区分,分别为invokestatic和invokevirtual;

4.关于this(aload_0)和super:

tip1:this指代当前线程操作的本类实例。由编译器在后台默认的的加在形参列表第一个位置上) obj.test(Object...objs) 可以理解为Class.test(obj,..objs) 在方法内用this指代obj(由JVM aload_0 载入);
tip2;super指代基类链表,super.getClass().getName()可以翻译为:从基类链的各自的方法区找到getClass()方法(Object final的不可被重写)然后执行,返回Class对象再getName();

//源代码:
public class Base {
    private String name;

    public Base() {
        super();
        // TODO Auto-generated constructor stub
    }
    public Base(String aname) {
        super();
        name = aname;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Base getInstance(){
        return this;
    }
    public static void test(Base base,String s,int i){
        System.out.println("test Base");
    }
}
//反编译:
Compiled from "Base.java"
public class oop.Base {
  public oop.Base();
    Code:
       0: aload_0  //将在本类construtor前的全部局部变量压入栈顶(this) 请注意getInstance方法的反编译
       1: invokespecial #10                 // Method java/lang/Object."<init>":()V
       4: return

  public oop.Base(java.lang.String);
    Code:
       0: aload_0
       1: invokespecial #10                 // Method java/lang/Object."<init>":()V
       4: aload_0
       5: aload_1  //构造参数压入栈顶
       6: putfield      #17                 // Field name:Ljava/lang/String;
       9: return

  public java.lang.String getName();
    Code:
       0: aload_0
       1: getfield      #17                 // Field name:Ljava/lang/String;
       4: areturn

  public void setName(java.lang.String);
    Code:
       0: aload_0
       1: aload_1
       2: putfield      #17                 // Field name:Ljava/lang/String;
       5: return

  public oop.Base getInstance();
    Code:
       0: aload_0
       1: areturn

  public static void test(oop.Base, java.lang.String, int);
    Code:
       0: getstatic     #27                 // Field java/lang/System.out:Ljava/io/PrintStream; 获取静态方法 
       3: ldc           #33                 // String test Base 载入字符串
       5: invokevirtual #35                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V执行实例方法
       8: return
}
//源代码:
public class BaseExtends extends Base{
    private String sex;
    public BaseExtends() {
        super();
        sex = "ChildSex";
    }

    public BaseExtends(String asex) {
        super();
        sex = asex;
    }
    public BaseExtends(String aname,String asex) {
        super(aname);
        sex = asex;
    }
    public String getSex() {
        return sex;
    }

    public void setSex(String asex) {
        sex = asex;
        super.getName();
    }
    public void test(String s){
        String str = sex;
    }
    public static void test(Base base ,String s,int i){
        System.out.println("test BaseExtends");
    }
}
//反编译
public class oop.BaseExtends extends oop.Base {
  public oop.BaseExtends();
    Code:
       0: aload_0
       1: invokespecial #10                 // Method oop/Base."<init>":()V  在执行基类的初始化代码
       4: aload_0 
       5: ldc           #12                 // String ChildSex
       7: putfield      #14                 // Field sex:Ljava/lang/String;
      10: return 

  public oop.BaseExtends(java.lang.String);
    Code:
       0: aload_0
       1: invokespecial #10                 // Method oop/Base."<init>":()V
       4: aload_0
       5: aload_1
       6: putfield      #14                 // Field sex:Ljava/lang/String;
       9: return

  public oop.BaseExtends(java.lang.String, java.lang.String);
    Code:
       0: aload_0
       1: aload_1
       2: invokespecial #23                 // Method oop/Base."<init>":(Ljava/lang/String;)V
       5: aload_0
       6: aload_2
       7: putfield      #14                 // Field sex:Ljava/lang/String;
      10: return

  public java.lang.String getSex();
    Code:
       0: aload_0
       1: getfield      #14                 // Field sex:Ljava/lang/String;
       4: areturn

  public void setSex(java.lang.String);
    Code:
       0: aload_0
       1: aload_1
       2: putfield      #14                 // Field sex:Ljava/lang/String;
       5: aload_0
       6: invokespecial #29                 // Method oop/Base.getName:()Ljava/lang/String;
       9: pop
      10: return

  public void test(java.lang.String);
    Code:
       0: aload_0
       1: getfield      #14                 // Field sex:Ljava/lang/String;
       4: astore_2
       5: return

  public static void test(oop.Base, java.lang.String, int);
    Code:
       0: getstatic     #36                 // Field java/lang/System.out:Ljava/io/PrintStream;
       3: ldc           #42                 // String test BaseExtends
       5: invokevirtual #44                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
       8: return
}

5.实例的构造过程(JVM 指令大体顺序):

new someClass //根据someClass的属性表开辟内存空间,并对各个属性初始化(赋予JVM默认值0啊,null啊等等 )返回内存空间的对应的“地址”。对于基类和扩展类有重复的属性这种情况(比如都分别声明了private String name这个属性,虽然是不合理不应该的设计),扩展类的实例在开辟内存空间时,name会分别的开辟不同的地址(基类和扩展类)。name对应的两个地址是JVM 指令getField或者putField的参数)
invokespecial //调用自己写的初始化代码
retunr aload_0的值;

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 135,929评论 19 139
  • 国家电网公司企业标准(Q/GDW)- 面向对象的用电信息数据交换协议 - 报批稿:20170802 前言: 排版 ...
    庭说阅读 13,963评论 6 13
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 32,622评论 18 399
  • 一、创建分支 本地分支 远程分支 二、删除分支 本地分支 远程分支 三、查看分支 本地分支 远程分支 四、切换分支
    鱼小念阅读 2,910评论 0 0
  • 樱花花语 樱花是爱情与希望的象征,代表着高雅,质朴纯洁的爱情。樱花宛如懵懂少女 的,安静得在春天开放,满树...
    芠芐whisky阅读 2,607评论 2 6

友情链接更多精彩内容