Java语言层面和JVM层面方法特征签名的区别 及 实例分析

Java语言层面和JVM层面方法特征签名的区别 及 实例分析

      在文章《Java前端编译:Java源代码编译成Class文件的过程》和《Java Class文件结构解析 及 实例分析验证》中多次提到Java语言层面方法特征签名和JVM层面方法特征签名的区别。

      下面我们先来回顾一下Java语言层面方法特征签名和JVM层面方法特征签名的区别的是什么,再用测试程序实例来分析验证。

1、两个层面的方法特征签名的区别

      方法特征签名:用于区分两个不同方法的语法符号;

(A)、Java语言层面的方法特征签名:

     特征签名 = 方法名 + 参数类型 + 参数顺序;

      更多请参考:http://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.4.2

(B)、JVM层面的方法特征签名:

     特征签名 = 方法名 + 参数类型 + 参数顺序 + 返回值类型;

      如果存在类型变量或参数化类型,还包括类型变量或参数化类型编译未擦除类型前的信息(FormalTypeParametersopt),和抛出的异常信息(ThrowsSignature),即方法名+签名;

      Java语言重载(Overload)一个方法,需要Java语言层面的方法特征签名不同,即不包括方法返回值;而Class文件中有两个同名同参数(类型、顺序都相同),但返回值类型不一样,也是允许的,可以正常运行,因为JVM层面的方法特征签名包括返回值类型。

      同样的,对字段来说,Java语言规定字段无法重载,名称必须不一样;但对Class文件来说,只要两个字段描述(类型)不一样,名称一样也是可以的。

2、实例分析验证

      下面我们先用javac编译测试程序JavacTestOverload.java,测试程序如下:


     
     
  1. public class JavacTestOverload {
  2. public String method1(String str) {
  3. String mtdName = Thread.currentThread().getStackTrace()[ 1].getMethodName(); //获取当前方法名称,具体使用数组的那个元素和JVM的实现有关,具体说明可以查看Thread.getStackTrace方法的javadoc
  4. System.out.println( "invoke " + mtdName + " return String");
  5. return "";
  6. }
  7. public int method2(String str) {
  8. String mtdName = Thread.currentThread().getStackTrace()[ 1].getMethodName();
  9. System.out.println( "invoke " + mtdName + " return int");
  10. return 1;
  11. }
  12. public static void main(String[] args) {
  13. JavacTestOverload javacTestOverload = new JavacTestOverload();
  14. String str = javacTestOverload.method1( "Test");
  15. int i = javacTestOverload.method2( "Test");
  16. }
  17. }

     注意,public String method1(String str)方法和public String method2(String str)方法,方法名称和返回值类型不同,而参数一样,因为方法名不同,是同时满足Java语言层面的方法特征签名和JVM层面的方法特征签名的要求;

     如果方法名相同(都为"method1"),就不满足ava语言层面的方法特征签名的要求,javac编译就会出现错误,如下:

     我们用上面的程序先通过编译,运行调用这两个方法,可以看到两个方法分别输出了自己的名称,如下:

     接着,我们用javap反编译JavacTestOverload..class文件,并保存到JavacTestOverload..txt文件,方便对照分析:

     javap -verbose JavacTestOverload> JavacTestOverload..txt

     然后,通过分析JavacTestOverload..txt反编译信息,可以知道"method2"方法名称对应的常量为第27项,描述符为第28项("method1"方法的分别为第25、26项),如下:

     而后,在JavacTestOverload..class找到"method2"方法名称对应的字节码,修改为"method1",修改前后如下("32"--》"31"):

     这样两个方法的名称就相同了,可以再通过反编译修改后的JavacTestOverload..class来对比,可以看到修改后生成的反编译信息中没有了"method2"的字符信息,都变为了"method1",如下:

     而运行修改后的JavacTestOverload..class,可以看到两个方法运行时输出的名称都为"method1",也证明了两个方法的名称相同,如下:

 

     到这里,这样就证明了:Class文件中有两个同名同参数(类型、顺序都相同),但返回值类型不一样的方法也是允许的,可以正常运行,因为JVM层面的方法特征签名包括返回值类型 。

 

【参考资料】

1、《The Java Virtual Machine Specification》Java SE 8 Edition:https://docs.oracle.com/javase/specs/jvms/se8/html/index.html

2、《The Java Language Specification》Java SE 8 Edition:https://docs.oracle.com/javase/specs/jls/se8/html/index.html

3、Java前端编译:Java源代码编译成Class文件的过程

4、Java Class文件结构解析 及 实例分析验证

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值