【问题标题】:getMethods() returns method I haven't defined when implementing a generic interfacegetMethods() 返回实现泛型接口时未定义的方法
【发布时间】:2013-02-22 12:12:00
【问题描述】:

一个简单的界面:

interface Foo {
    void myMethod(String arg);
}

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

    public static void main(String[] args) {
    Class cls = FooImpl.class;
    try {
        for (Method method : cls.getMethods()) {
        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
    }
    }
}

输出将是:

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

只打印一个 myMethod。

但如果我将接口更改为通用接口:

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的Method?

【问题讨论】:

    标签: java reflection interface


    【解决方案1】:

    第一个方法是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);
    }
    

    【讨论】:

    【解决方案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
        }
    

    更新: Bridge methods

    引用博客:

    Java 中的桥接方法是合成方法,它们是必要的 实现一些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()));
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-16
      相关资源
      最近更新 更多