我有一个注释
package javaannotationtest;
import java.lang.annotation.*;
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomAnnotation {
}
这适用于以下课程中的compareTo
package javaannotationtest;
public class Customer implements Comparable<Customer>{
@Override
@CustomAnnotation
public int compareTo(Customer o) {
return 0;
}
}
该类给出了java-7和java-8编译代码的不同结果。
Java 7
1.7.0_45 -> public int javaannotationtest.Customer.compareTo(javaannotationtest.Customer)
has annotation of type javaannotationtest.CustomAnnotation
1.7.0_45 -> public int javaannotationtest.Customer.compareTo(java.lang.Object)
has no annotation of type javaannotationtest.CustomAnnotation
请注意,compareTo(Object)没有注释。
Java 8
1.8.0 -> public int javaannotationtest.Customer.compareTo(javaannotationtest.Customer)
has annotation of type javaannotationtest.CustomAnnotation
1.8.0 -> public int javaannotationtest.Customer.compareTo(java.lang.Object)
has annotation of type javaannotationtest.CustomAnnotation
Java 8已将注释添加到compareTo(java.lang.Object)
方法
以下是使用Java 8编译的版本的javap输出(可能不相关,它显示了添加到两个方法的注释)
Classfile /C:/code/java8annoation/out/production/java8annoation/javaannotationtest/Customer.class
Last modified 17 Apr, 2014; size 719 bytes
MD5 checksum 678e0371f5f9ed5666b513c940f365a7
Compiled from "Customer.java"
public class javaannotationtest.Customer extends java.lang.Object implements java.lang.Comparable<javaannotationtest.Customer>
Signature: #20 // Ljava/lang/Object;Ljava/lang/Comparable<Ljavaannotationtest/Customer;>;
SourceFile: "Customer.java"
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #4.#23 // java/lang/Object."<init>":()V
#2 = Class #24 // javaannotationtest/Customer
#3 = Methodref #2.#25 // javaannotationtest/Customer.compareTo:(Ljavaannotationtest/Customer;)I
#4 = Class #26 // java/lang/Object
#5 = Class #27 // java/lang/Comparable
#6 = Utf8 <init>
#7 = Utf8 ()V
#8 = Utf8 Code
#9 = Utf8 LineNumberTable
#10 = Utf8 LocalVariableTable
#11 = Utf8 this
#12 = Utf8 Ljavaannotationtest/Customer;
#13 = Utf8 compareTo
#14 = Utf8 (Ljavaannotationtest/Customer;)I
#15 = Utf8 o
#16 = Utf8 RuntimeVisibleAnnotations
#17 = Utf8 Ljavaannotationtest/CustomAnnotation;
#18 = Utf8 (Ljava/lang/Object;)I
#19 = Utf8 Signature
#20 = Utf8 Ljava/lang/Object;Ljava/lang/Comparable<Ljavaannotationtest/Customer;>;
#21 = Utf8 SourceFile
#22 = Utf8 Customer.java
#23 = NameAndType #6:#7 // "<init>":()V
#24 = Utf8 javaannotationtest/Customer
#25 = NameAndType #13:#14 // compareTo:(Ljavaannotationtest/Customer;)I
#26 = Utf8 java/lang/Object
#27 = Utf8 java/lang/Comparable
{
public javaannotationtest.Customer();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 3: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Ljavaannotationtest/Customer;
public int compareTo(javaannotationtest.Customer);
descriptor: (Ljavaannotationtest/Customer;)I
flags: ACC_PUBLIC
Code:
stack=1, locals=2, args_size=2
0: iconst_0
1: ireturn
LineNumberTable:
line 7: 0
LocalVariableTable:
Start Length Slot Name Signature
0 2 0 this Ljavaannotationtest/Customer;
0 2 1 o Ljavaannotationtest/Customer;
RuntimeVisibleAnnotations:
0: #17()
public int compareTo(java.lang.Object);
descriptor: (Ljava/lang/Object;)I
flags: ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
Code:
stack=2, locals=2, args_size=2
0: aload_0
1: aload_1
2: checkcast #2 // class javaannotationtest/Customer
5: invokevirtual #3 // Method compareTo:(Ljavaannotationtest/Customer;)I
8: ireturn
LineNumberTable:
line 3: 0
LocalVariableTable:
Start Length Slot Name Signature
0 9 0 this Ljavaannotationtest/Customer;
RuntimeVisibleAnnotations:
0: #17()
}
有人可以解释Java 8中的相关更改吗? (如果符合条件,将提供Bounty。)
答案 0 :(得分:8)
此更改在问题JDK-6695379 - Copy method annotations and parameter annotations to synthetic bridge methods中有所描述。似乎没有太多关于此功能的讨论,但请求和理由确实对我有意义。
中也记录了它要求说明: 当类扩展泛型类或实现泛型接口时,可以生成合成方法以在采用特定参数/返回的方法与由对象定义的超类/接口之一之间进行桥接,因为擦除。根据Java语言规范,桥接方法将调用重定向到实际方法。然而,桥接方法缺少为原始方法及其参数定义的注释。
理由: 尝试在运行时检索此类方法的注释时出现问题。由于无法可靠地找出哪些类替换了泛型参数,因此我们不知道要向getMethod(...)发送什么参数以便接收正确的方法。当发送Object.class(而泛型参数是一个不同的类)时,getMethod将返回bridge方法,该方法将不具有有关原始方法注释的信息。
区域:工具/ javac
<强>概要强>
在此版本中,参数和方法注释被复制到合成桥接方法。此修复意味着现在适用于以下程序:@Target(value = {ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) @interface ParamAnnotation {} @Target(value = {ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @interface MethodAnnotation {} abstract class T<A,B> { B m(A a){return null;} } class CovariantReturnType extends T<Integer, Integer> { @MethodAnnotation Integer m(@ParamAnnotation Integer i) { return i; } public class VisibilityChange extends CovariantReturnType {} }
每个生成的桥接方法都将具有重定向到的方法的所有注释。参数注释也将被复制。行为的这种变化可能会影响某些注释处理器或一般任何使用注释的应用程序。
不相容的性质
行为<强> RFE 强>
6695379
答案 1 :(得分:3)
@kapep:非常好的回答。我想补充一些关于这个问题的补充信息。不仅将注释复制到桥接方法。参数名称也被复制。如果使用-parameters编译器选项编译示例,则会获得此javap输出:
public int compareTo(Customer);
descriptor: (LCustomer;)I
flags: ACC_PUBLIC
Code:
stack=1, locals=2, args_size=2
0: iconst_0
1: ireturn
LineNumberTable:
line 11: 0
MethodParameters:
Name Flags
o
RuntimeVisibleAnnotations:
0: #15()
public int compareTo(java.lang.Object);
descriptor: (Ljava/lang/Object;)I
flags: ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
Code:
stack=2, locals=2, args_size=2
0: aload_0
1: aload_1
2: checkcast #2 // class Customer
5: invokevirtual #3 // Method compareTo:(LCustomer;)I
8: ireturn
LineNumberTable:
line 7: 0
MethodParameters:
Name Flags
o synthetic <-- see the name copied to the bridge method
RuntimeVisibleAnnotations:
0: #15()