重载和重写的编码区别及JVM编译区别

一、在代码层次重载和重写的区别如下:

重载:

        1、重载的方法间方法名相同,参数的个数及类型不相同,参数及其类型表不相同即可(参数类型的顺序不同,参数类型个数及参数个数相同亦可);

        2、不能通过访问权限、返回值及抛出异常进行重载;

        3、方法的异常类型及数目不会对重载造成影响;

重写:

        1、存在于子类中,是对父类方法的覆盖;

        2、重写的方法,方法名、参数表个数、类型及顺序必须与父类被重写方法完全一样;

        3、重写方法的修饰符一定要大于被重写方法的修饰符:public>protected>default (private 方法无法被子类获取,不构成重写);

        4、重写方法的返回值必须与被重写方法一致;

        5、重写方法不能比被重写方法的抛出检查范围广泛的检查异常,例如被重写方法的抛出异常为:IndexOutOfBoundsException,重写方法的异常不能是:Exception;

        6、静态方法不能被重写,如果子类存在于父类完全相同的静态方法,那么会将父类的此方法隐藏,具体调用那个方法,要看声明;

        7、重写方法增加注解:@Override 后会自动做如上的重写检查


引用及参考:

http://blog.csdn.net/ycb1689/article/details/17163273;(静态方法重写的解析很到位)

http://www.iteye.com/problems/99162;(不完整,参考了此文回答的重写异常部分)

http://blog.csdn.net/baggio7095586/article/details/6149261(存在错误,代码层次的区别基于此在验证后得出的结论。)


二、JVM编译基础上的区别:

重载:

        1、JVM中对此方法调用的解析方法为静态分派:使用的是invokespecial;

重写:

        1、JVM对重写的方法的解析为动态分派:使用的是invokevirtual;体现效果为,当父类方法被重写后,无论声明和初始化的是子类还是父类,最终处理的都是重写的方法;


说明如下:

1、方法调用的解析
        在Class文件中,方法调用是常量池中的一个符号引用,在加载的解析期或者运行时才能确定直接引用。
        下面两种指令是在解析期就可以确定直接引用,调用的对应方法也叫作非虚方法。
a、  invokestatic 主要用于调用静态方法
b、  invokespecial 主要用于调用私有方法,构造器,父类方法。

        下面两种是在运行时才能确定直接引用的,但是除了final方法,final方法也可以在解析期确定方法的调用版本。
a、  invokevirtual 虚方法,不确定调用那一个实现类
b、  invokeinterface 接口方法,运行时才能确定实现接口的对象。

2、动态分派
        先回顾一下静态和动态分派的概念。Java中,所有以静态类型来定位方法执行版本的分派动作,都称为静态分派。其实也就是重载(Overload)就是一种典型的静态分派,在编译期就可以知道方法调用的实际版本。相对得,动态分派是需要在运行期才能确定方法的版本,也就是直接引用,一种典型应用就是重写(OverWrite)。在调用invokevirtual指令时,把常量池中的类方法符号引用解析到直接引用的过程就是重写的过程,运行期根据实际类型确定方法的执行版本。

3、重写JVM解析图:

     这个是类被虚拟机加载进方法区之后,在方法区里面的布局。

         如果我们像上面那样,用一个基类引用指向子类对象,那么,这个引用所绑定的类还是子类。只不过它所能访问的虚方法表与一般子类对象不同。上面黄色的部分才是父类这个引用所能访问的vtable的范围(关于vtable的生成有时间在总结),而普通的子类引用可以访问整个子类的vtable。


引用及参考:

http://yunshen0909.iteye.com/blog/2231374;(此文通过对字节码的解读,清楚的划分了重载是静态分派,重写是动态分派)

http://blog.csdn.net/qc_liu/article/details/42584099;(清晰的解析了重写的JVM实现逻辑)



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
// 对overload测试的文件:OverloadTest.java public class OverloadTest { // 下面几个方法用来验证可以通过定义不同的参数类型和参数的数目进行方法重载。 public void fun(){ System.out.println("method fun in OverloadTest, no parameter"); } public void fun(float f) { System.out.println("method fun in OverloadTest, parameter type: float"); } public void fun(int i){ System.out.println("method fun in OverloadTest, parameter type: int"); } public void fun(int i1, int i2) { System.out.println("method fun in OverloadTest, parameter type: int, int"); } // 下面的两个方法用来验证可以通过定义不同的参数顺序进行方法重载。 // 需要注意:这里的参数肯定不是相同的类型,否则的顺序的先后就毫无意义。 public void fun1(int i, float f) { System.out.println("method fun1 in OverloadTest, sequence of parameters is: int, float"); } public void fun1(float f, int i) { System.out.println("method fun1 in OverloadTest, sequence of parameters is: float, int"); } // 下面的两个方法用来验证方法抛出的异常对于重载的影响. // 无论是异常的类型还是异常的个数都不会对重载造成任何的影响。 public void fun2() throws TestException { System.out.println("fun2 in OverloadTest, exception: TestException"); } public void fun2(int i) throws TestException, TestException1 { System.out.println("fun2 in OverloadTest, exception: TestException, TestException1"); } public void fun2(float f) throws Exception { System.out.println("fun2 in OverloadTest, exception: Exception"); } // 不能通过抛出的异常类型来重载fun方法。 //public void fun(int i) throws Exception { // System.out.println("method fun in OverloadTest, parameter type: int, exception: Exception"); //} // ? 不能通过返回值重载fun方法。 //public boolean fun(int i) throws Exception { // System.out.println("method fun in OverloadTest, parameter type: int, exception: Exception, return: boolean"); // return true; //} private void fun3() { } // 不能通过不同的访问权限进行重载 public void fun3() { } public static void main(String[] args) { // 这里只是定义了OverloadTest的实例,所以test不会调用 // OverloadTest1中的方法。 OverloadTest test = new OverloadTest1(); // 这里定义了OverloadTest1的实例,因为OverloadTest1是OverloadTest // 的子类,所以test1会调用OverloadTest中的方法。 OverloadTest1 test1 = new OverloadTest1(); try { int i = 1, j = 2, m = 3; // 这里不会调用OverloadTest1的fun方法 // test.fun(i, m, j); test1.fun(i, j, m); test1.fun(); // 这个调用不会执行,因为fun3()在OverloadTest中访问权限是priavte //test1.fun3(); test1.fun3(i); } catch(Exception e) { } } } class OverloadTest1 extends OverloadTest{ // 在子类中重载fun public void fun(int i, int m, int n) { System.out.println("Overload fun1 in OverloadTest1, parameter type: int, int, int"); } // 这个不是对父类中方法的重载,只是一个新的方法。 public void fun3(int i) { System.out.println("fun2 in OverloadTest1"); } } // 对override测试的文件:OverrideTest.java public class OverrideTest { public void fun() throws TestException { System.out.println("method fun in OverrideTest"); } private void fun1() { System.out.println("method fun1 in OverrideTest"); } public static void main(String[] args) { OverrideTest test = new OverrideTest1(); try { test.fun(); test.fun1(); } catch(Exception e) { } } } class OverrideTest1 extends OverrideTest{ // 以下正常Override public void fun() throws TestException2 { System.out.println("fun in OverrideTest1"); } // 不能Override父类中的方法,因为它定义了不同的异常类型和 // 返回值。 //public int fun() throws TestException1 { // System.out.println("method fun in Test"); // return 1; //} // 不能Override父类中的方法,因为它抛出了比父类中非法范围 // 更大的异常。 //public void fun() throws Exception { // System.out.println("fun in OverrideTest1"); //} // 这个方法并没有Override父类中的fun1方法,因为这个方法在 // 父类是private类型,所以这里只是相当于定义了一个新方法。 public void fun1() { System.out.println("method fun1 in Test"); } } class TestException extends Exception{ public TestException(String msg) { super(msg); } } class TestException1 extends TestException { public TestException1(String msg) { super(msg); } } class TestException2 extends TestException { public TestException2(String msg) { super(msg); } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值