java解惑中谜题70;关于private不能被覆写的疑问(88分)

jiqikewang 2011-12-14 02:49:44
先上代码:打印出什么?
package hack;
import click.CodeTalk;
public class TypeIt {
private static class ClickIt extends CodeTalk {
void printMessage() {
System.out.println("Hack");
}
}

public static void main(String[ ] args) {
ClickIt clickit = new ClickIt();
clickit.doIt();
}
}

package click;
public class CodeTalk {
public void doIt() {
printMessage();
}

void printMessage() {
System.out.println("Click");
}
}


打印结果是:Click

很显然,对于private类型的方法,子类里面不能重写;但是这里是缺省的方法,子类里面也不能。
谁能解释下?
...全文
285 13 打赏 收藏 转发到动态 举报
写回复
用AI写文章
13 条回复
切换为时间正序
请发表友善的回复…
发表回复
dracularking 2011-12-15
  • 打赏
  • 举报
回复
8.4.8.1 Overriding (by Instance Methods)
An instance method m1 declared in a class C overrides another instance method, m2, declared in class A iff all of the following are true:

C is a subclass of A.

The signature of m1 is a subsignature (§8.4.2) of the signature of m2.

Either
m2 is public, protected or declared with default access in the same package as C, or
m1 overrides a method m3, m3 distinct from m1, m3 distinct from m2, such that m3 overrides m2. (间接覆盖)

Moreover, if m1 is not abstract, then m1 is said to implement any and all declarations of abstract methods that it overrides.

dracularking 2011-12-14
  • 打赏
  • 举报
回复
A package-private method cannot be directly overridden by a method in a different package.
总结就是package-private方法不能直接被另外一个包中的方法覆盖
chosen0ne 2011-12-14
  • 打赏
  • 举报
回复
这个问题,从JVM字节码来解答会一目了然。
首先,先清楚一个概念,方法绑定:
1. 静态绑定,就是在编译时就能确定给定的方法签名对应的方法体。在Java中,私有方法,构造器,父类的方法就是静态绑定,还包括那些编译时就可以确定方法体的方法。
2. 动态绑定,就是在运行时才确定一个方法签名对应的方法体。用于实现多态,Java中大部分方法都是动态绑定的。

在JVM上,静态绑定使用invokespecial指令,动态绑定使用invokvirtual。invokevirtual会根据方法签名从当前对象向他的父类进行搜索,直到找到一个方法为止。

先看一下CodeTalk和TypeIt在不同包的情况,CodeTalk.class反编译后的结果:

# 只截取了doIt方法
public void doIt();
Code:
0: aload_0
1: invokespecial #2; //Method printMessage:()V
4: return

LineNumberTable:
line 4: 0
line 5: 4


可以看到在doIt方法的字节码中,调用printMessage方法使用的指令是invokespecial:
1: invokespecial #2; //Method printMessage:()V
也就是说,doIt方法是静态绑定,并且绑定了CodeTalk.printMessage方法。所以这个方法会被调用,打印Click

在看ColdTalk和TypeIt在同一包的情况,CodeTalk.class反编译后的结果:

# 只截取了doIt方法
public void doIt();
Code:
0: aload_0
1: invokevirtual #2; //Method printMessage:()V
4: return

LineNumberTable:
line 16: 0
line 17: 4

可以看到printMessage方法调用使用的是invokevirtual,也就是方法是动态绑定的:
1: invokevirtual #2; //Method printMessage:()V
在调用clickIt.doIt()方法时,JVM会从ClickIt类开始向CodeTalk类搜索printMessage:()V这个方法,而ClickIt中定义了这个方法,所以直接返回。最后调用的是ClickIt.printMessage方法,打印Hack。

之所以为什么CodeTalk和TypeIt两个类在不在相同包中,会导致printMessage方法调用指令不一样,这是由javac编译器保证的。
XC2010_K 2011-12-14
  • 打赏
  • 举报
回复
不信你可以把父类中的printMessage()的访问权限设为public,结果就一定是Hack了。
XC2010_K 2011-12-14
  • 打赏
  • 举报
回复
在作为外包的类中,它含有的方法的访问权限必须是public或protected。
你在ClickIt中定义的printMessage只属于这个类自己,而不是父类中的printMessage。
ClickIt clickit = new ClickIt();
clickit.doIt();
这句是调用了父类中的doIt(),因为父类中的doIt()的访问权限是public,所以子类继承到了,doIt()方法找的是它本类中的printMessage(),所以输出的结果是Click.
yangleibj 2011-12-14
  • 打赏
  • 举报
回复
你说的不是Private,而是package,如果在一个包,应该可以。
wowwxg128 2011-12-14
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 caofaping 的回复:]
Java code


public class TypeIt {
private static class ClickIt extends CodeTalk {
void printMessage() {
System.out.println("Hack");
}
}

public static……
[/Quote]
4楼的朋友 应该是放在一个包里的。所以,是打印的子类的方法。
楼主的是在两个包里的, 打印的还是 父类里的那个方法的。
wowwxg128 2011-12-14
  • 打赏
  • 举报
回复
我也来凑个热闹!
--
关于访问权限是:public > protected > 默认 > private
·默认:就是什么都不写,它的真正名字是,“包访问权限”,即在同一个包内访问权限为public ,在包外就是private的了。
·protected:就是“继承访问权限”,它是要超越“包”的。包内,同上,public 。 “包”外分情况,如果有继承,也就相当于是 public 的。没有继承,就是 private的。
---
你上面的例子是在两个包的文件,虽然有继承,还是不能重写那个 默认 权限的方法的。
zhoujiaolongde 2011-12-14
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 caofaping 的回复:]

Java code

public class TypeIt {
private static class ClickIt extends CodeTalk {
void printMessage() {
System.out.println("Hack");
}
}

public static void mai……
[/Quote]
在不同的包里试试
caofaping 2011-12-14
  • 打赏
  • 举报
回复

public class TypeIt {
private static class ClickIt extends CodeTalk {
void printMessage() {
System.out.println("Hack");
}
}

public static void main(String[] args) {
ClickIt clickit = new ClickIt();
clickit.doIt();
}
}

class CodeTalk {
public void doIt() {
printMessage();
}

void printMessage() {
System.out.println("Click");
}
}


结果是:Hack JDK1.5

还好我想不通就运行看下结果。

求解!!!!
zhoujiaolongde 2011-12-14
  • 打赏
  • 举报
回复
补充一点 子类和父类在同一个包下面 那么在子类里面也是可以重写缺省的方法的 如果不在一个包下面的话只能重写protected以及public了
jiqikewang 2011-12-14
  • 打赏
  • 举报
回复
似乎是这个情况,多谢!!![Quote=引用 1 楼 zhoujiaolongde 的回复:]

java 中 四中访问权限 http://blog.csdn.net/fuuckwtu/article/details/6504161

重写就意味着可以使用super();这个方法 也就意味着可以访问父类的方法 而子类的访问权限 只到达protected这一个层次因此只有protected以及权限大于他的public可以被继承
[/Quote]
zhoujiaolongde 2011-12-14
  • 打赏
  • 举报
回复
java 中 四中访问权限 http://blog.csdn.net/fuuckwtu/article/details/6504161

重写就意味着可以使用super();这个方法 也就意味着可以访问父类的方法 而子类的访问权限 只到达protected这一个层次因此只有protected以及权限大于他的public可以被继承

62,616

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧