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,"测试对象","红色");这句后,内存中有几个对象?属性值分别是什么?
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,"测试对象","红色");这句后,内存中有几个对象?属性值分别是什么?
继承是相对于类而言,不想对于对象而言,类有继承的关系,对象是没有这个说法的。
private会被子类所继承,不仅仅是private,如果子类有与父类同名的属性或者方法,同名的也会被继承,他们只是不能被访问,并不代表他们没有被继承下来。
TestSubPrivate s = new TestSubPrivate(5.6, "测试对象", "红色");
Field ff= Base.class.getDeclaredField("name"); // 这里直接用Base的定义
ff.setAccessible(true); // 强行修改访问权限
System.out.println(ff.get(s)); // 直接获取s中的对应字段值
}
必须,否则你的对象还怎么能正常工作呢?要知道基类的所有方法,基本上都是建立在那些private属性和private方法上开展工作的。之所以private,其实本质上是就是为了保护基类自己的运行环境不被随意调整,所以让你不可见。
1.super方法调用父类构造方法,改变子类实例s的size和name值。
2.s是子类对象。所以改变的是子类对象。
3.不是。
4.一个。值的话,应该不用说了吧
既然子类不能访问父类中private修饰的成员,那么继承过来的private成员有什么用?
我9楼其实说了,我再换个方式解释下。所继承过来的private成员,不是直接供子类使用的。而是供父类所提供方法来使用的。比如你的父类如果是这样:class Base{
private String name;
private double size;
public void setSize(double newSize) {
this.size = newSize;
}
}
那么如果你的子类没有完整继承private的size的话,那么子类的实例(对象)调用setSize方法时,JVM怎么办?所以必须要有基类完整的内容,基本是那些已经被子类重载的函数,也仍然会有。
子类构造函数中用super调用,和不用super,直接把父类构造器的代码:this.size=size;this.name=name;拷过来在运行时有区别吗?
就是说在子类中用super会不会返回到父类里面去执行,还是只是把父类代码继承过来?
至于子类在实例化的时候具体做了哪些工作呢?
其实每个子类对象中都含有一个父类的对象(但这个父类的对象对外不可见就想子类对象的一个属性),而不是继承父类的私有属性!就像下图这样一切就明了了!super方法的调用其实就是初始化内部的父类对象。属性所有权不变,该是谁的就是谁的不会继承!
----------------------------
| 子类对象|---------| |
| | 父类对象| |
| --------- |
-----------------------------
你没法运行,应该说根本没法编译,因为你访问不了父类的size属性(可见度问题),而子类自身又没有定义size属性。最后你所说的:“把父类代码继承过来”这个是不存在的,被继承的不是代码,代码完全可以共享啊。而至于已经实例化的对象,本身也不需要去另外copy一份代码啊,只需要维护对象自己的属性和配套的数据模型就够了。
对于基础性的理论,如果是讨论的话,论坛还有价值,但如果是很多基础性知识都有漏洞的话,建议老老实实买本书看看,这样才能提高你的学习效率。
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);
全部走反射模型,看看打印出来的是啥。
私有属性确实是被继承了,并且也有方式能够获得值——使用反射(我这里不打算讲反射该怎么用,楼主可以自己去学习)。我要指出的是,当通过反射去获得这个私有属性的值得时候,对应的函数是传入这个对象,而不是什么父类对象。
其实继承这个概念,只相对于类而言,并不相对于对象而已,如果你new了某个对象,那么这个对象属于new这个对象的类以及其所有父类的对象,但是对象是只有一个的,只是它包含了当前类与其所有父类的属性。如何去理解这一点,其实是个有意思的事情,这牵扯到java的字节码工程方面的知识,因为java代码是面向对象的代码,但是字节码是过程型的汇编码,因此java得语言环境对于实际执行过程是有很大误导的(因为java代码设计就是希望你往对象的方面去思考)。如果你懂java字节码就能够很清楚的看到,其实构造函数就是一个普通的返回void的名叫"<init>"的方法(一般声明方法不能使用简括号),因此,构造函数不承担实例化对象的职责,它只是初始化对象,那么谁来实例化对象?就是new关键字,虽然在java的语法层new关键字必须与构造函数一起使用,但是如果你接触过jni开发,或者能够阅读字节码煮记符就知道,其实new的操作和构造函数的操作是分开的,而且通过jni或者你使用jdk自带的unsafe类,就可以实例化出不执行构造函数的对象,那么你要如何去自圆其说子类中会有父类的对象?好吧,我们不去管什么字节码,也不知道这些底层做了些什么,就想一个简单的问题,子类中包含所有父类属性与子类中包含一个父类对象,这两种实现都可以实现我们相同的需求,子类对象可以调用父类的属性,你说我去实例化N个父类对象消耗资源还是实例化一个对象去包含所有属性消耗资源?无论是内存还是cpu时钟?你认为jvm的实现者都是傻瓜么?
我的意思不是说子类对象包含了父类对象,没有所谓的对象里面还包含了另一个对象。
只是问当一个子类对象被创建时系统是否隐式地在内存中创建了父类对象,和他的子类对象对应的。请看以下的程序:
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对象?是不是系统在子类对象被创建时创建了该类父类的对象。
//分别占用不同的内存空间?
Object ojb = this;
但无法:
Object ojb = super;子类对象包含了所有基类的成员属性,并作了可见度保护,但确实没有“创建”这个基类。否则的话,如果基类是abstract的话,你让JVM咋玩?
另外,方法与属性其实是有区别的,对象的成员属性是多个的,他会与对象一起存放在堆中,但是方法都是只有一个(至少在一个域中是如此,想要了解域,你要学习类的装载机制、类型管理与jdk安全机制,这个你可以自己去学习),方法都只属于类,虽然很多时候动态看上去都属于某个对象,恰恰相反,是这个对象属于这个方法。因为静态方法与动态方法唯一的一个区别,就是一个不能用this一个能用(当然,调用的指令与jvm方法搜索机制都不同,但是这些不能决定他们的本质,关于这点你可以去查看jvm指令集说明),动态方法只是有第一个默认参数,当前对象this,而静态方法没有这个缺省对象,我只介绍到这里,更深入的,你还是自己去看吧,如果你真的想要理解java底层,你就要完全跳出java的语法对你的影响,因为jvm是C语言开发的,他的字节码执行逻辑是类汇编,用面向对象去理解这些东西,会出现偏差那就是很正常的事情了。。