日期:2014-05-20  浏览次数:20768 次

java解惑中谜题70;关于private不能被覆写的疑问(88分)
先上代码:打印出什么?
Java code
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类型的方法,子类里面不能重写;但是这里是缺省的方法,子类里面也不能。
谁能解释下?

------解决方案--------------------
java 中 四中访问权限 http://blog.csdn.net/fuuckwtu/article/details/6504161

重写就意味着可以使用super();这个方法 也就意味着可以访问父类的方法 而子类的访问权限 只到达protected这一个层次因此只有protected以及权限大于他的public可以被继承
------解决方案--------------------
补充一点 子类和父类在同一个包下面 那么在子类里面也是可以重写缺省的方法的 如果不在一个包下面的话只能重写protected以及public了
------解决方案--------------------
我也来凑个热闹!
--
关于访问权限是:public > protected > 默认 > private 
·默认:就是什么都不写,它的真正名字是,“包访问权限”,即在同一个包内访问权限为public ,在包外就是private的了。
·protected:就是“继承访问权限”,它是要超越“包”的。包内,同上,public 。 “包”外分情况,如果有继承,也就相当于是 public 的。没有继承,就是 private的。
---
你上面的例子是在两个包的文件,虽然有继承,还是不能重写那个 默认 权限的方法的。
------解决方案--------------------
在作为外包的类中,它含有的方法的访问权限必须是public或protected。
你在ClickIt中定义的printMessage只属于这个类自己,而不是父类中的printMessage。
ClickIt clickit = new ClickIt();
clickit.doIt();
这句是调用了父类中的doIt(),因为父类中的doIt()的访问权限是public,所以子类继承到了,doIt()方法找的是它本类中的printMessage(),所以输出的结果是Click.
------解决方案--------------------
不信你可以把父类中的printMessage()的访问权限设为public,结果就一定是Hack了。
------解决方案--------------------
这个问题,从JVM字节码来解答会一目了然。
首先,先清楚一个概念,方法绑定:
1. 静态绑定,就是在编译时就能确定给定的方法签名对应的方法体。在Java中,私有方法,构造器,父类的方法就是静态绑定,还包括那些编译时就可以确定方法体的方法。
2. 动态绑定,就是在运行时才确定一个方法签名对应的方法体。用于实现多态,Java中大部分方法都是动态绑定的。

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

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

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

  LineNumberTable:
   line 4: 0
   line 5: 4

------解决方案--------------------
A package-private method cannot be directly overridden by a method in a different package.
总结就是package-private方法不能直接被另外一个包中的方法覆盖
------解决方案--------------------
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.