2016-01-13 109 views
4

我有我想要使用加載類,並在運行時實例化我的對象的靜態方法,但是當我編譯,我得到這樣的警告:如何將通配符(?)轉換爲泛型類型T?

warning: [unchecked] unchecked cast 
      T t = (T) ctor.newInstance(); 
required: T 
found: CAP#1 
where T is a type-variable: 
    T extends Object declared in method <T>forName(String,Set<String>) 
    where CAP#1 is a fresh type-variable: 
    CAP#1 extends Object from capture of ? 
1 warning 

下面的代碼:

public static <T> Set<T> forName(String modulePath, Set<String> classes) throws InvalidModuleException{ 
    try { 
     ClassLoader cl = new URLClassLoader(new URL[]{new URL(modulePath)}); 

     Set<T> list = new HashSet<>(classes.size()); 
     for (String className : classes) { 
      Class<?> clazz = (Class<?>) Class.forName(className, true, cl); 
      Constructor<?> ctor = clazz.getConstructor(); 
      T t = (T) ctor.newInstance(); 
      list.add(t); 
     } 
     return list;  
    } catch (MalformedURLException | ReflectiveOperationException ex) { 
     throw new InvalidModuleException(ex.getMessage()); 
    } 
} 

有人可以解釋我嗎?

[更新] 這裏是和實例方法調用:

HashSet<String> set = new HashSet<>(); 
h.add("fully_classfied_classname_readed_from_file"); //Class that extends AbstractApplication 
Set<AbstractApplication> abs = Apps.forName("plugins/module.jar", set); 

回答

1

有一個缺失的位。首先,您嘗試將每個對象的類型設置爲T。如果你知道T prehand,我沒有看到你需要通過一組字符串當一個類的對象會做

假設,如果你仍然需要在子類的可能性的情況下誰的理由:

public static <T> Set<? extends T> forName(String modulePath, Set<String> classes, Class<T> claz) throws InvalidModuleException{ 
    try { 
    ClassLoader cl = new URLClassLoader(new URL[]{new URL(modulePath)}); 

    Set<T> list = new HashSet<>(classes.size()); 
    for (String className : classes) { 
     Class<?> clazz = Class.forName(className, true, cl); 
     Constructor<?> ctor = clazz.getConstructor(); 
     Object obj = ctor.newInstance(); 
     list.add(claz.cast(obj)); 
    } 
    return list; 
} catch (MalformedURLException | ReflectiveOperationException | ClassCastException ex) { 
    throw new InvalidModuleException(ex.getMessage()); 
} 
} 
+0

這就是我想要的。加載子類(請參閱更新)。我想你的代碼可以幫助。 – ehbarbian

+2

或者,您可以事先更改類的類型Class clazz = Class.forName(...)。asSubclass(claz);' – newacct

3

使用字符串來表示的類可以這樣做,在一個安全的方式。首先,編譯器沒有辦法知道這組字符串實際上包含完全合格的類名;即使它們是類名稱,也不能保證名稱指定的類是T的子類。

不是傳遞在一組字符串中,通過在一組類,限制爲的T子類:

Set<Class<? extends T>> classes 

然後,你可以遍歷這些類,並刪除任何鑄件的需要:

for (Class<? extends T> clazz : classes) { 
    Constructor<? extends T> ctor = clazz.getConstructor(); 
    T t = ctor.newInstance(); 
    list.add(t); 
} 

如果推遲類的初始化的要求是絕對的,你別無選擇,只能適當地添加@SuppressWarnings這種方法,並希望從這些字符串加載的配置爲c orrect。

+0

我使用Set ,因爲類名是從文件中讀取的。 我將文件保存在我將要使用的類中。 – ehbarbian

+0

@ehbarbian請參考最後一句。從類型的角度來看,你正在做一些本質上不安全的事情。 –

相關問題