是否能夠在Java中建立泛型類型的實例? 我根據我所看到的是,答案是思惟no
( 由於類型擦除 ),但我有興趣,若是任何人均可以看到我丟失的東西: html
class SomeContainer<E> { E createContents() { return what??? } }
編輯:事實證實, 超級類型令牌能夠用來解決個人問題,可是它須要不少基於反射的代碼,以下面的一些答案所示。 java
我將對此開放一下子,看看是否有人提出與Ian Robertson的Artima Article大相徑庭的東西 。 oracle
您能夠使用如下代碼段實現此目的: app
import java.lang.reflect.ParameterizedType; public class SomeContainer<E> { E createContents() throws InstantiationException, IllegalAccessException { ParameterizedType genericSuperclass = (ParameterizedType) getClass().getGenericSuperclass(); @SuppressWarnings("unchecked") Class<E> clazz = (Class<E>) genericSuperclass.getActualTypeArguments()[0]; return clazz.newInstance(); } public static void main( String[] args ) throws Throwable { SomeContainer< Long > scl = new SomeContainer<>(); Long l = scl.createContents(); System.out.println( l ); } }
從Java教程-泛型限制 : ide
沒法建立類型參數的實例 函數
您不能建立類型參數的實例。 例如,如下代碼會致使編譯時錯誤: 性能
public static <E> void append(List<E> list) { E elem = new E(); // compile-time error list.add(elem); }
解決方法是,能夠經過反射建立類型參數的對象: ui
public static <E> void append(List<E> list, Class<E> cls) throws Exception { E elem = cls.newInstance(); // OK list.add(elem); }
您能夠按如下方式調用append方法: this
List<String> ls = new ArrayList<>(); append(ls, String.class);
我覺得我能夠作到,但很失望:這行不通,但我仍然值得分享。 spa
也許有人能夠糾正:
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; interface SomeContainer<E> { E createContents(); } public class Main { @SuppressWarnings("unchecked") public static <E> SomeContainer<E> createSomeContainer() { return (SomeContainer<E>) Proxy.newProxyInstance(Main.class.getClassLoader(), new Class[]{ SomeContainer.class }, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Class<?> returnType = method.getReturnType(); return returnType.newInstance(); } }); } public static void main(String[] args) { SomeContainer<String> container = createSomeContainer(); [*] System.out.println("String created: [" +container.createContents()+"]"); } }
它產生:
Exception in thread "main" java.lang.ClassCastException: java.lang.Object cannot be cast to java.lang.String at Main.main(Main.java:26) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:601) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
第26行是帶有[*]
。
惟一可行的解決方案是@JustinRudd提供的解決方案
若是須要在泛型類中使用類型參數的新實例,則使構造函數須要其類...
public final class Foo<T> { private Class<T> typeArgumentClass; public Foo(Class<T> typeArgumentClass) { this.typeArgumentClass = typeArgumentClass; } public void doSomethingThatRequiresNewT() throws Exception { T myNewT = typeArgumentClass.newInstance(); ... } }
用法:
Foo<Bar> barFoo = new Foo<Bar>(Bar.class); Foo<Etc> etcFoo = new Foo<Etc>(Etc.class);
優勢:
缺點:
Foo<L>
證實。 首先,若是類型實參類沒有默認構造函數,則newInstance()
將引起搖擺器。 不管如何,這確實適用於全部已知的解決方案。 您能夠用一個類加載器和類名,最後加上一些參數。
final ClassLoader classLoader = ... final Class<?> aClass = classLoader.loadClass("java.lang.Integer"); final Constructor<?> constructor = aClass.getConstructor(int.class); final Object o = constructor.newInstance(123); System.out.println("o = " + o);