java8 - 注释compareTo <t> of Comparable <t>将注释添加到compareTo(Object o)</t> </t>

时间:2014-04-17 08:35:50

标签: java annotations java-8

我有一个注释

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。)

2 个答案:

答案 0 :(得分:8)

此更改在问题JDK-6695379 - Copy method annotations and parameter annotations to synthetic bridge methods中有所描述。似乎没有太多关于此功能的讨论,但请求和理由确实对我有意义。

  

要求说明:   当类扩展泛型类或实现泛型接口时,可以生成合成方法以在采用特定参数/返回的方法与由对象定义的超类/接口之一之间进行桥接,因为擦除。根据Java语言规范,桥接方法将调用重定向到实际方法。然而,桥接方法缺少为原始方法及其参数定义的注释。

     

理由:   尝试在运行时检索此类方法的注释时出现问题。由于无法可靠地找出哪些类替换了泛型参数,因此我们不知道要向getMethod(...)发送什么参数以便接收正确的方法。当发送Object.class(而泛型参数是一个不同的类)时,getMethod将返回bridge方法,该方法将不具有有关原始方法注释的信息。

JDK 8 compatibility guide

中也记录了它
  

区域:工具/ 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()