2013-03-07 53 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

相关问题