为什么Java的8适用于不同的注解,派生类? [英] Why does Java 8 apply annotations differently to derived classes?

查看:148
本文介绍了为什么Java的8适用于不同的注解,派生类?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我有以下两类:

// Base.java
public abstract class Base<T> {
  abstract void method(T t);
}

// Derived.java
public class Derived extends Base<Number> {
  @Deprecated
  void method(Number n) {}
}

然后我和 javac的Base.java Derived.java 编译它们,然后使用 javap的-v派生。如果我使用的Java 7,我得到

I then compile them with javac Base.java Derived.java and then use javap -v Derived. If I use Java 7, I get

public class Derived extends Base<java.lang.Number>
  Signature: #17                          // LBase<Ljava/lang/Number;>;
  SourceFile: "Derived.java"
  minor version: 0
  major version: 51
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #5.#20         //  Base."<init>":()V
   #2 = Class              #21            //  java/lang/Number
   #3 = Methodref          #4.#22         //  Derived.method:(Ljava/lang/Number;)V
   #4 = Class              #23            //  Derived
   #5 = Class              #24            //  Base
   #6 = Utf8               <init>
   #7 = Utf8               ()V
   #8 = Utf8               Code
   #9 = Utf8               LineNumberTable
  #10 = Utf8               method
  #11 = Utf8               (Ljava/lang/Number;)V
  #12 = Utf8               Deprecated
  #13 = Utf8               RuntimeVisibleAnnotations
  #14 = Utf8               Ljava/lang/Deprecated;
  #15 = Utf8               (Ljava/lang/Object;)V
  #16 = Utf8               Signature
  #17 = Utf8               LBase<Ljava/lang/Number;>;
  #18 = Utf8               SourceFile
  #19 = Utf8               Derived.java
  #20 = NameAndType        #6:#7          //  "<init>":()V
  #21 = Utf8               java/lang/Number
  #22 = NameAndType        #10:#11        //  method:(Ljava/lang/Number;)V
  #23 = Utf8               Derived
  #24 = Utf8               Base
{
  public Derived();
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method Base."<init>":()V
         4: return
      LineNumberTable:
        line 1: 0

  void method(java.lang.Number);
    flags:
    Code:
      stack=0, locals=2, args_size=2
         0: return
      LineNumberTable:
        line 7: 0
    Deprecated: true
    RuntimeVisibleAnnotations:
      0: #14()

  void method(java.lang.Object);
    flags: ACC_BRIDGE, ACC_SYNTHETIC
    Code:
      stack=2, locals=2, args_size=2
         0: aload_0
         1: aload_1
         2: checkcast     #2                  // class java/lang/Number
         5: invokevirtual #3                  // Method method:(Ljava/lang/Number;)V
         8: return
      LineNumberTable:
        line 1: 0
}

如果我做同样的事情与Java 8,我反而获得

If I do the same thing with Java 8, I instead get

public class Derived extends Base<java.lang.Number>
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #5.#20         // Base."<init>":()V
   #2 = Class              #21            // java/lang/Number
   #3 = Methodref          #4.#22         // Derived.method:(Ljava/lang/Number;)V
   #4 = Class              #23            // Derived
   #5 = Class              #24            // Base
   #6 = Utf8               <init>
   #7 = Utf8               ()V
   #8 = Utf8               Code
   #9 = Utf8               LineNumberTable
  #10 = Utf8               method
  #11 = Utf8               (Ljava/lang/Number;)V
  #12 = Utf8               Deprecated
  #13 = Utf8               RuntimeVisibleAnnotations
  #14 = Utf8               Ljava/lang/Deprecated;
  #15 = Utf8               (Ljava/lang/Object;)V
  #16 = Utf8               Signature
  #17 = Utf8               LBase<Ljava/lang/Number;>;
  #18 = Utf8               SourceFile
  #19 = Utf8               Derived.java
  #20 = NameAndType        #6:#7          // "<init>":()V
  #21 = Utf8               java/lang/Number
  #22 = NameAndType        #10:#11        // method:(Ljava/lang/Number;)V
  #23 = Utf8               Derived
  #24 = Utf8               Base
{
  public Derived();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method Base."<init>":()V
         4: return
      LineNumberTable:
        line 1: 0

  void method(java.lang.Number);
    descriptor: (Ljava/lang/Number;)V
    flags:
    Code:
      stack=0, locals=2, args_size=2
         0: return
      LineNumberTable:
        line 5: 0
    Deprecated: true
    RuntimeVisibleAnnotations:
      0: #14()

  void method(java.lang.Object);
    descriptor: (Ljava/lang/Object;)V
    flags: ACC_BRIDGE, ACC_SYNTHETIC
    Code:
      stack=2, locals=2, args_size=2
         0: aload_0
         1: aload_1
         2: checkcast     #2                  // class java/lang/Number
         5: invokevirtual #3                  // Method method:(Ljava/lang/Number;)V
         8: return
      LineNumberTable:
        line 1: 0
    RuntimeVisibleAnnotations:
      0: #14()
}
Signature: #17                          // LBase<Ljava/lang/Number;>;
SourceFile: "Derived.java"

这里要注意的一点是,上有无效的方法(java.lang.Object)中的在Java 8版本存根可见的注释,是不是present在Java 7的版本。这不只是的javap 犯了一个错误 - 如果你使用反射来检查在运行时的批注present,在Java 7的版本只对<$ C $注解C>无效的方法(java.lang.Number中)和Java 8版本有它两个。这是怎么回事?

The thing to note here is that there is an annotation visible on the void method(java.lang.Object) stub in the Java 8 version that is not present in the Java 7 version. It's not just javap making a mistake -- if you use reflection to check the annotations present at runtime, the Java 7 version only has an annotation on void method(java.lang.Number) and the Java 8 version has it on both. What's going on?

推荐答案

这是因为它被固定为这种行为似乎更加一致。详情请参阅 JDK-6695379 问题。而这不仅是Java的8,也有人反向移植到Java 7u80:

That's because it was fixed as this behavior seems to be more consistent. See the JDK-6695379 issue for details. And that's not only Java 8, it was also backported to Java 7u80:

C:\Test>"C:\Program Files\Java\jdk1.7.0_79\bin\javac.exe" Derived.java

C:\Test>javap -v Derived.class >javac7_79

C:\Test>"C:\Program Files\Java\jdk1.7.0_80\bin\javac.exe" Derived.java

C:\Test>javap -v Derived.class >javac7_80

C:\Test>diff javac7_79 javac7_80
2,3c2,3
<   Last modified 18.05.2015; size 484 bytes
<   MD5 checksum bd5e729c8eda30f72f3dc5301fa9bfc2
---
>   Last modified 18.05.2015; size 496 bytes
>   MD5 checksum 728d9e30b9aab2381e711b3edd008000
69a70,71
>     RuntimeVisibleAnnotations:
>       0: #14()

这篇关于为什么Java的8适用于不同的注解,派生类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆