案例分析
源代码一
class Super { private void test () { System.out.println( "super" ); } public void invoke () { test(); } } class Suber extends Super { public void test () { System.out.println( "suber" ); } } // 调用 public class TestClass7 { public static void main (String[] args) { new Suber().invoke(); } }
结果
super
源代码二
class Super { public void test () { System.out.println( "super" ); } public void invoke () { test(); } } class Suber extends Super { public void test () { System.out.println( "suber" ); } } // 调用 public class TestClass7 { public static void main (String[] args) { new Suber().invoke(); } }
结果
suber
分析
对于源代码一和源代码二来说, 仅仅只是Super类的test方法的权限不同, 一个为private, 一个为public, 那么对于源代码一来说, invoke方法是由Suber类实例来调用的, 在编译阶段, 由于invoke方法在Super类中, 那么其对test方法进行查看, 发现在Super类中存在一个private的test方法, 由此认为test方法是非虚方法, 对于非虚方法来说, 字节码中对该方法的调用应该用invokespecial, 并且是能够在加载阶段确定的, 而对于 源代码二中, 对test方法进行查看时, 没有发现非虚方法test, 所以该方法的调用由运行期间来决定, 在运行 时调用test方法, 由于子类Suber重写了test方法, 根据动态分派, 首先应该先查询调用者的实际类型(Suber) 中是否存在test方法, 存在即调用, 所以在invoke方法中调用的是重写的test的方法