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

Golden_Dog 2015-01-13 10:44:30
子类为C,父类为F;
---------------------------------------------------------
C实例化之前会先实例化F
那么
最后得到的C对象是包含了F对象
还是
仅仅在C对象中包含了F对象的引用??如果是这种情况,是不是说:实例化一个子类对象,会把他所有的父类实例化并且保存下来,这样是不是会很浪费内存,毕竟好多类是有很多父类的。

问题应该也可以等同于
当通过C对象调用没有被覆写的方法时,是直接调用了C对象中的方法?
还是通过引用调用了F对象的方法?
...全文
902 36 打赏 收藏 转发到动态 举报
写回复
用AI写文章
36 条回复
切换为时间正序
请发表友善的回复…
发表回复
乔巴好萌 2015-01-16
  • 打赏
  • 举报
回复
打错了 父子对象
乔巴好萌 2015-01-16
  • 打赏
  • 举报
回复
从实现上来说,父子进程应该位于一个同样的内存起始地址,只不过对这片内存地址的引用和解释依赖于前面的类型,因为Java依赖于JVM,所以这个地方你可以借用下C++看下,OO的实现机制大体都是一样的,父子进程没道理布局在不同的内存区域上,因为这样在runtime时,势必降低效率 你看下C++的实现 #include <iostream> using namespace std; class A{ public: A(){ this->value = 2; printf("Parent %p %p\n ",this, &(this->value)); } public: int value; }; class B: public A{ public: B(){ this->value = 0; this->mChildValue = 1; printf("Child %p %p\n\n", this, &(this->mChildValue)); } private: int mChildValue; }; int main(int argc, char *argv[]) { B b; return 0; } Parent 0x7fff5fbffc88 0x7fff5fbffc88 Child 0x7fff5fbffc88 0x7fff5fbffc8c 0x7fff5fbffc88 这个是父子进程的内存首地址,2者是一样的,构造的时候先构造了父类,接着在后面的内存区上构建子类 对应的java对象这个构建在堆上 0x7fff5fbffc8c 这个由于子类自己加了一个4字节的成员变量,可以看到子类和父类的field的偏移量就是这个4字节的对象
Golden_Dog 2015-01-16
  • 打赏
  • 举报
回复
引用 29 楼 zxs6587 的回复:
[quote=引用 28 楼 u011385186 的回复:] 恩,谢谢。static方法属于类,所以父类引用可以调用static方法,这和子类父类没什么必然关系吧?final方法不能被override。
我的意思是说:父类引用指向子类对象,但子类对象中存在与父类相同的static方法或者final方法,此时父类引用调用的static或者final方法,都是调用父类方法,不会执行子类中的static或者final方法,就是没有像普通方法那样动态绑定![/quote] 恩,是的。
Runner6587 2015-01-16
  • 打赏
  • 举报
回复
引用 28 楼 u011385186 的回复:
恩,谢谢。static方法属于类,所以父类引用可以调用static方法,这和子类父类没什么必然关系吧?final方法不能被override。
我的意思是说:父类引用指向子类对象,但子类对象中存在与父类相同的static方法或者final方法,此时父类引用调用的static或者final方法,都是调用父类方法,不会执行子类中的static或者final方法,就是没有像普通方法那样动态绑定!
Golden_Dog 2015-01-16
  • 打赏
  • 举报
回复
引用 27 楼 zxs6587 的回复:
[quote=引用 26 楼 u011385186 的回复:] [quote=引用 21 楼 zxs6587 的回复:] 只要记住:子类继承父类,继承了父类除了构造方法外的所有方法和属性!当创建子类对象时就要通过调用父类的构造方法来初始化从父类继承而来的属性!
恩,谢谢。看了不少回复,推测(不知对不对): 对于子类对象 1.从外部来看父类对象此时已经融入到了子类当中,不论是通过引用的方式还是把父类对象包装好放到子类当中,总之此时它们是一个整体。这个融合包含两个方面:从成员变量的角度,看不管是父类对象的什么成员变量(包括private的),都会包含在里面;从方法的角度看,当方法有覆写时,可能在子类对象中还存在着父类的方法,只是在通过子类对象访问时不会找父类的方法,而去找子类的方法(或许这里面有个寻找方法的过程),当然也可能父类方法直接就被覆盖了。 总之,从外部看它们是一个整体,子类父类的成员变量简单叠加(不论是否重名),子类父类的方法不知是简单叠加还是简单覆盖 2.从内部看,子类对象可以通过super访问父类的成员变量(不包括private)以及方法,(看起来更像是用引用来实现了父类成员变量的包含)。 我更趋向于的答案:子类实例化之前父类进行了初始化,最后子类对象中包含了一些引用(这些引用可能编译时是自动添加上的)指向了父类的成员变量以及方法。所以看起来子类对象拥有父类的private属性,而多态的实现我猜想:子类对象会先寻找自己的方法看有没有,没有就会去父类的方法区寻找(就近寻找)。 最后,子类实例化前父类仅仅初始化,还没有形成对象(我对对象研究不多,可能形成一个对象会包含很多信息),因此在子类的实例化后不会存在两个或更多对象,它就是一个对象,只是实例化过程复杂了一些。[/quote] 我也不敢说理解的对错!至少我感觉是没有错误的!对于多态:只有普通方法存在动态绑定!如果父类的方法是staic或者final的,用父类引用指向子类对象,调用static或者final方法,都是执行的父类中方法!还有对象的成员变量也没有动态绑定![/quote] 恩,谢谢。static方法属于类,所以父类引用可以调用static方法,这和子类父类没什么必然关系吧?final方法不能被override。
Runner6587 2015-01-16
  • 打赏
  • 举报
回复
引用 26 楼 u011385186 的回复:
[quote=引用 21 楼 zxs6587 的回复:] 只要记住:子类继承父类,继承了父类除了构造方法外的所有方法和属性!当创建子类对象时就要通过调用父类的构造方法来初始化从父类继承而来的属性!
恩,谢谢。看了不少回复,推测(不知对不对): 对于子类对象 1.从外部来看父类对象此时已经融入到了子类当中,不论是通过引用的方式还是把父类对象包装好放到子类当中,总之此时它们是一个整体。这个融合包含两个方面:从成员变量的角度,看不管是父类对象的什么成员变量(包括private的),都会包含在里面;从方法的角度看,当方法有覆写时,可能在子类对象中还存在着父类的方法,只是在通过子类对象访问时不会找父类的方法,而去找子类的方法(或许这里面有个寻找方法的过程),当然也可能父类方法直接就被覆盖了。 总之,从外部看它们是一个整体,子类父类的成员变量简单叠加(不论是否重名),子类父类的方法不知是简单叠加还是简单覆盖 2.从内部看,子类对象可以通过super访问父类的成员变量(不包括private)以及方法,(看起来更像是用引用来实现了父类成员变量的包含)。 我更趋向于的答案:子类实例化之前父类进行了初始化,最后子类对象中包含了一些引用(这些引用可能编译时是自动添加上的)指向了父类的成员变量以及方法。所以看起来子类对象拥有父类的private属性,而多态的实现我猜想:子类对象会先寻找自己的方法看有没有,没有就会去父类的方法区寻找(就近寻找)。 最后,子类实例化前父类仅仅初始化,还没有形成对象(我对对象研究不多,可能形成一个对象会包含很多信息),因此在子类的实例化后不会存在两个或更多对象,它就是一个对象,只是实例化过程复杂了一些。[/quote] 我也不敢说理解的对错!至少我感觉是没有错误的!对于多态:只有普通方法存在动态绑定!如果父类的方法是staic或者final的,用父类引用指向子类对象,调用static或者final方法,都是执行的父类中方法!还有对象的成员变量也没有动态绑定!
Golden_Dog 2015-01-16
  • 打赏
  • 举报
回复
引用 21 楼 zxs6587 的回复:
只要记住:子类继承父类,继承了父类除了构造方法外的所有方法和属性!当创建子类对象时就要通过调用父类的构造方法来初始化从父类继承而来的属性!
恩,谢谢。看了不少回复,推测(不知对不对): 对于子类对象 1.从外部来看父类对象此时已经融入到了子类当中,不论是通过引用的方式还是把父类对象包装好放到子类当中,总之此时它们是一个整体。这个融合包含两个方面:从成员变量的角度,看不管是父类对象的什么成员变量(包括private的),都会包含在里面;从方法的角度看,当方法有覆写时,可能在子类对象中还存在着父类的方法,只是在通过子类对象访问时不会找父类的方法,而去找子类的方法(或许这里面有个寻找方法的过程),当然也可能父类方法直接就被覆盖了。 总之,从外部看它们是一个整体,子类父类的成员变量简单叠加(不论是否重名),子类父类的方法不知是简单叠加还是简单覆盖 2.从内部看,子类对象可以通过super访问父类的成员变量(不包括private)以及方法,(看起来更像是用引用来实现了父类成员变量的包含)。 我更趋向于的答案:子类实例化之前父类进行了初始化,最后子类对象中包含了一些引用(这些引用可能编译时是自动添加上的)指向了父类的成员变量以及方法。所以看起来子类对象拥有父类的private属性,而多态的实现我猜想:子类对象会先寻找自己的方法看有没有,没有就会去父类的方法区寻找(就近寻找)。 最后,子类实例化前父类仅仅初始化,还没有形成对象(我对对象研究不多,可能形成一个对象会包含很多信息),因此在子类的实例化后不会存在两个或更多对象,它就是一个对象,只是实例化过程复杂了一些。
Golden_Dog 2015-01-16
  • 打赏
  • 举报
回复
引用 22 楼 cumtwyc 的回复:
[quote=引用 18 楼 u011385186 的回复:] [quote=引用 13 楼 cumtwyc 的回复:] 父类初始化是肯定的,同时父类的构造函数也会被调用,这就相当于实例化了父类,只是没有将其赋给一个引用变量而已。
恩,谢谢。有人说是父类初始化,有人说是实例化,那么最终意思是不是: 父类开辟了(至少开辟过)内存来存放父类的成员变量,并且进行了初始化赋值? 那么子类对象最终在堆内形成后,子类对象内有没有(刚刚在堆内初始化的)父类的成员变量? 也可以说,子类对象的形成是把父类成员变量复制进来一份然后让父类之前的成员变量随风而去? 还是说子类对象仅仅持有父类的引用,要用父类成员变量时再通过引用去找,父类对象相当于隐形的存在着? 希望有看过子类实例化在jvm中具体过程的人认真回答,谢谢。 其实我感觉有点钻牛角尖了。[/quote] 1.父类开辟了(至少开辟过)内存来存放父类的成员变量,并且进行了初始化赋值? 既有父类类初始化,也有实例化,二者是不同的概念。当你实例化一个子类的时候,JVM在解析的过程中加载、链接(类变量分配内存并初始化为默认值)、初始化(为类变量赋值,包括直接赋值语句,静态块赋值语句等),这是一个递归的过程,直到回到当前类。然后进行实例化,实例化也有一个类似的过程,首先调用父类的<init>方法,父类<init>方法最多包括三个部分,其中就有父类的构造函数,所以说我前面回答相当于实例化了父类。 2.那么子类对象最终在堆内形成后,子类对象内有没有(刚刚在堆内初始化的)父类的成员变量? 肯定是有的,至于子类对象在堆中怎么组织,不同的JVM实现可以采取不同的方式。 3.也可以说,子类对象的形成是把父类成员变量复制进来一份然后让父类之前的成员变量随风而去? 还是说子类对象仅仅持有父类的引用,要用父类成员变量时再通过引用去找,父类对象相当于隐形的存在着? 回答同上面一样,你问的这些问题肯定也是JVM设计者们曾经考虑的问题。有的实现是把父类中的属性和方法按照顺序排列到子类中,子类如果重写了对应的方法,则将父类的覆盖,内部通过指针实现,这样在访问从父类继承的方法时,减少了一次指针访问,加快了速度。 父类实例化后不会立刻消亡,因为子类中可以使用super访问父类成员(相当于super引用父类,所以不会被垃圾回收),而且当我们使用super调用父类成员时,父类并没有再次调用构造函数进行初始化,这些可以作为证明(最后一句是个人推测而已,仅供参考)。[/quote] 恩,谢谢。看了不少回复,推测(不知对不对): 对于子类对象 1.从外部来看父类对象此时已经融入到了子类当中,不论是通过引用的方式还是把父类对象包装好放到子类当中,总之此时它们是一个整体。这个融合包含两个方面:从成员变量的角度,看不管是父类对象的什么成员变量(包括private的),都会包含在里面;从方法的角度看,当方法有覆写时,可能在子类对象中还存在着父类的方法,只是在通过子类对象访问时不会找父类的方法,而去找子类的方法(或许这里面有个寻找方法的过程),当然也可能父类方法直接就被覆盖了。 总之,从外部看它们是一个整体,子类父类的成员变量简单叠加(不论是否重名),子类父类的方法不知是简单叠加还是简单覆盖 2.从内部看,子类对象可以通过super访问父类的成员变量(不包括private)以及方法,(看起来更像是用引用来实现了父类成员变量的包含)。 我更趋向于的答案:子类实例化之前父类进行了初始化,最后子类对象中包含了一些引用(这些引用可能编译时是自动添加上的)指向了父类的成员变量以及方法。所以看起来子类对象拥有父类的private属性,而多态的实现我猜想:子类对象会先寻找自己的方法看有没有,没有就会去父类的方法区寻找(就近寻找)。 最后,子类实例化前父类仅仅初始化,还没有形成对象(我对对象研究不多,可能形成一个对象会包含很多信息),因此在子类的实例化后不会存在两个或更多对象,它就是一个对象,只是实例化过程复杂了一些。
Golden_Dog 2015-01-16
  • 打赏
  • 举报
回复
引用 15 楼 wangxf_8341 的回复:
对象的实例化和初始化是两个概念 对象初始化的时候如果发现父类没有被初始化,就会先初始化父类,依次类推,但是如果父类是接口则不会去初始化父类 类的初始化是由类被主动使用导致的,new是一种,Class.forName()是一种,还有就是调用一个类的方法、属性或延迟的常量(就像下面的例子)

public class InitialTest {

    public static void main(String[] args) {
        Entity e = new Entity();
        Good g = e.CONST;//此处注释就不会打印"Good initial!"
    }

    static class Entity implements Bean {

        @Override
        public void execute() {
            // TODO Auto-generated method stub

        }
        static{
            System.out.println("Entity initial!");
        }
    }

    interface Bean {

        Good CONST = new Good();

        void execute();
    }

    static class Good {

        static {
            System.out.println("Good initial!");
        }
    }
}

恩,谢谢。有人说是父类初始化,有人说是实例化,那么最终意思是不是: 父类开辟了(至少开辟过)内存来存放父类的成员变量,并且进行了初始化赋值? 那么子类对象最终在堆内形成后,子类对象内有没有(刚刚在堆内初始化的)父类的成员变量? 也可以说,子类对象的形成是把父类成员变量复制进来一份然后让父类之前的成员变量随风而去? 还是说子类对象仅仅持有父类的引用,要用父类成员变量时再通过引用去找,父类对象相当于隐形的存在着? 希望有看过子类实例化在jvm中具体过程的人认真回答,谢谢。 其实我感觉有点钻牛角尖了。
引用 20 楼 skyhitnow 的回复:
[quote=引用 17 楼 u011385186 的回复:] [quote=引用 13 楼 cumtwyc 的回复:] 父类初始化是肯定的,同时父类的构造函数也会被调用,这就相当于实例化了父类,只是没有将其赋给一个引用变量而已。
我做过一个小测试:C,F都有Private int id; 那么C的对象是可以对C和F的id进行Set和Get的。
引用 11 楼 skyhitnow 的回复:
ackage extendtest;

/**
 *
 * @author Administrator
 */
public class Test {
public static int Number=1;
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        Child ppa=new Child();
    }
    
}

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package extendtest;

/**
 *
 * @author FathersFatherdministrator
 */
public class FathersFather {
    private String i;
    private static String s;
    {
        this.i="FathersFather";
        System.out.println(Test.Number+++"  "+i+"实例变量初始化");
    }
    static {
        s="FathersFather";
        System.out.println(Test.Number+++"  "+s+"类变量初始化");
    }
    public FathersFather() {
        System.out.println(Test.Number+++"  "+"FathersFather构造器调用");
    }
   
}
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package extendtest;

/**
 *
 * @author Administrator
 */
public class Father extends FathersFather{
    private String i;
    private static String s;
    {
        this.i="Father";
        System.out.println(Test.Number+++"  "+i+"实例变量初始化");
    }
    static {
        s="Father";
        System.out.println(Test.Number+++"  "+s+"类变量初始化");
    }
    public Father() {
        System.out.println(Test.Number+++"  "+"Father构造器调用");
    }
}
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package extendtest;

/**
 *
 * @author Administrator
 */
public class Child extends Father{
    private String i;
    private static String s;
    {
        this.i="Child";
        System.out.println(Test.Number+++"  "+i+"实例变量初始化");
    }
    static {
        s="Child";
        System.out.println(Test.Number+++"  "+s+"类变量初始化");
    }

    public Child() {
        System.out.println(Test.Number+++"  "+"Child构造器调用");
    }
    
}
运行结果: 1 FathersFather类变量初始化 2 Father类变量初始化 3 Child类变量初始化 4 FathersFather实例变量初始化 5 FathersFather构造器调用 6 Father实例变量初始化 7 Father构造器调用 8 Child实例变量初始化 9 Child构造器调用 ========================= 结论:子类实例化必然伴随父类实例化,也就是说产生了父类的对象。但是父类对象的引用不可传递。也就是说只能通过super关键字从子类中访问父类的方法、字段。构造器等,当然,是在权限许可的情况下。但是无法将super赋值给新的引用变量。
恩,谢谢。有人说是父类初始化,有人说是实例化,那么最终意思是不是: 父类开辟了(至少开辟过)内存来存放父类的成员变量,并且进行了初始化赋值? 那么子类对象最终在堆内形成后,子类对象内有没有(刚刚在堆内初始化的)父类的成员变量? 也可以说,子类对象的形成是把父类成员变量复制进来一份然后让父类之前的成员变量随风而去? 还是说子类对象仅仅持有父类的引用,要用父类成员变量时再通过引用去找,父类对象相当于隐形的存在着? 希望有看过子类实例化在jvm中具体过程的人认真回答,谢谢。 其实我感觉有点钻牛角尖了。 [/quote] 1 实例化是指对象的创建,即生成类的对象; 2 初始化是指类的对应Class对象的创建以及静态成员、静态初始化块的执行; 3 父类对象不同于一般的对象,它并非单独在堆上创建,而是内嵌在子类对象之中,所以不可以从外部引用它;它的所有状态都能够保持,即使是不能够访问的private字段(没有公有get set方法)。所以,虽然它不是独立的对象,但是对于子类对象来说,它在功能上和独立对象没有什么区别。你可以把它当成独立的对象。当然,java的语言关系错综复杂,有时候可能会有微妙的限制,本人水平有限,也无法说清楚它的全部不同之处。[/quote] 恩,谢谢。看了不少回复,推测(不知对不对): 对于子类对象 1.从外部来看父类对象此时已经融入到了子类当中,不论是通过引用的方式还是把父类对象包装好放到子类当中,总之此时它们是一个整体。这个融合包含两个方面:从成员变量的角度,看不管是父类对象的什么成员变量(包括private的),都会包含在里面;从方法的角度看,当方法有覆写时,可能在子类对象中还存在着父类的方法,只是在通过子类对象访问时不会找父类的方法,而去找子类的方法(或许这里面有个寻找方法的过程),当然也可能父类方法直接就被覆盖了。 总之,从外部看它们是一个整体,子类父类的成员变量简单叠加(不论是否重名),子类父类的方法不知是简单叠加还是简单覆盖 2.从内部看,子类对象可以通过super访问父类的成员变量(不包括private)以及方法,(看起来更像是用引用来实现了父类成员变量的包含)。 我更趋向于的答案:子类实例化之前父类进行了初始化,最后子类对象中包含了一些引用(这些引用可能编译时是自动添加上的)指向了父类的成员变量以及方法。所以看起来子类对象拥有父类的private属性,而多态的实现我猜想:子类对象会先寻找自己的方法看有没有,没有就会去父类的方法区寻找(就近寻找)。 最后,子类实例化前父类仅仅初始化,还没有形成对象(我对对象研究不多,可能形成一个对象会包含很多信息),因此在子类的实例化后不会存在两个或更多对象,它就是一个对象,只是实例化过程复杂了一些。
乔巴好萌 2015-01-16
  • 打赏
  • 举报
回复
class FooClass{ } class Parent{ FooClass c; Parent(){ this.c = new FooClass(); System.out.println("Parent\t" + c.hashCode()); } } class Child extends Parent{ Child(){ System.out.println("Child\t" + this.c.hashCode()); } } public class MyTest { public static void main(String[] args) { Child c = new Child(); } } 是引用
wyc_ 2015-01-16
  • 打赏
  • 举报
回复
引用 18 楼 u011385186 的回复:
[quote=引用 13 楼 cumtwyc 的回复:] 父类初始化是肯定的,同时父类的构造函数也会被调用,这就相当于实例化了父类,只是没有将其赋给一个引用变量而已。
恩,谢谢。有人说是父类初始化,有人说是实例化,那么最终意思是不是: 父类开辟了(至少开辟过)内存来存放父类的成员变量,并且进行了初始化赋值? 那么子类对象最终在堆内形成后,子类对象内有没有(刚刚在堆内初始化的)父类的成员变量? 也可以说,子类对象的形成是把父类成员变量复制进来一份然后让父类之前的成员变量随风而去? 还是说子类对象仅仅持有父类的引用,要用父类成员变量时再通过引用去找,父类对象相当于隐形的存在着? 希望有看过子类实例化在jvm中具体过程的人认真回答,谢谢。 其实我感觉有点钻牛角尖了。[/quote] 1.父类开辟了(至少开辟过)内存来存放父类的成员变量,并且进行了初始化赋值? 既有父类类初始化,也有实例化,二者是不同的概念。当你实例化一个子类的时候,JVM在解析的过程中加载、链接(类变量分配内存并初始化为默认值)、初始化(为类变量赋值,包括直接赋值语句,静态块赋值语句等),这是一个递归的过程,直到回到当前类。然后进行实例化,实例化也有一个类似的过程,首先调用父类的<init>方法,父类<init>方法最多包括三个部分,其中就有父类的构造函数,所以说我前面回答相当于实例化了父类。 2.那么子类对象最终在堆内形成后,子类对象内有没有(刚刚在堆内初始化的)父类的成员变量? 肯定是有的,至于子类对象在堆中怎么组织,不同的JVM实现可以采取不同的方式。 3.也可以说,子类对象的形成是把父类成员变量复制进来一份然后让父类之前的成员变量随风而去? 还是说子类对象仅仅持有父类的引用,要用父类成员变量时再通过引用去找,父类对象相当于隐形的存在着? 回答同上面一样,你问的这些问题肯定也是JVM设计者们曾经考虑的问题。有的实现是把父类中的属性和方法按照顺序排列到子类中,子类如果重写了对应的方法,则将父类的覆盖,内部通过指针实现,这样在访问从父类继承的方法时,减少了一次指针访问,加快了速度。 父类实例化后不会立刻消亡,因为子类中可以使用super访问父类成员(相当于super引用父类,所以不会被垃圾回收),而且当我们使用super调用父类成员时,父类并没有再次调用构造函数进行初始化,这些可以作为证明(最后一句是个人推测而已,仅供参考)。
Runner6587 2015-01-16
  • 打赏
  • 举报
回复
只要记住:子类继承父类,继承了父类除了构造方法外的所有方法和属性!当创建子类对象时就要通过调用父类的构造方法来初始化从父类继承而来的属性!
skyhitnow 2015-01-16
  • 打赏
  • 举报
回复
引用 17 楼 u011385186 的回复:
[quote=引用 13 楼 cumtwyc 的回复:] 父类初始化是肯定的,同时父类的构造函数也会被调用,这就相当于实例化了父类,只是没有将其赋给一个引用变量而已。
我做过一个小测试:C,F都有Private int id; 那么C的对象是可以对C和F的id进行Set和Get的。
引用 11 楼 skyhitnow 的回复:
ackage extendtest;

/**
 *
 * @author Administrator
 */
public class Test {
public static int Number=1;
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        Child ppa=new Child();
    }
    
}

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package extendtest;

/**
 *
 * @author FathersFatherdministrator
 */
public class FathersFather {
    private String i;
    private static String s;
    {
        this.i="FathersFather";
        System.out.println(Test.Number+++"  "+i+"实例变量初始化");
    }
    static {
        s="FathersFather";
        System.out.println(Test.Number+++"  "+s+"类变量初始化");
    }
    public FathersFather() {
        System.out.println(Test.Number+++"  "+"FathersFather构造器调用");
    }
   
}
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package extendtest;

/**
 *
 * @author Administrator
 */
public class Father extends FathersFather{
    private String i;
    private static String s;
    {
        this.i="Father";
        System.out.println(Test.Number+++"  "+i+"实例变量初始化");
    }
    static {
        s="Father";
        System.out.println(Test.Number+++"  "+s+"类变量初始化");
    }
    public Father() {
        System.out.println(Test.Number+++"  "+"Father构造器调用");
    }
}
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package extendtest;

/**
 *
 * @author Administrator
 */
public class Child extends Father{
    private String i;
    private static String s;
    {
        this.i="Child";
        System.out.println(Test.Number+++"  "+i+"实例变量初始化");
    }
    static {
        s="Child";
        System.out.println(Test.Number+++"  "+s+"类变量初始化");
    }

    public Child() {
        System.out.println(Test.Number+++"  "+"Child构造器调用");
    }
    
}
运行结果: 1 FathersFather类变量初始化 2 Father类变量初始化 3 Child类变量初始化 4 FathersFather实例变量初始化 5 FathersFather构造器调用 6 Father实例变量初始化 7 Father构造器调用 8 Child实例变量初始化 9 Child构造器调用 ========================= 结论:子类实例化必然伴随父类实例化,也就是说产生了父类的对象。但是父类对象的引用不可传递。也就是说只能通过super关键字从子类中访问父类的方法、字段。构造器等,当然,是在权限许可的情况下。但是无法将super赋值给新的引用变量。
恩,谢谢。有人说是父类初始化,有人说是实例化,那么最终意思是不是: 父类开辟了(至少开辟过)内存来存放父类的成员变量,并且进行了初始化赋值? 那么子类对象最终在堆内形成后,子类对象内有没有(刚刚在堆内初始化的)父类的成员变量? 也可以说,子类对象的形成是把父类成员变量复制进来一份然后让父类之前的成员变量随风而去? 还是说子类对象仅仅持有父类的引用,要用父类成员变量时再通过引用去找,父类对象相当于隐形的存在着? 希望有看过子类实例化在jvm中具体过程的人认真回答,谢谢。 其实我感觉有点钻牛角尖了。 [/quote] 1 实例化是指对象的创建,即生成类的对象; 2 初始化是指类的对应Class对象的创建以及静态成员、静态初始化块的执行; 3 父类对象不同于一般的对象,它并非单独在堆上创建,而是内嵌在子类对象之中,所以不可以从外部引用它;它的所有状态都能够保持,即使是不能够访问的private字段(没有公有get set方法)。所以,虽然它不是独立的对象,但是对于子类对象来说,它在功能上和独立对象没有什么区别。你可以把它当成独立的对象。当然,java的语言关系错综复杂,有时候可能会有微妙的限制,本人水平有限,也无法说清楚它的全部不同之处。
Golden_Dog 2015-01-16
  • 打赏
  • 举报
回复
引用 33 楼 skyhitnow 的回复:
恩,谢谢。看了不少回复,推测(不知对不对): 对于子类对象 1.从外部来看父类对象此时已经融入到了子类当中,不论是通过引用的方式还是把父类对象包装好放到子类当中,总之此时它们是一个整体。这个融合包含两个方面:从成员变量的角度,看不管是父类对象的什么成员变量(包括private的),都会包含在里面;从方法的角度看,当方法有覆写时,可能在子类对象中还存在着父类的方法,只是在通过子类对象访问时不会找父类的方法,而去找子类的方法(或许这里面有个寻找方法的过程),当然也可能父类方法直接就被覆盖了。 总之,从外部看它们是一个整体,子类父类的成员变量简单叠加(不论是否重名),子类父类的方法不知是简单叠加还是简单覆盖 2.从内部看,子类对象可以通过super访问父类的成员变量(不包括private)以及方法,(看起来更像是用引用来实现了父类成员变量的包含)。 我更趋向于的答案:子类实例化之前父类进行了初始化,最后子类对象中包含了一些引用(这些引用可能编译时是自动添加上的)指向了父类的成员变量以及方法。所以看起来子类对象拥有父类的private属性,而多态的实现我猜想:子类对象会先寻找自己的方法看有没有,没有就会去父类的方法区寻找(就近寻找)。 最后,子类实例化前父类仅仅初始化,还没有形成对象(我对对象研究不多,可能形成一个对象会包含很多信息),因此在子类的实例化后不会存在两个或更多对象,它就是一个对象,只是实例化过程复杂了一些。 ========================================= 看前面测试程序结果: 子类实例化前先实例化父类; 最后整个对象包括:在父类中声明的所有实例变量、在子类中声明的所有实例变量。这样,未被覆盖的变量只有一份;覆盖的变量包括子类和父类中的各自一份。
31楼是真相,你可以研究一下
Golden_Dog 2015-01-16
  • 打赏
  • 举报
回复
引用 31 楼 openXMPP 的回复:
从实现上来说,父子进程应该位于一个同样的内存起始地址,只不过对这片内存地址的引用和解释依赖于前面的类型,因为Java依赖于JVM,所以这个地方你可以借用下C++看下,OO的实现机制大体都是一样的,父子进程没道理布局在不同的内存区域上,因为这样在runtime时,势必降低效率 你看下C++的实现 #include <iostream> using namespace std; class A{ public: A(){ this->value = 2; printf("Parent %p %p\n ",this, &(this->value)); } public: int value; }; class B: public A{ public: B(){ this->value = 0; this->mChildValue = 1; printf("Child %p %p\n\n", this, &(this->mChildValue)); } private: int mChildValue; }; int main(int argc, char *argv[]) { B b; return 0; } Parent 0x7fff5fbffc88 0x7fff5fbffc88 Child 0x7fff5fbffc88 0x7fff5fbffc8c 0x7fff5fbffc88 这个是父子进程的内存首地址,2者是一样的,构造的时候先构造了父类,接着在后面的内存区上构建子类 对应的java对象这个构建在堆上 0x7fff5fbffc8c 这个由于子类自己加了一个4字节的成员变量,可以看到子类和父类的field的偏移量就是这个4字节的对象
恩,太感谢了。好专业的回复,就是期待的答案! 看来实例化子类在内存中是连续进行的,在子类实例化过程中父类只是在前期打打地基,干完活就交给了子类继续完成。至少从内存上看:子类对象是个包含所有父类成员变量、自己成员变量的整体。
skyhitnow 2015-01-16
  • 打赏
  • 举报
回复
恩,谢谢。看了不少回复,推测(不知对不对): 对于子类对象 1.从外部来看父类对象此时已经融入到了子类当中,不论是通过引用的方式还是把父类对象包装好放到子类当中,总之此时它们是一个整体。这个融合包含两个方面:从成员变量的角度,看不管是父类对象的什么成员变量(包括private的),都会包含在里面;从方法的角度看,当方法有覆写时,可能在子类对象中还存在着父类的方法,只是在通过子类对象访问时不会找父类的方法,而去找子类的方法(或许这里面有个寻找方法的过程),当然也可能父类方法直接就被覆盖了。 总之,从外部看它们是一个整体,子类父类的成员变量简单叠加(不论是否重名),子类父类的方法不知是简单叠加还是简单覆盖 2.从内部看,子类对象可以通过super访问父类的成员变量(不包括private)以及方法,(看起来更像是用引用来实现了父类成员变量的包含)。 我更趋向于的答案:子类实例化之前父类进行了初始化,最后子类对象中包含了一些引用(这些引用可能编译时是自动添加上的)指向了父类的成员变量以及方法。所以看起来子类对象拥有父类的private属性,而多态的实现我猜想:子类对象会先寻找自己的方法看有没有,没有就会去父类的方法区寻找(就近寻找)。 最后,子类实例化前父类仅仅初始化,还没有形成对象(我对对象研究不多,可能形成一个对象会包含很多信息),因此在子类的实例化后不会存在两个或更多对象,它就是一个对象,只是实例化过程复杂了一些。 ========================================= 看前面测试程序结果: 子类实例化前先实例化父类; 最后整个对象包括:在父类中声明的所有实例变量、在子类中声明的所有实例变量。这样,未被覆盖的变量只有一份;覆盖的变量包括子类和父类中的各自一份。
Golden_Dog 2015-01-15
  • 打赏
  • 举报
回复
引用 14 楼 xujhsin30 的回复:
1.对像和类是两个维度的东西,您以可将子类和父类看成完全不同的两个类,所以它们的实例化没有任何相干性。 2.子类的实例和父类的实例之前没有任合关系。 3.子类的对像只是和你类拥有相同的父类暴露出来的函数、常量值、成员变量名及初始化值,仅此而已。
恩,谢谢。有人说是父类初始化,有人说是实例化,那么最终意思是不是: 父类开辟了(至少开辟过)内存来存放父类的成员变量,并且进行了初始化赋值? 那么子类对象最终在堆内形成后,子类对象内有没有(刚刚在堆内初始化的)父类的成员变量? 也可以说,子类对象的形成是把父类成员变量复制进来一份然后让父类之前的成员变量随风而去? 还是说子类对象仅仅持有父类的引用,要用父类成员变量时再通过引用去找,父类对象相当于隐形的存在着? 希望有看过子类实例化在jvm中具体过程的人认真回答,谢谢。 其实我感觉有点钻牛角尖了。
Golden_Dog 2015-01-15
  • 打赏
  • 举报
回复
引用 13 楼 cumtwyc 的回复:
父类初始化是肯定的,同时父类的构造函数也会被调用,这就相当于实例化了父类,只是没有将其赋给一个引用变量而已。
恩,谢谢。有人说是父类初始化,有人说是实例化,那么最终意思是不是: 父类开辟了(至少开辟过)内存来存放父类的成员变量,并且进行了初始化赋值? 那么子类对象最终在堆内形成后,子类对象内有没有(刚刚在堆内初始化的)父类的成员变量? 也可以说,子类对象的形成是把父类成员变量复制进来一份然后让父类之前的成员变量随风而去? 还是说子类对象仅仅持有父类的引用,要用父类成员变量时再通过引用去找,父类对象相当于隐形的存在着? 希望有看过子类实例化在jvm中具体过程的人认真回答,谢谢。 其实我感觉有点钻牛角尖了。
Golden_Dog 2015-01-15
  • 打赏
  • 举报
回复
引用 13 楼 cumtwyc 的回复:
父类初始化是肯定的,同时父类的构造函数也会被调用,这就相当于实例化了父类,只是没有将其赋给一个引用变量而已。
我做过一个小测试:C,F都有Private int id; 那么C的对象是可以对C和F的id进行Set和Get的。
引用 11 楼 skyhitnow 的回复:
ackage extendtest;

/**
 *
 * @author Administrator
 */
public class Test {
public static int Number=1;
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        Child ppa=new Child();
    }
    
}

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package extendtest;

/**
 *
 * @author FathersFatherdministrator
 */
public class FathersFather {
    private String i;
    private static String s;
    {
        this.i="FathersFather";
        System.out.println(Test.Number+++"  "+i+"实例变量初始化");
    }
    static {
        s="FathersFather";
        System.out.println(Test.Number+++"  "+s+"类变量初始化");
    }
    public FathersFather() {
        System.out.println(Test.Number+++"  "+"FathersFather构造器调用");
    }
   
}
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package extendtest;

/**
 *
 * @author Administrator
 */
public class Father extends FathersFather{
    private String i;
    private static String s;
    {
        this.i="Father";
        System.out.println(Test.Number+++"  "+i+"实例变量初始化");
    }
    static {
        s="Father";
        System.out.println(Test.Number+++"  "+s+"类变量初始化");
    }
    public Father() {
        System.out.println(Test.Number+++"  "+"Father构造器调用");
    }
}
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package extendtest;

/**
 *
 * @author Administrator
 */
public class Child extends Father{
    private String i;
    private static String s;
    {
        this.i="Child";
        System.out.println(Test.Number+++"  "+i+"实例变量初始化");
    }
    static {
        s="Child";
        System.out.println(Test.Number+++"  "+s+"类变量初始化");
    }

    public Child() {
        System.out.println(Test.Number+++"  "+"Child构造器调用");
    }
    
}
运行结果: 1 FathersFather类变量初始化 2 Father类变量初始化 3 Child类变量初始化 4 FathersFather实例变量初始化 5 FathersFather构造器调用 6 Father实例变量初始化 7 Father构造器调用 8 Child实例变量初始化 9 Child构造器调用 ========================= 结论:子类实例化必然伴随父类实例化,也就是说产生了父类的对象。但是父类对象的引用不可传递。也就是说只能通过super关键字从子类中访问父类的方法、字段。构造器等,当然,是在权限许可的情况下。但是无法将super赋值给新的引用变量。
恩,谢谢。有人说是父类初始化,有人说是实例化,那么最终意思是不是: 父类开辟了(至少开辟过)内存来存放父类的成员变量,并且进行了初始化赋值? 那么子类对象最终在堆内形成后,子类对象内有没有(刚刚在堆内初始化的)父类的成员变量? 也可以说,子类对象的形成是把父类成员变量复制进来一份然后让父类之前的成员变量随风而去? 还是说子类对象仅仅持有父类的引用,要用父类成员变量时再通过引用去找,父类对象相当于隐形的存在着? 希望有看过子类实例化在jvm中具体过程的人认真回答,谢谢。 其实我感觉有点钻牛角尖了。
qiaoqiao7370 2015-01-15
  • 打赏
  • 举报
回复
大多数类都有默认的构造方法,子类实例化时会先调用父类的构造方法。 因为是继承,所以子类继承了父类除构造方法以外的所有方法,实例化谁就调用谁里面的方法,也就是new后面的那部分。
加载更多回复(15)

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧