简体   繁体   English

反射无法获取从泛型接口重写的方法的实际参数类型?

[英]Reflection can't get the actual parameter type of a method that overrides from a generic-typed interface?

EDIT: Sorry the example I provide below doesn't reproduce the problem... I'm trying to find the right way to reproduce it. 编辑:对不起,我在下面提供的示例无法重现该问题...我正在尝试找到重现此问题的正确方法。 Before that, you may just ignore my question... 在此之前,您可能会忽略我的问题...

Usually we grab the parameter type of a method like this: 通常我们会像这样获取方法的参数类型:

Class<?> clazz = method.getParameterTypes()[0]

I have never thought twice about it before, but recently I bumped into an issue that I always got class java.lang.Object when doing that. 我以前从未三思而后行,但最近遇到一个问题,即这样做时我总是得到class java.lang.Object After an inspection, I found out the case can be described like this: 经过检查,我发现案件可以这样描述:

/** A parameterized interface */
public interface IService<T> {

    Result create(T obj);
}

/** An implementation */
public class CarService implements IService<Car> {

    public Result create(Car car) { ... }
}

And then when I use the way above to get the class of the parameter car , it turns out to be a class java.lang.Object : 然后,当我使用上述方法获取参数car的类时,结果证明它是一个class java.lang.Object

Method methods = CarService.class.getMethods();
for (Method method : methods) {
    Class<?>[] types = method.getParameterTypes();
    // when the loop meets "create" here ...
}

I guess I have totally forgot something very fundamental about type erase? 我想我完全忘记了有关类型擦除的一些基本知识? But now I really need get the actual parameter type in this case, if it's possible... 但是现在,如果可能的话,在这种情况下,我真的需要获取实际的参数类型。

Yes, this is type erasure being annoying. 是的,这是令人讨厌的类型擦除。 It's worth looking at what you get in bytecode here: 值得一看的是您在这里的字节码中得到了什么:

class Car {}
interface IService<T> {
    void create(T obj);
}

class CarService implements IService<Car> {
    public void create(Car car) {}
}

Then: 然后:

$ javac Test.java # Contains all the above...
$ javap -c CarService

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

  public void create(Car);
    Code:
       0: return

  public void create(java.lang.Object);
    Code:
       0: aload_0
       1: aload_1
       2: checkcast     #2                  // class Car
       5: invokevirtual #3                  // Method create:(LCar;)V
       8: return
}

And those are also shown when you use reflection: 使用反射时也会显示这些内容:

public class Test {
    public static void main(String[] args) {
        Method[] methods = CarService.class.getDeclaredMethods();
        for (Method method : methods) {
            System.out.println(method.getName());
            for (Class<?> type : method.getParameterTypes()) {
                System.out.printf("- %s%n", type.getName());
            }
        }
    }
}

Output: 输出:

create
- Car
create
- java.lang.Object

How you use this will depend on exactly what you're trying to achieve, but hopefully the awareness that there are multiple methods in the bytecode will help... 如何使用它取决于您要实现的目标,但是希望知道字节码中有多种方法将有所帮助...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM