103 votes

Pourquoi devrais-je me soucier du fait que Java n'a pas de génériques réifiés?

C'est venu comme une question j'ai demandé dans une interview récemment que quelque chose le candidat souhaité voir ajouter au langage Java. Il est communément identifié comme une douleur que Java n'a pas réifiée les génériques mais, quand on le pousse, le candidat ne pouvais pas vraiment me dire le genre de choses qu'il aurait pu étaient-ils là.

Bien sûr, parce que raw types sont admissibles en Java (et dangereux contrôles), il est possible de subvertir les génériques et jusqu'à la fin avec un List<Integer> que (par exemple) contient Strings. De toute évidence, cela pourrait être rendue impossible ont des informations de type réifiée; mais il doit y avoir plus que cela!

Des gens pourraient publier des exemples de choses qu' ils veulent vraiment faire, ont été réifiée génériques disponibles? Je veux dire, évidemment, vous pourriez obtenir le type d'une List lors de l'exécution - mais que voulez-vous faire avec ça?

public <T> void foo(List<T> l) {
   if (l.getGenericType() == Integer.class) {
       //yeah baby! err, what now?

EDIT: UNE mise à jour rapide de ce que les réponses semblent surtout préoccupés par la nécessité de passer en Class comme un paramètre (par exemple, EnumSet.noneOf(TimeUnit.class)). J'étais à la recherche de plus pour quelque chose le long des lignes de , où ce n'est tout simplement pas possible. Par exemple:

List<?> l1 = api.gimmeAList();
List<?> l2 = api.gimmeAnotherList();

if (l1.getGenericType().isAssignableFrom(l2.getGenericType())) {
    l1.addAll(l2); //why on earth would I be doing this anyway?

101voto

RHSeeger Points 9217

Ce qui m’inquiète le plus souvent, c’est l’incapacité de tirer parti de plusieurs envois répartis entre plusieurs types génériques. Ce qui suit n'est pas possible et il existe de nombreux cas où ce serait la meilleure solution:

 public void my_method(List<String> input) { ... }
public void my_method(List<Integer> input) { ... }
 

81voto

BalusC Points 498232

Les quelques fois que je suis tombé sur ce "besoin", il revient finalement à cette construction:

public class Foo<T> {

    private T t;

    public Foo() {
        this.t = new T(); // Help?
    }

}

Ceci fonctionne en C# en supposant qu' T a un défaut constructeur. Vous pouvez même obtenir le runtime type en typeof(T) et obtenir les constructeurs en Type.GetConstructor().

La commune de Java solution serait de passer l' Class<T> comme argument.

public class Foo<T> {

    private T t;

    public Foo(Class<T> cls) throws Exception {
        this.t = cls.newInstance();
    }

}

(il ne doit pas nécessairement être passé en argument du constructeur, comme un argument de méthode est aussi très bien, ce qui précède est juste un exemple, aussi le try-catch est omis par souci de concision)

35voto

gustafc Points 13552

Type de sécurité vient à l'esprit. De passer à un paramétrées type sera toujours dangereux sans réifiée génériques:

List<String> myFriends = new ArrayList();
myFriends.add("Alice");
getSession().put("friends", myFriends);
// later, elsewhere
List<Friend> myFriends = (List<Friend>) getSession().get("friends");
myFriends.add(new Friend("Bob")); // works like a charm!
// and so...
List<String> myFriends = (List<String>) getSession().get("friends");
for (String friend : myFriends) print(friend); // ClassCastException, wtf!?

Aussi, les abstractions serait fuite de moins - au moins ceux qui peuvent être intéressés par des informations d'exécution sur leurs paramètres de type. Aujourd'hui, si vous avez besoin de tout type de moteur d'exécution d'informations sur le type de l'un des paramètres génériques, vous devez passer ses Class . De cette façon, votre interface externe dépend de votre application (si vous utilisez RTTI sur vos paramètres ou pas).

27voto

Turnor Points 1376

Vous seriez capable de créer des tableaux génériques dans votre code.

 public <T> static void DoStuff() {
    T[] myArray = new T[42]; // No can do
}
 

11voto

sateesh Points 7967

Mon exposition à Java Geneircs est assez limité, et mis à part les points de d'autres réponses ont déjà mentionné qu'il y avait un scénario expliqué dans le livre de Java Génériques et Collections, par Maurice nick naftalin et Philip Walder, où la réifiée génériques sont utiles.

Depuis les types ne sont pas reifiable, il n'est pas possible d'avoir Paramétré les exceptions.

Par exemple la déclaration du formulaire ci-dessous n'est pas valide.

class ParametericException<T> extends Exception // compile error

C'est parce que le catch clause vérifie si la levée d'une exception correspond à un type donné. Cette case est la même que la vérification effectuée par l'instance d'essai et depuis le type n'est pas reifiable le formulaire ci-dessus de déclaration n'est pas valide.

Si le code ci-dessus est valide ensuite la gestion des exceptions dans le ci-dessous de manière aurait été possible:

try {
     throw new ParametericException<Integer>(42);
} catch (ParametericException<Integer> e) { // compile error
  ...
}

Le livre mentionne aussi que si Java génériques sont définis de la même façon les modèles C++ sont défini (expansion), cela peut conduire à une mise en œuvre efficace que cela offre plus de les possibilités d'optimisation. Mais n'offre pas d'explication plus que cela, de sorte que toute explication (pointeurs) à partir de la connaissance des gens seraient utiles.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X