663 Stimmen

Instanz eines generischen Typs in Java erstellen?

Ist es möglich, eine Instanz eines generischen Typs in Java zu erstellen? Basierend auf dem, was ich gesehen habe, denke ich, dass die Antwort lautet no ( aufgrund von Schriftlöschung ), aber es würde mich interessieren, ob jemand etwas sieht, das ich übersehe:

class SomeContainer<E>
{
    E createContents()
    {
        return what???
    }
}

EDIT: Es hat sich herausgestellt, dass Supertyp-Marken könnte verwendet werden, um mein Problem zu lösen, aber es erfordert eine Menge von Reflexion-basierten Code, wie einige der Antworten unten angegeben haben.

Ich werde das Thema noch eine Weile offen lassen, um zu sehen, ob jemand mit etwas kommt, das sich von Ian Robertsons Artima Artikel .

3 Stimmen

Habe gerade die Leistung auf einem Android-Gerät getestet. 10000 Operationen und: 8-9 ms dauert new SomeClass(), 9-11 ms dauert Factory<SomeClass>.createInstance() und 64-71 ms dauert shortest reflection: SomeClass z = SomeClass.class.newInstance(). Und alle Tests waren in einem einzigen try-catch-Block. Reflection newInstance() wirft 4 verschiedene Ausnahmen, erinnern Sie sich? Also habe ich beschlossen, das Factory-Muster zu verwenden

0 Stimmen

4 Stimmen

Mit Java 8 können Sie nun eine Konstruktorreferenz oder ein Lambda übergeben, wodurch dieses Problem ziemlich einfach zu umgehen ist. Siehe meine Antwort unten für Einzelheiten.

4voto

cacheoff Punkte 81

Verwenden Sie die TypeToken<T> Klasse:

public class MyClass<T> {
    public T doSomething() {
        return (T) new TypeToken<T>(){}.getRawType().newInstance();
    }
}

1 Stimmen

Wenn Sie Guava statt GSON verwenden, sieht die Sache ein wenig anders aus: (T) new TypeToken<T>(getClass()){}.getRawType().newInstance();

3voto

Luigi R. Viggiano Punkte 8381

Ich dachte, ich könnte das tun, aber ich bin ziemlich enttäuscht: Es funktioniert nicht, aber ich denke, es ist es trotzdem wert, dass man es teilt.

Vielleicht kann mich jemand korrigieren:

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()+"]");

    }
}

Sie produziert:

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)

Zeile 26 ist die Zeile mit dem [*] .

Die einzige praktikable Lösung ist die von @JustinRudd

3voto

Amio.io Punkte 19007

Eine Erweiterung der Antwort von @Noah.

Grund für die Änderung

a] Es ist sicherer, wenn mehr als 1 generischer Typ verwendet wird, falls Sie die Reihenfolge ändern.

b] Eine generische Typsignatur einer Klasse ändert sich von Zeit zu Zeit, so dass Sie zur Laufzeit nicht von unerklärlichen Ausnahmen überrascht werden.

Robuster Code

public abstract class Clazz<P extends Params, M extends Model> {

    protected M model;

    protected void createModel() {
    Type[] typeArguments = ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments();
    for (Type type : typeArguments) {
        if ((type instanceof Class) && (Model.class.isAssignableFrom((Class) type))) {
            try {
                model = ((Class<M>) type).newInstance();
            } catch (InstantiationException | IllegalAccessException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

Oder verwenden Sie den One-Liner

Einzeiliger Code

model = ((Class<M>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[1]).newInstance();

3voto

Sudhanshu Jain Punkte 2121

Was Sie tun können, ist -

  1. Deklarieren Sie zunächst die Variable dieser generischen Klasse

    2. dann einen Konstruktor dafür erstellen und dieses Objekt instanziieren

  2. Dann verwenden Sie es, wo immer Sie es verwenden möchten

Beispiel -

1

private Class<E> entity;

2

public xyzservice(Class<E> entity) {
        this.entity = entity;
    }

public E getEntity(Class<E> entity) throws InstantiationException, IllegalAccessException {
        return entity.newInstance();
    }

3.

E e = getEntity(Entität);

1 Stimmen

Return entity.newInstance(); löst eine Warnung aus: "Die Methode newInstance() vom Typ Class<E> ist seit Version 9 veraltet"

1voto

Jonathan Punkte 5518

Hier ist eine Implementierung von createContents die die TypeTools um die rohe Klasse aufzulösen, die durch E :

E createContents() throws Exception {
  return TypeTools.resolveRawArgument(SomeContainer.class, getClass()).newInstance();
}

Dieser Ansatz funktioniert nur, wenn SomeContainer ist unterklassig, so dass der tatsächliche Wert von E wird in einer Typdefinition festgehalten:

class SomeStringContainer extends SomeContainer<String>

Andernfalls wird der Wert von E zur Laufzeit gelöscht und ist nicht wiederherstellbar.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X