Java语言中方法重写的本质

Java语言中方法重写的本质

    找到操作数栈顶的第一个元素所执行的对象的实际类型,记作 C。 如果在类型C中找到与常量中的描述符合简单名称都相符的方法,则进行访问权限校验。 如果通过则返回这个方法的直接引用,查找过程结束 如果不通过,则返回java.lang.IllegalAccessError 异常 否则,按照继承关系从下往上依次对C的各个父类进行第2步的搜索和验证过程。 如果始终没有找到合适的方法,则抛出java.lang.AbstractMethodError异常。
上面这个过程也被称为动态分派:根据对象的实际类型,来确认调用的方法版本,子类有重写方法,则调用子类的重写方法,否则去父类找对应的方法,这就是 invokevirtual 指令的执行逻辑,这是 java 里面对于方法重写的本质。

IllegalAccessError介绍

    程序试图访问或修改一个属性或调用一个方法,这个属性或方法,你没有权限访问。一般的,这个会引起编译器异常。这个错误如果发生在运行时,就说明一个类发生了不兼容的改变。 比如,你把应该有的jar包放从工程中拿走了,或者Maven中存在jar包冲突

举例

public class FieldHasNoPolymorphic {
          
   
    static class Father{
          
   
        public int money = 1;
        public Father(){
          
   
            money = 2;
            showMeTheMoney();
        }
        public void showMeTheMoney(){
          
   
            System.out.println("I am Father, i have $" + money);
        }
    }
    static class Son extends Father{
          
   
        public int money = 3;
        public Son(){
          
   
            money = 4;
            showMeTheMoney();//第二行的结果
        }
        public void showMeTheMoney(){
          
   
            System.out.println("I am Son, i have $" + money);
        }
    }
    public static void main(String[] args){
          
   
        Father gay = new Son();
        System.out.println("This gay has $" + gay.money);
    }

}

上面代码的输出结果如下:

第一行结果的原因

    首先进入FieldHasNoPolymorphic 的init 函数,然后开始运行它的main函数。main函数的字节码如下: 接下来进入 Son 的init()
    进入 father 的 init(): 然后father里面有 invokevirtual,根据动态分配的原则,首先会选择调用实际类型的重写,方法。因此这里虽然 father已经给money赋值了,但是任然会调用 son 的showmoney 方法。 由于此时son里面的money还没有被复制,因此输出了 0 (这个0应该是在编译过程中的JVM类加载阶段为money付的默认值 )。

第二行结果

正常执行下来,son中的showmoney

第三行结果

下图为 main 函数的字节码 可以看到最后main函数执行的是 father中的money: 成员变量,静态方法看左边;

总结

访问成员变量的两种方式下的不同规则

    直接访问时,查看父类: 直接通过对象名称访问成员变量:看等号左边是哪个对象(子类或父类),则优先用哪个对象的成员变量,没有则向上找。 成员方法中查找当前域: 间接通过成员方法访问成员变量:看该方法属于哪个对象(子类或父类),则优先用哪个对象的方法,没有则向上找。

访问成员方法的规则: 看new的是哪个对象(子类或父类),则优先用哪个对象的成员方法,没有则向上找。

注意:

(1)成员变量指的是父类或子类中的属性,成员方法指的是父类或子类中的方法,如下图:

(2)只有成员方法才能覆盖重写,成员变量不能覆盖重写。

经验分享 程序员 微信小程序 职场和发展