2013-03-07 56 views
10

當一個簡單的接口,還沒有定義。的getMethods()返回的方法實現的通用接口

但如果我更改接口以一個通用的一個:

interface Foo<T> { 
    void myMethod(T arg);  
} 

class FooImpl implements Foo<String> { 
    void myMethod(String arg){} 
} 

然後奇怪的輸出將是:

myMethod java.lang.Object, 
myMethod java.lang.String, 
...//Other Method 

爲什麼改變接口的通用一個後會導致一個更使用參數類型Object的方法?

回答

6

第一種方法是由編譯器創建的bridge method。 如果你測試'isBridge()'的方法,你可以過濾掉'錯誤'的方法(也可以過濾掉你可以用協方差返回得到的一些奇怪的結果)。

下面的代碼不會打印myMethod java.lang.Object

import java.lang.reflect.Method; 


public class FooImpl implements Foo<String> { 
    public void myMethod(String arg) { 
    } 

    public static void main(String[] args) throws Exception { 
     Class cls = FooImpl.class; 
     for (Method method : cls.getMethods()) { 
      if (!method.isBridge()) { 
       System.out.print(method.getName() + "\t"); 

       for (Class paramCls : method.getParameterTypes()) { 

        System.out.print(paramCls.getName() + ","); 

       } 
      } 
      System.out.println(); 
     } 
    } 
} 

interface Foo<T> { 
    public void myMethod(T arg); 
} 
+0

展望「什麼是電橋法」了。 – StarPinkER 2013-03-07 10:45:47

+1

閱讀本教程,它爲博客鏈接解釋了所有內容:http://docs.oracle.com/javase/tutorial/java/generics/erasure.html – Muel 2013-03-07 10:47:49

2
try { 
     for (Method method : cls.getMethods()) { 
    //these methods are called bridge methods  
      if(!method.isBridge()){ 
       System.out.print(method.getName() + "\t"); 
       for(Class paramCls : method.getParameterTypes()){ 
        System.out.print(paramCls.getName() + ","); 
       } 
       System.out.println(); 
      } 
     } 
    } catch (SecurityException e) { 
     // TODO Auto-generated catch block 
    } 

UPDATE:Bridge methods

引述博客:

在Java Bridge的方法是合成方法,其對是必要的實現一些Java語言功能。已知最好的樣本是 協變返回類型,以及基於 方法的參數與正在調用的實際方法不同時的泛型情況。

更新代碼從上方博客:

public class SampleTwo { 
    public static class A<T> { 
     public T getT(T args) { 
      return args; 
     } 
    } 

    public static class B extends A<String> { 
     public String getT(String args) { 
      return args; 
     } 
    } 
} 

在編譯代碼將看起來像:

public SampleThree$B(); 
... 
public java.lang.String getT(java.lang.String); 
Code: 
0: aload_1 
1: areturn 

public java.lang.Object getT(java.lang.Object); 
Code: 
0: aload_0 
1: aload_1 
2: checkcast  #2; //class java/lang/String 
5: invokevirtual #3; //Method getT:(Ljava/lang/String;)Ljava/lang/String; 
8: areturn 
} 

橋方法,它從基類重寫方法「A 「,而不是 只是調用一個帶字符串參數(#3),但也執行類型 強制轉換到「java.lang.String」(#2)。這意味着,如果你將執行 下面的代碼,忽略編譯器的「選中」的警告,結果 將拋出ClassCastException從橋上方法拋出:

A a = new B(); 
a.getT(new Object())); 
+0

+1。 – StarPinkER 2013-03-07 12:06:38

相關問題