抽象类不会被实例化那么继承于抽象类的对象中内存有时怎么样的啊.在构造子类对象时子类会调用父类的构造方法,抽象父类不会被实例化,怎么编译时不会出错呢?

解决方案 »

  1.   

    无论你继承什么类,都不会将父类实例化
    父类只是被作为基础的模板使用的,new出来的只是这个子类而已
    调用构造函数只是为了正确地使用这个父类而已
      

  2.   

    我的理解是因为抽象类允许有实现 所以具备了抽象要素的类不能全面实例化
    new AbstractType();
    但是它的部分实现是需要被实例化的
    这就是子类在构造的时候把抽象父类能实例化的部分都实例化了 可继承的部分成为
    自身不可分割的一部分 也符合面向对象的特性
      

  3.   

    这个涉及到java的内存模型。记住,任何一个派生类的实例都包含其超类的一个完整实例。这里说的“完整实例”,是指属性和方法,属性当然是内存中的实际空间,而方法不是指具体指令代码,而是类似于C++中的(虚)函数表的东西。指令代码在另一段内存中。可以想象,一个派生类的实例包裹着其超类的一个实例,层层包裹,最里层是Object的一个实例。如果类的继承层次的某个环节上有抽象类,那这个抽象类也有一个实例在这个包裹中的某一层,这个实例和其他任何一个实例一样,包含属性和方法表。了解了这点,就可以很好地解释为什么不存在“抽象属性”,只存在“抽象方法”了。从这个意义上说,抽象类其实一点都不“抽象”。产生这种疑问的症结在于:抽象类的特殊性被大部分人大大地夸大了。
    换句话说,抽象类远没有大家想象的那么特殊,它和一般“具象类”的实质区别非常小。
      

  4.   

    楼上没看明白我的意思。我的意思,简单概括起来就是说:抽象类和普通类一样,都是要实例化的,只不过它不能通过new 类名()的形式去直接实例化,而只能由其直接派生类的构造方法去调用它的某个构造方法来实例化它。除了可以有抽象方法和不能直接化以外,抽象类没有任何特殊性。个人认为,抽象类的存在意义不大,是Java设计中的一个败笔。
      

  5.   

    无论你继承什么类,都不会将父类实例化 
    父类只是被作为基础的模板使用的,new出来的只是这个子类而已
    调用的是子类的构造方法,并没调用父类的 
    调用构造函数只是为了正确地使用这个父类而已
      

  6.   

    to 12楼:你所引用并同意的那种说法是错的。to 所有人:请仔细看看我在7楼和9楼的回复,如果不同意的话,请好好研究并实际运行一下下面的代码:
    abstract class AbstractBase { private int i;
    public int j; {  // 看仔细哦,这不是构造方法,是实例初始化块,如果我没有实例化,这段怎么执行了呢? i = 20;
    j = 30;
    } public int getI() { return i; }}class Inherited extends AbstractBase { private int i;
    public int j;

    {  // 看仔细哦,这不是构造方法,是实例初始化块
    i = 200;
    j = 300;
    } public void f() {
    System.out.println("i = " + i);   // 我自己有一个i,值是200
    // System.out.println("i = " + super.i); // 我的超类实例中也有一个i,值是20,但是我不能访问
    System.out.println("super.i = " + super.getI()); //这样就可以访问了 System.out.println("j = " + j);   // 我自己有一个j,值是300
    System.out.println("super.j = " + super.j);   // 我的超类实例中也有一个j,值是30,可以访问
    }
    }public class AbstractStudy { public static void main(String[] args) {
    new Inherited().f();
    }}
      

  7.   

    TO F14
    偶的观点是
    比如这样2个类public class a{
      private int i;
      public a(int i){
        this.i = i;
      }
      public void f(){
      }
    }
    public class b extends a{
      private int j;
      public b(int j){
        super(j);
        this.j = j;
      }
      public void g(){
      }
    }那么 ,编译器把它弄成类似这样一个类,当然,实际上还是分开装到不同的class上面去
    public class b extends a{
      private int i;
      private int j;
      private a(int i){
        this.i = i;
      }
      public b(int j){
        a(j);
        this.j = j;
      }
      public void f(){
      }
      public void g(){
      }
    }然后new的时候,就按照这个东西来做一个Instance,所有数据都放进这个Instance里面包括类型信息,这样就算向上转型,所有信息也不会丢失所以只存在这一个Instance而已当然这只是我的推测而已,我没有任何证据可以证明
      

  8.   

    后来用JAVAP看了一下
    发现new跟调用构造函数的方法是一样的:invokespecial   #1; //Method a."<init>":(I)V
    便以为调用构造函数便要分配内存了,但是又想了一下,用this调用会怎么样呢?
    结果都是一样的:invokespecial   #1; //Method a."<init>":(I)V
    所以,我认为调用了构造函数不一定便要创建实例,所以我认为...(见F16)
    如有错误,请指正...C:\java>javap -c b
    Compiled from "test.java"
    class b extends a{
    public b(int);
      Code:
       0:   aload_0
       1:   iload_1
       2:   invokespecial   #1; //Method a."<init>":(I)V
       5:   aload_0
       6:   iload_1
       7:   putfield        #2; //Field j:I
       10:  returnpublic b();
      Code:
       0:   aload_0
       1:   bipush  99
       3:   invokespecial   #3; //Method "<init>":(I)V
       6:   returnpublic b(java.lang.String);
      Code:
       0:   aload_0
       1:   invokespecial   #4; //Method "<init>":()V
       4:   returnpublic void g();
      Code:
       0:   new     #5; //class a
       3:   dup
       4:   bipush  9
       6:   invokespecial   #1; //Method a."<init>":(I)V
       9:   pop
       10:  return}class a{
      private int i;
      public a(int i){
        this.i = i;
      }
      public void f(){
      }
    }
    class b extends a{
      private int j;
      public b(int j){
        super(j);
        this.j = j;
      }
      public b(){
        this(99);
      }
      public b(String s){
        this();
      }
      public void g(){
        new a(9);
      }
    }
      

  9.   

    又查看了一下内存使用情况,发现的确是逐步分配的,构造函数可能会先检测Instance是否存在
    现在我完全同意Dan1980 的观点
      

  10.   

    话说回来,请问一下Dan1980 先生
    调用构造函数时,JVM都做了些什么呢?
    谢谢
      

  11.   

    to zapdos:你的那种理解从实用主义角度来看也是无可厚非的,但和事实的真相还是有出入,呵呵。你的那个例子不具备一般性,请看我在14楼的例子,派生类和基类中同时存在变量i和j,如果按你的理解,派生类的实例中只有一个i和一个j,但实际上,是各有两个。构造函数的调用是建立实例的最后一步工作,当调用到构造函数的时候,实例已经基本上建好了。
    很多人认为构造函数的调用是实例创建的开始,其实是结束。
    所以这时没有多余的工作要做,按构造函数中的代码逐步执行就完了。
      

  12.   

    能不能这样理解创建子类对象的时候,先是子类的引用调用抽象父类的构造方法(隐含的调用super(参数列表)),并没有用new创建父类的实例,即子类中没有创建父类对象。
      

  13.   

    游离初始化块中的代码,比如你所写的
      {  // 看仔细哦,这不是构造方法,是实例初始化块,如果我没有实例化,这段怎么执行了呢?        i = 20;
            j = 30;
        }
    和直接写在所在类(如这里的AbstractBase类)的构造方法中作用是完全相同的,每一次构造方法被调用时都会被执行。
    当使用"new Inherited()"创建子类Inherited对象时,会在Inherited构造方法执行过程中隐含通过"super();"调用其父类AbstractBase的缺省无参构造方法,super方式调用构造方法不会创建AbstractBase类的实例,同时隐含执行了前述的游离初始化块,这里初始化的仍是子类的实例。
      

  14.   

    不错,有待研究。倾向于abstract 可以实例化,不过不包括抽象的方法。包括变量。
      

  15.   

    我觉得面对对象最重要的是抽象.而抽象类真正对应于OOA的过程,应该是于接口所处的地位是相同的.也就是是说纯粹的OO思想中,没有抽象类与借口的区别,更多的是我们甚至从来不提抽象类,就好象我们从来没有他一样,我们只知道接口.
    从OOA开始学习整个OO才是正道!!
      

  16.   

    当然我只是疑问啊...你这样的结构是不能支持动态绑定的,而且不能解释为什么B的对象不能访问i的属性.
    只有C++才是这样的一种伪动态的静态来实现动态绑定...