【问题标题】:What will be the runtime signature?运行时签名是什么?
【发布时间】:2015-02-07 22:09:57
【问题描述】:

当涉及到有界类型时,我在理解 Java 的类型擦除方面有点问题。考虑一下:

class Event {} // From the API
class FooEvent extends Event {}

abstract class Foo<EventType extends Event> {
    public abstract <E extends EventType> void onEventCaught(E event);
}

class Bar extends Foo<FooEvent> {
    @Override
    public void onEventCaught(FooEvent event) {

    }
}

显然这编译没有问题。我问自己的问题是,这里声明了Bar#onEventCaught() 的参数类型(如,反射是怎么想的)?

onEventCaught(FooEvent event) 还是onEventCaught(Event event)

【问题讨论】:

  • 不要将泛型类型命名为您已经拥有的类。例如,您可以创建像 class Foo&lt;String&gt; 这样的类,但对于此类,String 将代表泛型类型,而不是 java.lang.String 类型,因此您将无法在其中使用 String s = "hello world"。将泛型类型命名为更简单的名称,例如 class Foo&lt;T&gt;
  • @Pshemo 注意到,我想这会避免我在未来的一些混乱......

标签: java reflection type-erasure


【解决方案1】:

来自Java Language Specification

类型变量的擦除(第 4.4 节)是其最左边界的擦除。

你有

<EventType extends Event> 

<E extends EventType>

E的最左边界是EventType,这是另一个类型变量,它的最左边界是Event。所以在

中删除E
public abstract <E extends EventType> void onEventCaught(E event);

Event

类型变量确实出现在.class 文件中,您可以在反射中使用它们。

Class<?> clazz = Foo.class;
TypeVariable typeVariable = clazz.getTypeParameters()[0];
Type type = typeVariable.getBounds()[0];

System.out.println(typeVariable);
System.out.println(type);

打印

EventType
class com.example.Event

【讨论】:

  • 所以当方法被注释时,比如说@interface Subscribe 并且有人通过反射扫描类以查找带有Subscribe 的方法,他们将看到一个方法onEventCaught(Event event),对吗?
  • @WorldSEnder 这取决于他们使用什么。如果他们使用Method#getParameterTypes,他们将看到Event。如果他们使用返回Parameter[]Method#getParameters,他们将看到E。尽管您总是可以通过对方法的类型变量或类进行一些逆向工程来找到 E 的含义。
  • 我的想法是:当方法仅在Bar 中注释时,注释是否仍然应用于onEventCaught(Event event)Bar 在其 onEventCaught(FooEvent ev) 的声明中没有使用泛型,那么这将如何解决呢?如果您也可以为此引用标准,我会很高兴。
  • @WorldSEnder 在同一个 JLS 部分中所有其他类型的擦除都是类型本身。所以对于Bar#onEventCaught(FooEvent),参数类型将是FooEvent
猜你喜欢
  • 2011-04-23
  • 2017-10-19
  • 2019-11-15
  • 1970-01-01
  • 1970-01-01
  • 2022-09-27
  • 2017-02-17
  • 2014-09-13
  • 2022-06-28
相关资源
最近更新 更多