2015-02-07 116 views
1

當涉及到有界類型時,我有一個理解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)

+0

不要對你的泛型類型就像你已經有了類。例如,你可以創建類如'class Foo ',但對於這個類,String將表示泛型類型而不是java.lang.String類型,所以你將不能使用String s =「hello world」 '裏面呢。命名泛型類型比較簡單,比如'class Foo '。 – Pshemo 2015-02-07 22:25:31

+0

@Pshemo注意到,我想這樣可以避免將來在我身邊出現一些混淆...... – WorldSEnder 2015-02-07 22:27:28

回答

3

Java Language Specification

類型變量(§4.4)的擦除是其最左邊的結合的擦除。

你有

<EventType extends Event> 

<E extends EventType> 

最左邊的束縛的EEventType,這是另一種類型的變量,它的最左邊界是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 
+0

所以,當方法被註釋掉時,讓我們說'@interface Subscribe',然後有人通過反射來掃描類,方法是使用'Subscribe'他們會看到一個方法'onEventCaught(Event event)',這是否正確? – WorldSEnder 2015-02-07 22:18:19

+1

@WorldSEnder這取決於他們使用什麼。如果他們使用'Method#getParameterTypes',他們會看到'Event'。如果他們使用'Method#getParameters'返回一個'Parameter []',他們會看到'E'。儘管你總是可以通過對方法的類型變量或類進行逆向工程來找到'E'。 – 2015-02-07 22:21:38

+0

我想到了什麼:僅在'Bar'註釋方法時,註釋是否仍然適用於'onEventCaught(Event event)'? 'Bar'不會在'onEventCaught(FooEvent ev)'的聲明中使用泛型,那麼如何解決?如果你也可以引用這個標準,我會很高興。 – WorldSEnder 2015-02-07 22:58:25