2017-06-12 66 views
4

我有一個類,如下所示:如何在運行時將類<T>轉換爲類似<Class T extends Foo>的東西?

class FooClassAnalyser<T extends Foo> extends ClassAnalyser<T> 

(其中ClassAnalyser爲若干具體實施方式的一個抽象基類;和FooClassAnalyser是的專業對於其中T延伸Foo的情況下的具體實現)。它有一個構造函數,看起來像這樣:

FooClassAnalyser(Class<T> classToAnalyse) 

在另一類,我取決於classToAnalyse的類型ClassAnalyser個靜態工廠方法調用適當的構造函數:

static <U> ClassAnalyser<U> constructClassAnalyser(Class<U> classToAnalyse) 

的功能我想要查看是否U instanceof Foo,然後構造一個FooClassAnalyser並返回它,如果是。

但是,我找不到一種方法來適應Java的類型系統。類型擦除意味着我們不能直接與U做任何事情。然而,我們作爲一個參數能夠通過classToAnalyse事實測試通過使用反射來看看U instanceof Foo

if (Foo.class.isAssignableFrom(classToAnalyse)) 

我的問題是,不像instanceof,這種「通過反射的instanceof」不可見Java的類型系統。特別是,直接將classToAnalyse作爲參數傳遞給FooClassAnalyser的構造函數會因類型不匹配而失敗,因爲Java不知道classToAnalyse實際上是Class<U extends Foo>

到目前爲止,我已經找到了最好的解決方案是使用未經檢查的鑄造,使classToAnalyse一個Class<? extends Foo>(這是實際上檢查,但Java的不知道它的選中)。至少可以將它作爲參數傳遞給new FooClassAnalyser,並獲得返回的對象FooClassAnalyser<?>。然而,問題在於,這不會轉換回ClassAnalyser<U>,因爲Java不承認鑄造classToAnalyse具有不同的泛型綁定,但不會改變對象仍然是相同對象的事實(因此仍然是Class<U>);換句話說,所有Java可以看到的是它不認可的FooClassAnalyser<?>也是FooClassAnalyser<U>,因此轉換回來需要另一個未檢查的轉換。其結果是編譯和運行的代碼,但有許多關於類型安全性的警告。

我嘗試過的大多數其他事情都是語法錯誤(例如,類型Class<U extends Foo>的變量不能直接聲明; Java不會正確解析)。應該指出,我實際上沒有任何一個類型爲U的對象;我試圖分析課程本身,因此只有Class<U>對象可以使用。

是否有可能以類型安全的方式編寫這樣的代碼?

+1

對於它的價值,我認爲你可以做得比你現在做的更好(沒有經過檢查的劇組)。當你使用Java泛型稍微高級一些時,它總是會變得越來越糟糕。 – kaqqao

+1

作爲一個方面說明,你不必使用未經檢查的強制轉換爲Class <?擴展Foo>'。你可以使用['clazz.asSubclass(Foo.class)'](http://docs.oracle.com/javase/8/docs/api/java/lang/Class.html#asSubclass-java.lang.Class- )。 – Radiodef

+0

@Radiodef:是的,但'clazz.asSubclass(Foo.class)'返回一個'Class <?延伸Foo>',這已經失去了關於''的知識。你可以用它來構造一個'FooClassAnalyser <?在沒有警告的情況下安全地延伸Foo>',但沒有乾淨的方式將其作爲'ClassAnalyser '返回...... – Holger

回答

0

我的問題是,與instanceof不同,這個「通過反射的instanceof」對Java的類型系統是不可見的。特別是,直接將classToAnalyse作爲參數傳遞給FooClassAnalyser的構造函數會因類型不匹配而失敗,因爲Java不知道classToAnalyse實際上是Class<U extends Foo>

爲你傳遞一個Class<U>constructClassAnalyser這隻要發生。你沒有給我們提供太多的代碼,所以我不能爲你寫一個明確的解決方案。然而,如果您能找到一種方法將U傳遞給constructClassAnalyser而不是Class<U>,那將會更加簡單。

static <U> ClassAnalyser<U> constructClassAnalyser(U objectToAnalyse)

要檢查它的類,你可以使用objectToAnalyse#getClass;如果objectToAnalyse instanceof Foo返回true,則還可以使用instanceof來驗證U extends Foo,然後在需要時將其轉換爲其各自的類。

+0

「ClassAnalyser」的重點在於它分析一個類;它不一定具有該類可用的對象。所以這個解決方案是行不通的,這並沒有真正回答這個問題。 (即使我們確實有一個可用類的對象,但是我不相信你可以擺脫我當前解決方案中的第二個未經檢查的演員,儘管可以很容易地看出你如何擺脫第一個。) – smithaiw

+0

如果你有這個類,只需使用'Class#newInstance'來創建它的一個新實例 –

+0

這就要求類有一個可訪問的構造函數,並且還需要爲構造函數找到適當的參數。另外,構造函數可能有副作用。 (儘管如此,我仍然沒有看到它將如何解決最初的問題。) – smithaiw

相關問題