class Base{
  private String name;
  private double size;
  public Base(double dax,String mz)
 {
  this.name=mz;
  this.size=dax;
 }
}public class Sub extends Base{
 public String color;
 public Sub(double size,String name,String color)
 {
  super(size,name);
  this.color=color;
 }
 
 public static void main(String[] args)
 {
  Sub s=new Sub(5.6,"测试对象","红色");
 }
}
注意到Base中name和size都是private的,子类中不可能继承,那么子类中super(size,name)调用父类构造函数
改变的是哪个对象的什么变量的值呢?是子类的对象还是父类的对象?
是不是每当创建子对象时系统默认创建相应的父对象???
执行了Sub s=new Sub(5.6,"测试对象","红色");这句后,内存中有几个对象?属性值分别是什么?

解决方案 »

  1.   

    我很想知道“private不能被继承”这句话是谁说的,我想和他聊聊
      

  2.   

    首先说明一点,对象只有一个,无论多少层的继承,都只有一个对象。
    继承是相对于类而言,不想对于对象而言,类有继承的关系,对象是没有这个说法的。
    private会被子类所继承,不仅仅是private,如果子类有与父类同名的属性或者方法,同名的也会被继承,他们只是不能被访问,并不代表他们没有被继承下来。
      

  3.   

    这样能否让你如愿?    public static void main(String[] args) throws Exception {
            TestSubPrivate s = new TestSubPrivate(5.6, "测试对象", "红色");
            Field ff= Base.class.getDeclaredField("name"); // 这里直接用Base的定义
            ff.setAccessible(true); // 强行修改访问权限
            System.out.println(ff.get(s)); // 直接获取s中的对应字段值
        }
      

  4.   

    补充:请问子类继承父类的属性和方法,则创建子类对象时不管是private的还是public的是否都在内存中实际存在呢?
      

  5.   


    必须,否则你的对象还怎么能正常工作呢?要知道基类的所有方法,基本上都是建立在那些private属性和private方法上开展工作的。之所以private,其实本质上是就是为了保护基类自己的运行环境不被随意调整,所以让你不可见。
      

  6.   

    java类加载顺序:先父类的static成员变量-》子类的static成员变量-》父类的成员变量-》父类构造-》子类成员变量-》子类构造。
      

  7.   

    子类中不可能继承,这句话是错的。私有成员是不能再其他地方直接访问。子类继承父类的所哟东西。当创建子类对象时,内存中会开辟一个父类的空间(并不是创建一个父类对象,也就是说从始至终只有一个对象),先。所以现在回答楼主问题。
    1.super方法调用父类构造方法,改变子类实例s的size和name值。
    2.s是子类对象。所以改变的是子类对象。
    3.不是。
    4.一个。值的话,应该不用说了吧
      

  8.   

    《疯狂java讲义》第147页有福插图上写的:当Java程序创建某个类的对象时,系统会隐式创建该类的父类对象。我还是糊里糊涂的。
      

  9.   


    既然子类不能访问父类中private修饰的成员,那么继承过来的private成员有什么用?
      

  10.   


    我9楼其实说了,我再换个方式解释下。所继承过来的private成员,不是直接供子类使用的。而是供父类所提供方法来使用的。比如你的父类如果是这样:class Base{
      private String name;
      private double size;
      public void setSize(double newSize) {
        this.size = newSize;
      }
    }
    那么如果你的子类没有完整继承private的size的话,那么子类的实例(对象)调用setSize方法时,JVM怎么办?所以必须要有基类完整的内容,基本是那些已经被子类重载的函数,也仍然会有。
      

  11.   

    老师,感谢多次解答小弟的问题,还想再问个东西:
    子类构造函数中用super调用,和不用super,直接把父类构造器的代码:this.size=size;this.name=name;拷过来在运行时有区别吗?
    就是说在子类中用super会不会返回到父类里面去执行,还是只是把父类代码继承过来?
      

  12.   

    其实楼上的理解都是错误的,基类的私有域是不能被子类继承的--这是正确的!
    至于子类在实例化的时候具体做了哪些工作呢?
    其实每个子类对象中都含有一个父类的对象(但这个父类的对象对外不可见就想子类对象的一个属性),而不是继承父类的私有属性!就像下图这样一切就明了了!super方法的调用其实就是初始化内部的父类对象。属性所有权不变,该是谁的就是谁的不会继承!
                          ----------------------------
                          | 子类对象|---------|      |
                          |         | 父类对象|      |
                          |          ---------       |
                          -----------------------------
      

  13.   

    看你最后一个问题,说明你对类和对象的概念还是比较模糊,4楼其实解答过这个问题。在生成对象的时候,子类和基类所定义的所有属性,就已经是配套这个对象生成好了的,但这里面仍然会有个类似于栈的访问模型。“直接把父类构造器的代码:this.size=size;this.name=name;拷过来在运行时有区别吗?”
    你没法运行,应该说根本没法编译,因为你访问不了父类的size属性(可见度问题),而子类自身又没有定义size属性。最后你所说的:“把父类代码继承过来”这个是不存在的,被继承的不是代码,代码完全可以共享啊。而至于已经实例化的对象,本身也不需要去另外copy一份代码啊,只需要维护对象自己的属性和配套的数据模型就够了。
    对于基础性的理论,如果是讨论的话,论坛还有价值,但如果是很多基础性知识都有漏洞的话,建议老老实实买本书看看,这样才能提高你的学习效率。
      

  14.   

    这样吧,楼主,你再这么玩下:Base类里面定义一个函数:
    public void whoami() {
      System.out.println(this.getClass());
    }然后在TestSubPrivate的main函数中这样写:
    TestSubPrivate s = new TestSubPrivate(5.6, "测试对象", "红色");
    Base base = s;
    Method mm = Base.class.getDeclaredMethod("whoami");
    mm.invoke(base);
    全部走反射模型,看看打印出来的是啥。
      

  15.   

    http://topic.csdn.net/t/20050704/09/4120799.html看看这个帖子上很多高手的解答吧!我觉得很有道理!就像孩子可以给老子要钱(public方法访问父类私有变量)但不可直接拥有一份!
      

  16.   

    Helios_Fly,不要误认子弟,虽然我不知道你是听哪位大牛忽悠了你,但是请你有过研究,拿出证明来再反驳他人的观点。
    私有属性确实是被继承了,并且也有方式能够获得值——使用反射(我这里不打算讲反射该怎么用,楼主可以自己去学习)。我要指出的是,当通过反射去获得这个私有属性的值得时候,对应的函数是传入这个对象,而不是什么父类对象。
    其实继承这个概念,只相对于类而言,并不相对于对象而已,如果你new了某个对象,那么这个对象属于new这个对象的类以及其所有父类的对象,但是对象是只有一个的,只是它包含了当前类与其所有父类的属性。如何去理解这一点,其实是个有意思的事情,这牵扯到java的字节码工程方面的知识,因为java代码是面向对象的代码,但是字节码是过程型的汇编码,因此java得语言环境对于实际执行过程是有很大误导的(因为java代码设计就是希望你往对象的方面去思考)。如果你懂java字节码就能够很清楚的看到,其实构造函数就是一个普通的返回void的名叫"<init>"的方法(一般声明方法不能使用简括号),因此,构造函数不承担实例化对象的职责,它只是初始化对象,那么谁来实例化对象?就是new关键字,虽然在java的语法层new关键字必须与构造函数一起使用,但是如果你接触过jni开发,或者能够阅读字节码煮记符就知道,其实new的操作和构造函数的操作是分开的,而且通过jni或者你使用jdk自带的unsafe类,就可以实例化出不执行构造函数的对象,那么你要如何去自圆其说子类中会有父类的对象?好吧,我们不去管什么字节码,也不知道这些底层做了些什么,就想一个简单的问题,子类中包含所有父类属性与子类中包含一个父类对象,这两种实现都可以实现我们相同的需求,子类对象可以调用父类的属性,你说我去实例化N个父类对象消耗资源还是实例化一个对象去包含所有属性消耗资源?无论是内存还是cpu时钟?你认为jvm的实现者都是傻瓜么?
      

  17.   

    另外说一句,与此对比的,内部类的对象引用了外部类的对象,这点是有据可查的,通过字节码,可以查到内部类引用外部类的那个属性,通过反射的方式,同样可以获得内部类对外部类的那个引用关系,这个问题在《java核心技术》讲述内部类的相关章节有描述,我当时看的是第七版。与这个问题相对的,子类对象的建立时没有父类对象建立的,因为不存在任何指针引用与调用方式。
      

  18.   


    我的意思不是说子类对象包含了父类对象,没有所谓的对象里面还包含了另一个对象。
    只是问当一个子类对象被创建时系统是否隐式地在内存中创建了父类对象,和他的子类对象对应的。请看以下的程序:
    public class Bird{
    public void fly()
    {
     System.out.println("我在天空自由自在的飞翔!");
    }
    }public class Tuoniao extends Bird{
    public  void fly()
    {
     System.out.println("我只能在地上跑。");
    }
        public void callOverridedMethod()
    {
     super.fly();
    }    public static void main(String[] args)
    {
     Tuoniao t=new Tuoniao();
     t.fly();
     t.callOverridedMethod();
     
    }}
    //Bird类中定义的fly方法是一个实例方法,需要通过bird对象调用,
    //而callOverrideMethod方法通过super就可以调用这个方法,可见super引用了一个Bird对象,
    //但我没有显式创建Bird对象,哪来的Bird对象?是不是系统在子类对象被创建时创建了该类父类的对象。
    //分别占用不同的内存空间?
      

  19.   

    只能说:猛一看貌似有道理,但可惜super是编译才有用的,是用来指导编译器的。你可以:
    Object ojb = this;
    但无法:
    Object ojb = super;子类对象包含了所有基类的成员属性,并作了可见度保护,但确实没有“创建”这个基类。否则的话,如果基类是abstract的话,你让JVM咋玩?
      

  20.   

    从一开始,Java的语法结构就会把人往一个错误的方向去引领(或许这不是一种错误,因为Java本身是希望程序员去这么思考与应用,但是它是与实际执行是背离的),super在语法层次,看上去就像父类对象的指针,但是事实却不是,在构造函数第一句的super指的是一个父类的构造方法,即使你不加super,那么虚拟机会自动添加super()在任何构造方法的第一句,也就是说父类构造方法一定会被执行。而普通方法中的super.xxx中的super也不是父类的对象,而是一个引用父类类型的一个指针,其实无论super还是this,把它理解为指向对象其实是并不太合适的。更好的理解应该是指向当前类型,因为无论怎么样,对象只有一个。
    另外,方法与属性其实是有区别的,对象的成员属性是多个的,他会与对象一起存放在堆中,但是方法都是只有一个(至少在一个域中是如此,想要了解域,你要学习类的装载机制、类型管理与jdk安全机制,这个你可以自己去学习),方法都只属于类,虽然很多时候动态看上去都属于某个对象,恰恰相反,是这个对象属于这个方法。因为静态方法与动态方法唯一的一个区别,就是一个不能用this一个能用(当然,调用的指令与jvm方法搜索机制都不同,但是这些不能决定他们的本质,关于这点你可以去查看jvm指令集说明),动态方法只是有第一个默认参数,当前对象this,而静态方法没有这个缺省对象,我只介绍到这里,更深入的,你还是自己去看吧,如果你真的想要理解java底层,你就要完全跳出java的语法对你的影响,因为jvm是C语言开发的,他的字节码执行逻辑是类汇编,用面向对象去理解这些东西,会出现偏差那就是很正常的事情了。。
      

  21.   

    父类中的私有成员被继承下来了,只是没有访问的权限。super 引用当前对象的父类 注意是引用