请问,下面这句话是什么意思呢?SuperA p = new SubB();(其中,SubB是SuperA的子类)1.等号定义成父类的类型,右边是子类的构造方法,那实例化出来的是子类还是父类啊?2.这句话应该也是从右边执行到左边的吧,那它的实际内部执行过程是怎样的?比如分配内存空间什么的。3.这句话执行的过程中会什么时候调用父类的构造函数啊,调用几次?4.这与左右边都是子类的情况有什么不同吗?

解决方案 »

  1.   

    以我个人理解new SubB()是在改造一个SubB类的对象。=就是将构造的对象付给SuperA类的引用 A,由于两者的类型不一致,必定存在一个类型的转换!于是也就回答你的1,2.至于第三问完全可以自己做实验来解决。至于第四问,我想明白了1,2也就差不多了!
      

  2.   

    如果你要搞清楚这个问题首先你要搞清楚三个个问题:
    第一、编译时与运行时的区别。
    第二、深刻理解面向对象的原理与思想,也就是类与对象的联系与区别。
    第三、理解什么引用什么是数据。
    在你能够搞清楚这三个问题之前恐怕你不那么好理解上面那句多态的语句到底是干了什么。
    不过我现在绕过那三个问题吧答案告诉,至于为什么你搞清楚那三个问题就都明白了:
    1、实例化出来的是子类而不是父类。
    2、赋值操作符都是从右往左执行,这句话代表想内存申请空间存放对象并执行构造函数。
    3、执行构造函数的第一句话就是执行父类的构造函数(也就是立即执行父类构造函数),如果父类不是java.lang.Object对象,那么就继续往上执行父类构造函数,直到java.lang.Object。
    4、如果左边是父类引用,那么只能调用对象在父类中声明的方法和属性,如果左边是本类引用,则可以调用所有的方法和属性。
      

  3.   

    同意楼上,父类引用可以指向子类对象。
    还有,new B() 内部操作有点复杂:先是为最顶端父类对象分配内存空间,
                                     然后对这个对象进行默认初始化,
                                     然后执行构造体代码。
                               然后逐步向下(向子类方向)进行同样的动作,直到执行完成B对象的构造方法。
    建议楼主在看看think in java。
      

  4.   

    这么作的  会使子类变窄    就是 子类中有的方法而父类中没有的方法 
      在这个以父类引用变量作为引用的子类对象不能在调用其子类有而父类中没有的方法了
    public class A {
    public static void main(String[] args){
    C c=new B();
    c.abc();
                    c.abcd();//会报错找不到此方法

    }
    }
    class  B extends C{
    void abc(){
    System.out.println("d");
    }
    void abcd(){
    System.out.println("dsfdsf");
    }
    }
    class  C{
    void abc(){
    System.out.println("SDFSDFSD");

    }

    }
      

  5.   

    我依旧是那么说,首先要理解我说的那三个问题你才能真正理解SuperA p = new SubB();这句话做了什么,它有什么意义。
    要理解什么是编译时什么是运行时,他们会有什么区别。
    你们所说的多态其实都是编译时的概念,父类引用引用子类对象不存在什么转型,这种转型的说法只是一种被编译时的表面现象所误导而一厢情愿的猜测而已,不会有这种转型语句的存在,它是那种类型的对象在内存中就会一直是那种内存的对象,无论引用它的是哪个数据类型的引用。还有8楼的那位,你的理解是很多学习java的人都会出现的一个理解错误,按照你的那种说法,如果一个类继承了N层那么它实例化就会有N个对象,那么一个类的实例化至少会有两个对象,因为至少继承Object类。你不觉得这样太消耗内存了么,你认为java的实现者们会这么去实现java机制么?而且这种说法也存在明显的漏洞,如果父类是一个接口或者是抽象类呢,很明显它们不能被实例化,你要如何解释这种情况的存在;还有另外一个漏洞就是如果因为这样存在大量对象在内存中,岂不是更加增加了虚拟机对对象管理负担?如果把这个问题再细想下去,会发现不合理性和漏洞越来越多,你不会认为那些设计java语言的人都是白痴吧。总结一句,其实学习java很多特性在开始的时候确实很难理解,特别是多态的理解与继承的机制,因为这牵扯到很多底层的机制,这些机制是这些实现思想的基础,但是他们对一个初学者来说又比较难以掌握,所以我建议还是慢慢来,不要急着一口吃成胖子,学得多练得多了以后就慢慢理解了,这总要有个过程的。
      

  6.   


    没错,继承N层就会产生N的对象,你可以想一想,如果没有上层对象,或者说上层的实例变量没有初始化的话,就初始化子类对象,是会有问题的。
    至于你说的Object必须存在的,我认为应该是这样的,Object对象占用的内存得看object的实例变量有多少有多大,这一点我还不确定,不过Object作为顶层类不会有多少实例变量的,还有你说的接口,接口是不用初始化父接口的。
      

  7.   

    其实你们会理解成继承N层就有N个对象也是很正常的,我曾经也这么认为过,这并没什么,会这么想的人都在认真学习java,但是这种想法毕竟只是一种一厢情愿的猜想,我相信你们并没有去验证过也没有通过更深入的学习去理解,而且你们吧思维扩散一下,如果要实现继承机制有几种做法,如果是你会用哪种做法?如果只是想出一个可靠的想法就认为那是正确的显然是不对的。
    也许用继承N层就实例化N个对象也许同样能够实现继承机制,但是java是不是这样做的还是需要继续学习,给自己一个确定的答案。再总结一句,有了猜想就要去验证,不能觉得猜想行得通他就是对的,正确的答案需要自己去寻找,就算我告诉你们答案你们也不理解,而且你们也不会同意我告诉你们的答案,而且我的答案也未必是正确的。
      

  8.   

    答:玩过套盒子的游戏吧.大盒子里套了个小盒子,小盒子里套了个更小盒子,更小盒子里套了个...,一直下去.
    因此:孙子的对象空间里含有一个完整的爸爸对象(直接作为孙子对象中的一个部分),爸爸对象空间中含有一个完整的爸爸的爸爸(爷爷),爷爷的对象空间中含有一个完整的爷爷的爸爸(祖爷爷),......,一直下去,直到最后是Object老祖宗.
      

  9.   


    SuperA p = new SubB(); 
    后面还可以接一句:
    SubB p2=(SubB)p;这样是合法的。如果p是父类的话,怎么可以强制转型到子类呢?
    因此,p一定是子类对象
      

  10.   

    多态就是这样:子类对象一定是其父类的一个对象,比如:“水果”是一个类,“苹果”是“水果”的子类,那么如果我手里拿了一个“苹果”(一个类型为苹果的对象),其实也可以说我手里拿着一个水果。这时自然就可以直接赋值:Fruit obj = new Apple();但是父类的一个对象不一定是其子类的一个对象。比如:“香焦”和“苹果”都是“水果”的子类,如果我现在手里拿着一个“水果”,那么这个水果就有可能是香焦,也可能是一个苹果。这时把父类对象的引用赋值给子类对象时,就要用 instanceof 判断一下以确定它更精确的类型,并且还要作强制类型转换:
    Fruit obj = .....;
    ..
    ..
    if(obj instanceof Apple) {
        Apple apple = (Apple)obj;
    }同在一个“家族”中的兄弟类型之间是不能赋值的,也不能强制类型转换,否则会报编译错误。比如:苹果绝对不可能是香焦,所以下面的代码编译不过:
    Apple app = new Banana();同样的道理,想让不相干的类型之间进行转换也会报编译错误,比如一辆汽车绝对不可能是一个苹果,因此:
    Apple app = new Car();
    是会报编译错误的。
      

  11.   

    看看thinking in java 的多态那章,就会理解的。
      

  12.   


    1. 实例化出来的是子类的对象
    2. 内部执行过程:
    1)新建一个父类的引用p,指向null; 
    2)调用java.lang.Object构造函数,调用Object的子类构造函数一次类推调用父类构造函数,调用子类构造函数,新建出一个子类的对象,对象初始化;
    3)把子类的对象分配给引用p
    3. 新建子类对象时调用父类构造函数,调用一次
    4. 多态,具体用途很多,请参考教科书建议楼主找本书看看多态这一章,或者找个视频教程看看有关内容
      

  13.   

    SuperA p = new SubB(); 如果说左边是一个父类的引用,右边是一个子类的实例,然后把这个父类的引用指向这个子类,那这个父类的对象存在吗?是不是先要在SuperA p = new SubB(); 这句的前边再加上父类实例化的语句啊?右边在实例化子类的时候,会先调用父类的构造函数,那这次执行父类构造函数的时候会实例化出一个父类的对象吗?左边的SuperA p这句会也调用父类的构造函数吗?
      

  14.   

    如果说实例化子类的时候,也会同时生成父类的对象,
    那所有类在实例化的时候,最高父类Object都会生成一个Object的对象吧,但是Object对象已经在实例化一个类的时候生成了,已经存在了的话,那再实例化其他类时,是不是就不用再生成Object对象,而只是生成一个OBject对象的引用呢?
      

  15.   

    这就是面向对象的多态性之一。在C++中是父类的对象调用子类的方法,在java中等号左边实际上就相当于一个指针,其实是在栈中分配的一个名称,它储存对象的地址,储存拿过对象的地址呢?也就是储存new出来的对象,即等号右边的。只要是new出的东西,一定是在堆里分配的内存
      

  16.   

    SuperA p = new SubB(); 是从右到左执行的。首先分析new SubB(),执行new SubB()是调用子类SubB的默认构造方法,即public SubB(){},事实上子类的
    构造方法是这样的:public SubB(){ 
                         SubA() {};
                       }
    子类构造方法里面父类的构造方法是编译器加上的,不需要自己写出来。所以调用子类构造方法时也会调用父类构造方法,且只调用一次,
    调用完父类构造方法后再执行子类构造方法剩下的代码,这样就在内存中创建了一个子类对象,里面包含了一个父类对象;
    然后用父类类型的引用p去持有这个创建出来的子类对象。通过引用p只能访问子类中从父类中继承的属性和方法,而子类中新增的属性和方法不能
    通过引用p去访问,如果引用p是子类类型的,那么通过p可以访问所有子类中的属性和方法。
      

  17.   

    是父类引用指向子类对象,会产生多态,其实就创建了一个对象,subperB的对象
    父类引用(superA)指向了他。如果你等号两边都是子类类型,则不会产生多态,
    当然,你创建的仍然是一个对象,都是在堆中创建的对象
      

  18.   

    父类引用指向子类对象多态的三要素之一。假设SuperA{void m1(){};void m2(){}} 而SuperB{void m1(){};void m2(){};void m3(){};voidm4(){}},那么SuperA p = new SuperB();这个p对象只能调用方法m1,m2,要想能够调用m3,m4,必须SuperB p1 = (SuperB)p,这样p1才能调用m3,m4
      

  19.   

    当然,SuperB中的m1,m2方法是从SuperA中继承过来的,我直接写了。
      

  20.   

    请问,我是否可以理解成,SuperA p = new SuperB();这句话只是实例化出了一个子类的对象p,而等号左边用了父类的引用来指向这个对象,是在限制这个子类对象只能访问从父类继承来的父类的成员,而它虽然是子类的对象,却不能再访问子类自身的成员啦?并且,等号右边在实例化出子类的对象时,先调用了父类的构造方法来对子类继承过来的父类成员进行初始化,然后调用子类的构造函数来实例化子类自身成员(但是这句中由于子类被父类引用限制了,所以不初始化子类自身成员,子类构造函数只是在内存中分配了对象空间,生成子类对象)?
      

  21.   

    [Quote=引用 34 楼 tojoykorea 的回复:]
    请问,我是否可以理解成,SuperA p = new SuperB();这句话只是实例化出了一个子类的对象p,而等号左边用了父类的引用来指向这个对象,是在限制这个子类对象只能访问从父类继承来的父类的成员,而它虽然是子类的对象,却不能再访问子类自身的成员啦?(可以这样理解,但是要注意对method和field区别对待,调用方法的时候会调用实际对象的类型中定义的方法,这就是多肽。而对于field访问,实际访问到的是从父类中继承下来的field)。并且,等号右边在实例化出子类的对象时,先调用了父类的构造方法来对子类继承过来的父类成员进行初始化,然后调用子类的构造函数来实例化子类自身成员(但是这句中由于子类…
    这里就是父类的引用指向子类对象,new SuperB();就是为子类对象分配空间,调用子类的构造方法。注意对父类的构造方法的调用是通过在子类构造方法中使用super()语句直接调用的。你的理解还是有些问题。
      

  22.   


    说的是下面这个意思吗?子类对象只能调用继承来的父类的field,不能调用自身的field,而子类对象却可以连自身的method也可以调用?为什么method和field会不同呢?
      

  23.   

    把引用和对象区分开就没那么多问题了.
    建议找本基础的书看看,比如Core Java或者The java programming language,尤其是后者,很多概念问题和原理说的比较清楚,毕竟是设计java语言的人写的。
      

  24.   

    List list = new ArrayList();
      

  25.   

    2008年的帖子还有人挖坟,//faint
      

  26.   

    1.创建出的是子类对象。用父类的引用指向一个子类对象。
    2.先执行SuperA p,仅仅是定义一个引用,在内存中占4byte。后执行new SubB(),创建出实例对象,分配相应的内存。最后将p指向了刚才创建的对象内存空间的首地址。
    3.new SubB()时,在创建SubB类时会调用构造方法SubB(),而方法SubB()首先执行的操作时调用父类构造方法。调用一次。
    4.创建对象的过程没什么区别,只是一个是父类引用指向对象,一个是子类引用指向对象。
    这是多态的体现
      

  27.   

    分成两句话好理解一些:
           new SubB();
           Super p;
    相当于于 SubB b = new SubB();
             Super p = b;
      上面的两句话只产生了一个对象b,  而p只是对b对象的一个引用。
      

  28.   

    这就是多态嘛相对而言,父类是比子类更“泛”的类型;子类是比父类更加“精确”的类型比如,“水果”是父类,“苹果”、“桔子”是子类
    所以,我们说一个“桔子”也是一个“水果”,所以水果 变量1 = new 桔子();是很合理的
      

  29.   

     class A {
    A(){
    System.out.println(this);
    }
    }public class B extends A {
    B() {
    System.out.println(this);
    } public static void main(String[] args) {
    A a =new B();
    }
    }你运行上段代码就可以知道答案了 打印的对象都是子类的 也就是说没有生成父类对象