Java继承问题以及子类转换为父类时调用方法及属性的情况
1.方法的继承
子类可以继承父类的非private方法。
class parent{
public void pnp() {
System.out.println("Parent");
}
}
class child extends parent{
}
child c = new child();
c.pnp();
输出结果为Parent.
子类可以重写父类的非private方法。
class parent{
public void pnp() {
System.out.println("Parent");
}
}
class child extends parent{
@Override
public void pnp() {
System.out.println("Child");
}
}
这时,输出结果为Child
对于父类的private方法,子类是不可见的,尝试调用父类的private方法会导致静态检查直接报错。
当然,子类中也可以添加自己独特的新方法。如果子类中写了一个和父类某个private方法一样的方法,这不能算重写,应该也算添加新方法。
2.属性的继承
属性的继承和方法的继承类似,子类可以继承父类的非private属性。父子类定义如下:
class parent{
int np = 0;
}
class child extends parent{
}
子类child可以访问np属性,在main中进行测试,输出结果为0.
child ch = new child();
System.out.println(ch.np);
当然,类似于方法的重写,子类也可以覆盖掉父类的属性。
class parent{
int np = 0;
}
class child extends parent{
int np = 1;
}
测试代码和上面一样,输出结果为1.
当子类试图访问父类的private属性时,静态检查会直接报错。
子类中也可以添加自己独特的新属性。
3.方法与属性混合的情况
如果方法是从父类继承的,那么方法中使用到的属性都是父类的属性。
class parent{
int np = 0;
public void pnp() {
System.out.println(np);
}
}
class child extends parent{
int np = 1;
}
child ch = new child();
ch.pnp();
在main中测试,输出结果是0.即使子类中已经覆盖了属性np,但是方法的行为仍然和父类一致,这时就不能简单地看代码的逻辑了。如果子类想按照代码的逻辑实现功能的话就只能重写,而重写的代码和之前一模一样。
class parent{
int np = 0;
public void pnp() {
System.out.println(np);
}
}
class child extends parent{
int np = 1;
@Override
public void pnp() {
System.out.println(np);
}
}
这时测试输出结果为1.
然而对于方法内部再次调用方法的情况,却正好相反。如果从父类继承来的方法A调用了方法B,并且子类重写了方法B,当子类调用方法A时,方法A内部会调用被重写的方法B.
class parent{
public void A() {
B();
}
public void B() {
System.out.println("Origin");
}
}
class child extends parent{
public void B() {
System.out.println("Override");
}
}
子类调用A()时会输出Override。
4.子类转换为父类时,调用方法及属性的情况
显然的是,当子类转换为父类后,只能调用父类中存在的方法、访问父类中存在的属性。
当访问属性时,属性的值是父类中的值。
class parent{
int np = 0;
}
class child extends parent{
int np = 1;
}
parent c = new child();
System.out.println(c.np);
输出结果为0.
而调用的方法应该是子类中的方法。
如果方法被重写,调用的方法就是子类中被重写的方法。
class parent{
public void A() {
System.out.println("Origin");
}
}
class child extends parent{
@Override
public void A() {
System.out.println("Override");
}
}
parent c = new child();
c.A();
输出结果为Override。
如果方法没有被重写,调用的方法就是父类中的方法。
class parent{
public void A() {
System.out.println("Origin");
}
}
class child extends parent{
}
parent c = new child();
c.A();
输出结果为Origin。
如果调用的方法中访问了某个属性或者又调用了其他方法时,会遵循3中给出的分析。
简单总结一下
对于属性的访问,在运行前就会确定,因此只看当前的类型,当前的类型是什么就访问这个类型中定义的属性;而对方法的调用在运行时才会确定,要看原本的类型(即new的时候的类型),按照这个类型调用相应方法。而方法内部如果访问了属性,这个属性是定义该方法的那个类型中的属性;方法内部如果调用了其他方法,被调用的方法仍然是这个类型中的方法,当然,也存在嵌套的情况。