本以为学过继承,没想到别人随便找到几道题就被干掉了,结合看到的几篇博客,总结如下。
首先是看视频学到的知识点:
继承--------extends
A:子类只能继承父类所有非私有的成员(成员方法和成员变量)
B:子类不能继承父类的构造方法,但是可以通过super(马上讲)关键字去访问父类构造方法。
C:不要为了部分功能而去继承
---- 在子类方法中访问一个变量的查找顺序: (+this,从成员里找。+super,从父类找)
a:在子类方法的局部范围找,有就使用
b:在子类的成员范围找,有就使用
c:在父类的成员范围找,有就使用
d:如果还找不到,就报错。
以上第二点总结出来一个知识点就是:
子类中如果有和父类重名的成员变量,那么子类的成员变量就会把父类的成员变量给屏蔽了,所以访问子类的这个成员变量返回的值应该是子类中所赋予的值。见下例:
class A1 {
int a = 1;
public int getA() {
return a;
}
}
class B1 extends A1 {
int a = 2;
public int getA() {
return a;
}
}
public class Demo1 {
public static void main(String[] args) {
B1 b = new B1();
System.out.println(b.getA());
}
}
此处运行结果为:
2
但是,这句话中应该还有隐含条件,那就是调用成员变量的方式,此处因为成员变量a是public修饰,所以有b.a和b.getA()两种方法。
第一种方法b.a没有需要注意点,遵照子类成员变量屏蔽父类同名变量的原则即可,接下来我要讨论的是第二种方法访问成员变量的情况。
第二种方法有什么问题呢?那就要引出另一个知识点:继承中方法的重写,即子类中把父类的方法重写后,优先调用的是子类中的方法。
对照上一个例子,参看下一个例子:
class A2 {
int a = 1;
public int getA() {
return a;
}
}
class B2 extends A2 {
int a = 2;
// public int getA() {
// return a;
// }
}
public class Demo1 {
public static void main(String[] args) {
B2 b = new B2();
System.out.println(b.getA());
}
}
此处运行结果为:
1
第二个例子中把B2中的getA()注释了,因为B2中没有同名的getA()方法,所以b.getA()中调用的getA()是继承自A2类的,A2类中的getA()调用的是它本身的a(A2.a),所以输出为:1
再看一个例子
class A3 {
int a = 1;
public int getA() {
return a;
}
}
class B3 extends A3 {
public B3() {
// a = 3;
int a = 2;
}
}
public class Demo1 {
public static void main(String[] args) {
B3 b = new B3();
System.out.println(b.getA());
}
}
此处运行结果为:
1
先不忙分析,先看看取消注释后的结果:
3
是不是好像明白了什么?
首先这个例子中B3构造函数的ina a = 2,其实只是干扰项,对结果的a没有影响,可以忽略;
其次取消注释后,子类(B3)既继承了父类(A3)的变量a,同时也继承了父类的getA()方法,所以B3()中的构造函数对a的赋值实际上是对继承自父类的变量a的赋值。由于方法并没有被覆盖,所以b.getA()调用的也是继承自父类A3的方法。输出结果应该是 :3
最后再看一个例子
class A4 {
int a = 1;
public int getA() {
return a;
}
}
class B4 extends A4 {
int a = 2;
public B4() {
a = 3;
}
}
public class Test4 {
public static void main(String[] args) {
B4 b = new B4();
System.out.println(b.getA());
System.out.println(b.a);
}
}
还是先来看结果:
1
3
先说结果:1,还是和第二个例子一样,因为没有覆盖父类的getA()方法,所以调用从A4中继承来的getA()方法,返回的也就是A4中的值1
再看结果:3,此处的3就是子类B4自己的成员变量a的值,首先成员变量来自于int a = 2;其次构造函数中对于a进行了赋值,所以a的值由2变成了3。也就是与第三个例子不同,构造函数所改变的并不是A4中成员变量a的值。
最后总结一下,大概就是以下两点:
1、通过属性值的方法(b.a)直接访问成员变量,返回的首先是子类中的与父类同名的成员变量的值,在没有时,才访问继承自父类的成员变量;
2、通过调用方法访问成员变量( b.getA() ),首先要看子类对象所调用的方法是自身的方法还是继承自父类的方法,前者的返回值类似总结1,即优先返回子类本地的成员变量;后者的返回值通常为父类中的成员变量的值,但子类构造函数如果对父类中的成员变量有所改动,则返回改动后的值。