java 8 - Icomparable<T> 的注释 compareTo <T> 也添加了注释 compareTo(Object o)

标签 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 中的相关变化吗? (将在符合条件时提供赏金)。

最佳答案

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

A DESCRIPTION OF THE REQUEST : When a class extends a generic classes or implements a generic interface, synthetic method may be generated to bridge between the method taking specific parameters/return and the one of the super-class/interface which is defined with Objects, because of erasure. A bridge method redirects the call to the actual method, according to Java Language Specification. However the bridge method lacks the annotations defined for the original method and its parameters.

JUSTIFICATION : The problem arises when trying to retrieve annotations of such a method at run-time. Since it's impossible to find out reliably what classes substitute the generic parameters, we don't know what parameter to send to getMethod(...) in order to receive the correct method back. When sending Object.class (while generic parameter is a different class) getMethod will return the bridge method, which won't have the information about the original method annotations.

它也记录在 JDK 8 compatibility guide 中:

Area: Tools / javac

Synopsis
As of this release, parameter and method annotations are copied to synthetic bridge methods.This fix implies that now for programs like:

@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 {}
 
}

Each generated bridge method will have all the annotations of the method it redirects to. Parameter annotations will also be copied. This change in the behavior may impact some annotations processor or in general any application that use the annotations.

Nature of Incompatibility
behavioral

RFE
6695379

关于java 8 - Icomparable<T> 的注释 compareTo <T> 也添加了注释 compareTo(Object o),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23128335/

相关文章:

java - 在 glOrtho View 中绘制一条线,为什么它使用默认投影?

java - 使用用户定义的注释时获取 java.lang.NullPointerException

java - 无法解析注释参数

ruby - Java 8 相当于 ruby​​ each_with_index

java - 从 guiceModule 访问 dropwizard Bundle 实例

java - Linux 上的 TCP 打洞和 setReuseAddress()

java - GUI 随机方程生成器

ios - 如何将红色的Pin更改为自定义图像?的iOS

java - java会允许使用功能接口(interface)作为方法吗?

java - Controller 类中 FXML Controller 的 Getters 而不是查找?