2015-05-18 6 views
10

Jeśli mam dwie następujące klasy:Dlaczego środowisko Java 8 stosuje adnotacje w sposób odmienny do klas pochodnych?

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

i

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

I następnie skompilować je javac Base.java Derived.java a następnie użyć javap -v Derived. Jeśli używam Java 7, mam

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 
} 

jeśli robię to samo z Java 8, I zamiast dostać

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" 

rzeczą uwagę jest to, że istnieje adnotacja widoczna na void method(java.lang.Object) stub w wersji Java 8, którego nie ma w wersji Java 7. To nie tylko javap popełnianie błędu - jeśli używasz refleksji do sprawdzania adnotacji obecnych w środowisku wykonawczym, wersja Java 7 ma tylko adnotację na void method(java.lang.Number), a wersja Java 8 ma je na obu. Co się dzieje?

Odpowiedz

8

To dlatego, że zostało naprawione, ponieważ to zachowanie wydaje się być bardziej spójne. Szczegółowe informacje można znaleźć w numerze JDK-6695379. A to nie tylko Java 8, ale również przeniesienie do 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() 
+0

To niesamowicie irytująca zmiana zachowania. Dzięki za wskaźnik. –

Powiązane problemy