Wie erhalte ich das Attribut `.class` von einem generischen Typparameter?

70

Die akzeptierte Antwort auf diese Frage beschreibt, wie eine Instanz von Tin der Generic<T>Klasse erstellt wird. Dies beinhaltet die Übergabe eines Class<T>Parameters an den GenericKonstruktor und das Aufrufen der newInstanceMethode von diesem.

Generic<Bar>Anschließend wird eine neue Instanz von erstellt und der Parameter Bar.classübergeben.

Was tun Sie, wenn der generische Typparameter für die neue GenericKlasse keine bekannte Klasse ist, Barsondern selbst ein generischer Typparameter ist? Angenommen, ich hätte eine andere KlasseSkeet<J> und wollte eine neue Instanz Generic<J>innerhalb dieser Klasse erstellen . Wenn ich dann versuche, weiterzugeben, J.classerhalte ich den folgenden Compilerfehler:

cannot select from a type variable.

Gibt es einen Weg daran vorbei?

Das spezifische Codebit, das den Fehler für mich auslöst, ist:

public class InputField<W extends Component & WidgetInterface>
                                                 extends InputFieldArray<W>
{
  public InputField(String labelText)
  {
    super(new String[] {labelText}, W.class);
  }
  /* ... */
}

public class InputFieldArray<W extends Component & WidgetInterface>
                                                                 extends JPanel
{
   /* ... */
  public InputFieldArray(String[] labelText, Class<W> clazz)
                          throws InstantiationException, IllegalAccessException
  {
    /* ... */

    for (int i = 0 ; i < labelText.length ; i++) {
      newLabel = new JLabel(labelText[i]);
      newWidget = clazz.newInstance();
      /* ... */
    }
    /* ... */
  }
  /* ... */
}

Der Fehler tritt auf, weil ich nicht schreiben kann W.class. Gibt es eine andere Möglichkeit, dieselben Informationen weiterzugeben?

John Gowers
quelle
Ihre Frage ist möglicherweise klarer, wenn Sie ein Codebeispiel veröffentlichen (dh das, das den Compilerfehler auslöst).
Duncan Jones
Aber Sie müssen den Klassennamen Skeet<J>richtig haben? Sie müssen diese Klasse an den GenericKonstruktor übergeben. Wenn Sie den tatsächlichen Code anzeigen, können wir Ihnen besser helfen.
Rohit Jain
Sie können J.classwegen Löschung des Typs nicht verwenden . Aber Sie können konkrete ClassVariable auf Skeet<J>Bau bekommen
RiaD
Bei der verknüpften Frage meinte Jon nicht wörtlich T.class- Sie können sie nicht .classfür Typparameter verwenden. Er meinte, ein Class<T>müsste vom Anrufer übergeben werden.
Paul Bellora
Ich weiß. Ich möchte jedoch in der Klasse von bestehen können J. Ist das möglich?
John Gowers

Antworten:

63

Die Verwendung .classauf einem Typparameter ist nicht zulässig - wegen Typ Löschung , Wwird wurde gelöscht , um Componentzur Laufzeit. InputFieldmuss auch eine Class<W>vom Anrufer nehmen, wie InputFieldArray:

public InputField(String labelText, Class<W> clazz)
{
    super(new String[] {labelText}, clazz);
}
Paul Bellora
quelle
Basierend auf dem angegebenen Typ-Löschlink wird der generische Typ durch den Typ ersetzt, Objectda in diesem Fall keine Bindung angegeben ist. Da Typ Classdie Unterklasse von ist Object, können wir in diesem Fall wahrscheinlich nicht aufrufen .class. Aber was ist, wenn die angegebene Grenze nicht ist Object( <? extends Foo>ich meine, die Methode .classsollte in diesem Fall noch auswählbar sein. Ich bin hier ein bisschen verwirrt. @Paul Bellora
Träumer
@Dreamer .classist keine Methode oder etwas, das zur Laufzeit dynamisch aufgelöst werden kann. Es ist ein Konstrukt zur Kompilierungszeit, mit dem das ClassObjekt, das einen expliziten konkreten Typ darstellt , statisch abgerufen wird .
Paul Bellora
11

Wenn Sie die GSONBibliothek verwenden, können Sie den Typ Teinfach mit verwenden TypeToken. Die Klassendokumentation finden Sie hier :

Ich habe es so gemacht:

Dies ist meine Klassendefinition:

public class ManagerGeneric <T> {}

Das ist in meiner Methode:

// Get the type of generic parameter
Type typeOfT = new TypeToken<T>(){}.getType();
// Deserialize
T data = gson.fromJson(json, typeOfT);
jdex
quelle
10

W ist möglicherweise aufgrund der Löschung nicht verfügbar. Sie sollten verlangen, dass a Class<W>an die Methode übergeben wird. Sie erhalten ein Klassenobjekt und sein generisches Objekt stellt sicher, dass Waufgrund der Kovarianz nur und keine Unterklasse übergeben wird.

public InputField(String labelText, Class<W> cls)
{
    super(new String[] {labelText}, cls);
}

wird W.classaber nicht nehmen WSubtype.class.

Nanofarad
quelle