在James Gosling的《Java程序设计语言(第4版)》(《The Java Programming Language(Fourth Edition)》的第18章——包的访问里关于可访问性和覆盖方法的讨论中,作者对于类中具有包访问权限的方法在继承条件下有这样的观点:
有如下三个类:
/**第一个类的代码*/
package p1;
public abstract class AbstractBase {
private void pri(){System.out.println("AbstractBase .private()");}
void pac(){System.out.println("AbstractBase .package()");}
protected void pro(){System.out.println("AbstractBase .protected()");}
public void pub(){System.out.println("AbstractBase .public()");}
public final void show(){
pri();
pac();
pro();
pub();
}
}
/**第二个类的代码*/
package p2;
import p1.AbstractBase ;
public class Concrete1 extends AbstractBase {
public void pri(){System.out.println("Concrete1.private()");}
public void pac(){System.out.println("Concrete1.package()");}
pubilc void pro(){System.out.println("Concrete1.protected()");}
public void pub(){System.out.println("Concrete1.public()");}
}
/**第三个类的代码*/
package p1;
import p2.Concrete1;
public class Concrete2 extends Concrete1 {
public void pri(){System.out.println("Concrete2.private()");}
public void pac(){System.out.println("Concrete2.package()");}
public void pro(){System.out.println("Concrete2.protected()");}
public void pub(){System.out.println("Concrete2.public()");}
}
作者认为由于Concrete1与AbstractBase不在同一个包中,AbstractBase类中具有包访问权限的pac方法不能被Concrete1访问和继承,因此Concrete1类中的pac方法,也不算是覆盖AbstractBase类中的pac方法;由于Concrete2与AbstractBase在同一个包中,Concrete2可以访问继承到AbstractBase的pac方法,因此Concrete2的pac方法既覆盖了Concrete1的pac方法也覆盖了AbstractBase的pac方法。而经验证,在Concrete2的main方法中通过new Concrete2的对象调用AbstractBase类的final方法show的输出结果是:
AbstractBase.private()
Concrete2.package()
Concrete2.protected()
Concrete2.public()
这也表明Concrete2的pac方法的确覆盖了AbstractBase的pac方法。
然后,我对第二个和第三个类进行了如下的改造:
/**第二个类修改后的代码*/
package p2;
import p1.AbstractBase ;
public class Concrete1 extends AbstractBase {
public void pri(){System.out.println("Concrete1.private()");}
pubilc void pro(){System.out.println("Concrete1.protected()");}
public void pub(){System.out.println("Concrete1.public()");}
}
/**第三个类修改后的代码*/
package p1;
import p2.Concrete1;
public class Concrete2 extends Concrete1 {
public void pri(){System.out.println("Concrete2.private()");}
public void pro(){System.out.println("Concrete2.protected()");}
public void pub(){System.out.println("Concrete2.public()");}
public void show2(){
pri();
pac();//该行编译器报错:类型AbstractBase中的方法pac()不可视。
pro();
pub();
}
}
如果说Concrete2能够访问继承到AbstractBase中具有包访问权限的方法pac,那么在我进行了以上修改后编译器不应该报错说那个方法不可视。如果说Concrete2不能够访问继承到AbstractBase的pac方法,那么就说明在修改前的代码仅仅是对Concrete1中的pac方法进行的覆盖,而Concrete1中的pac方法又不是对AbstractBase中的pac方法的覆盖。那么修改前的输出应该是:
AbstractBase.private()
AbstractBase.package()
Concrete2.protected()
Concrete2.public()
而不是:
AbstractBase.private()
Concrete2.package()
Concrete2.protected()
Concrete2.public()
我的问题是,在以上三个类的继承关系下,Concrete2是否能真正继承并可访问AbstractBase中具有包访问权限的方法pac,修改前Concrete2是否真的也覆盖了AbstractBase的pac方法?
[b]问题补充:[/b]
首先感谢lovewhzlq,蔡华江两位朋友的及时作答。
但是,对于蔡华江朋友的作答,我仍有个疑问。在第一个例子中,我的确定义的是Concrete2对象。但Concrete2对象本身没有show方法,它是通过调用其隔代超类AbstractBase中的final方法show来调用pac方法的。如果按蔡华江朋友所说的,“。。。调出来的就是Concrete2的pac方法”。那在Concrete2访问不到从而就覆盖不了AbstractBase中的pac方法的情况下,AbstractBase中的show方法为什么调用的是Concrete2中的pac方法而不是本类自身的pac方法呢(请注意AbstractBase类本身是有pac方法的)?就如同,Concrete2无法访问并覆盖AbstractBase中的pri方法。但在同样的调用执行中,show方法却明显调用的是AbstractBase类中的pri方法(同样请注意Concrete2类本身也是有pri方法的);如果Concrete2能访问到并继承了AbstractBase中的pac方法,那在第二个例子中,编译器就不该报错。所以,我关心的重点是:Concrete2中的pac方法与AbstractBase中的pac方法是否构成覆盖关系,而Concrete1仅仅是构成这个问题的一个桥梁和手段。因此,lovewhzlq朋友的回答对于问题理解的偏差也许更大一些,毕竟super只能引用到Concrete1而与AbstractBase无关。
:) 同时欢迎更多的朋友参与我这个小问题的讨论,谢谢