2017-06-26 3 views
5

汎用のJavaインターフェイスId<T>と、T getId()という1つのメソッドと、Id<Long>を実装するクラスMyClassがあります。 MyClassで宣言されたメソッドをJavaリフレクションで調べると、戻り値のタイプがLongで、戻り値がObjectのメソッドが2つあります。 2番目の方法はどこから来て、どのように削除できますか?ここで一般的なJavaインターフェイスを実装すると、追加のメソッドが追加されます

はソースです:

package mypackage; 

import java.lang.reflect.Method; 

public class MainClass { 
    public static void main(String[] args) { 
     for (Method method : MyClass.class.getDeclaredMethods()) { 
      System.out.println(method); 
     } 
     // prints out two lines 
     // public java.lang.Long mypackage.MyClass.getId() <-- ok 
     // public java.lang.Object mypackage.MyClass.getId() <-- not ok 
    } 
} 

interface Id<T> { 
    T getId(); 
} 

class MyClass implements Id<Long> { 
    @Override 
    public Long getId() { 
     return new Long(0); 
    }; 
} 
+0

Returntypeが 'Long'のメソッドでは、プリミティブ' long'を返すこともできます。 'return 0L;'。それは 'ロング'にautoboxedされます。あなたの質問への答えではありませんが、おそらくあなたは知りませんでした。 –

答えて

3

2番目の方法はsynthetic bridgeメソッドです。method.isSynthetic()またはmethod.isBridge()で確認できます。それを削除することはできませんが、宣言されたメソッドのリストでそれを見たくない場合は、それらのメソッドにすべてisBridge() == falseが含まれているかチェックしてください。

合成ブリッジメソッドは、コンパイル時に汎用クラスに自動的に追加されます。合成方法の詳細についてはhereをご覧ください。

for (Method method : MyClass.class.getDeclaredMethods()) { 
    System.out.println("Method: " + method); 
    System.out.println("synthetic: " + method.isSynthetic()); 
    System.out.println("bridge: " + method.isBridge()); 
} 

// 1 
//Method: public java.lang.Long Main$MyClass.getId() 
//synthetic: false 
//bridge: false 
// 2 
//Method: public java.lang.Object Main$MyClass.getId() 
//synthetic: true 
//bridge: true 
1

あなたはjavap -c MyClassによってコンパイルされた方法を見つけることができます。

Compiled from "Test.java" 
class MyClass implements Id<java.lang.Long> { 
    MyClass(); 
    Code: 
     0: aload_0 
     1: invokespecial #1     // Method java/lang/Object."<init>":()V 
     4: return 

    public java.lang.Long getId(); 
    Code: 
     0: new   #2     // class java/lang/Long 
     3: dup 
     4: lconst_0 
     5: invokespecial #3     // Method java/lang/Long."<init>":(J)V 
     8: areturn 

    public java.lang.Object getId(); 
    Code: 
     0: aload_0 
     1: invokevirtual #4     // Method getId:()Ljava/lang/Long; 
     4: areturn 
} 

あなたはgetIdため方法がある見ることができるように、1つの戻り値の型implementationとしてLongと別のリターンですObjectタイプ(Long getIdメソッドを呼び出すタイプ)です。

戻り値の型Object方法は決してLong getId方法にジェネリック型とブリッジを指定する際に取り扱うないためです。例:私たちはLongタイプでId匿名クラスを実装することができます上記のコードスニペットとして

Id<Long> id = new Id<Long>() { 
     @Override 
     public Long getId() { 
      return null; 
     } 
    }; 
    Long id1 = id.getId(); 

。しかしなしジェネリック型変数に指定するように、我々はまた、Id匿名クラスを実装することができます問題:それは型を返すだときid.getId()

Id id = new Id<Long>() { 
     @Override 
     public Long getId() { 
      return null; 
     } 
    }; 
    Object id1 = id.getId(); 

は今のために、コンパイラは、変数idためジェネリック型を推測することはできませんObject型変数は、このメソッドをpublic java.lang.Object getId();と呼び、public java.lang.Long getId();メソッドを呼び出すことを意味します。

関連する問題