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

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的值;

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容

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