2015-05-18 8 views
10

Se Ho le seguenti due classi:Perché Java 8 applica le annotazioni in modo diverso alle classi derivate?

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

e

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

Ho poi compilarli con javac Base.java Derived.java e quindi utilizzare javap -v Derived. Se uso Java 7, ottengo

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 
} 

Se faccio la stessa cosa con Java 8, ho invece capito

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" 

La cosa da notare qui è che non v'è un'annotazione visibile sul void method(java.lang.Object) stub nella versione Java 8 non presente nella versione Java 7. Non è solo javap commettere un errore: se si utilizza il reflection per controllare le annotazioni presenti al runtime, la versione Java 7 ha solo un'annotazione su void method(java.lang.Number) e la versione Java 8 lo ha su entrambi. Cosa sta succedendo?

risposta

8

Questo perché è stato risolto in quanto questo comportamento sembra essere più coerente. Vedere il problema JDK-6695379 per i dettagli. E non è solo Java 8, ma è stato anche sostituito a 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

Questo è un cambio di comportamento incredibilmente fastidioso. Grazie per il puntatore. –

Problemi correlati