今天看了几篇继承的文章,把继承时的属性问题搞明白了,
package test;
class Parent {
private int a=11;
public int getA() {
return a;
}
}
class Son extends Parent {
private int a=12;
}
public class test6 {
public static void main(String[] args) {
Parent haha=new Son();
System.out.println(haha.getA());
}
}
在内存中其实是存着两个a的,一个是Parent的a,一个是Son的a,由于调用的是父类的getA方法,所以改父类的a,对于父类来说,他根本不知道子类有哪些变量,当然也不知道子类里有个同名的a了,于是它去把父类的a显示出来了。
现在改成:
package test;
class Parent {
private int a=11;
public int getA() {
return a;
}
}
class Son extends Parent {
private int a=12;
public int getA() {
return a;
}
}
public class test6 {
public static void main(String[] args) {
Parent haha=new Son();
System.out.println(haha.getA());
}
}
这时候调用的是子类的方法getA,子类方法优先去找子类的变量a,并显示出来。
再看下面的:
package test;
class ParentClass {
public int i = 10;
public ParentClass(){
i=7;
System.out.println("hahahhaha");
}
}
public class test7 extends ParentClass {
public int i = 30;
public test7(){
//super();
// i=7;
}
public static void main(String[] args) {
ParentClass parentClass = new test7();
test7 subClass = new test7();
System.out.println(parentClass.i + subClass.i);
}
}
答案是37,首先用parentClass访问到的i是父类的i,用subClass访问到的是子类的i,当new出一个子类对象时,调用其构造函数,其构造函数优先调用无参数的父类构造函数,父类的构造函数更改父类的i为7,最后相加自然是37。如果在子类的构造函数中多加一句i=7,这会使得子类的i变为7,所以答案就变为14了。
综上,用方法访问变量时,优先访问本类中的变量,找不到就在其父类中寻找,所以调用父类的构造函数时就访问父类的变量,回到子类的构造函数后就访问子类的变量。当用引用名.变量来访问变量时,会根据引用名的类型来决定访问父类的变量还是访问子类的变量。
JAVA的继承在内存中就是这么麻烦!!!new出一个子类还要维护好它的父类的变量,多继承几次,维护的东西就更多了。
所以采用组合的方式会比继承更节省内存的空间。
class A{
B b;
}
当A想用B的某些方法时只要用一个引用b指向B的对象即可,而不是像在继承时每new一个对象就要维护一个父类的版本。
组合的好处更体现在:
比如原来想用A继承B,现在改用A直接拥有B,这样B能做的任何事情A都能做,如果B是一个接口类型,那么所有实现了B接口的类的方法都能被A所利用,而当A继承B的时候还需要被B所限制,比如b里面规定的protected方法你不能重写成public的,A类必须遵从B类制定的制度。现在不同了,A翻身做主人了,我为什么要听命于你B,仅仅因为我跟你有同样的性质?因为“我是你”所以我被你限制了,现在我不再是你了,我只想做我自己,你管不着我了,我想节省代码的时候我只要把你作为我的属性就行了。原来我听命于你,现在你为我所用。原来我继承你不就是想利用你原有的一些方法么?为什么还要我维护你的属性呢?现在你为我所用,我直接拿你的方法来用就行了。这样,A的自主性更高了,它现在谁也不是,它想干嘛就能干嘛了。