web-dev-qa-db-fra.com

Extension des classes génériques

public class MyGeneric<T, E> {}

public class Extend1<T, E> extends MyGeneric<T, E> {}

public class Extend2 extends MyGeneric<String, Object> {}

Pour autant que je sache, les deux sous-classes de l'exemple ci-dessus sont valides. Je me demandais comment Java sait quand les types donnés dans la superclasse vont être définis quand la sous-classe est instanciée, et quand ce sont des noms de classe réels (ie Comment sait-il que T, E sont pas des noms de classe)?

Remarque: est-il permis (même si cela n'est pas courant) d'utiliser plus d'une lettre pour les types génériques? Que faire si (par une erreur grave de planification) Les types entrent en conflit avec une classe existante, par ex.

public class E{}
public class Foo<E>{}

que se passe-t-il alors?

Edit: Merci d'avoir répondu si rapidement. Pour répondre à ma première question, réponse de Joachim est le plus efficace.

Pour répondre au point de côté, la réponse d'Aioobe est plus claire

52
James

Regardons cette définition:

public class Extend1<T, E> extends MyGeneric<T, E> {}

Ici T et E sont chacun présents deux fois et dans deux rôles différents

  • dans Extend1<T,E> vous définissez des arguments de type. Cela signifie que le type Extend1 a deux arguments de type (non limités) T et E. This indique au Java que ceux qui utilisent Extend1 besoin de spécifier les types.
  • dans extends MyGeneric<T,E> vous utilisez les arguments de type définis précédemment. Si T et E n'étaient pas connus pour être des arguments de type ici, alors T et E seraient de simples références de type, c'est-à-dire que le compilateur chercherait des classes (ou interfaces, ...) nommées T et E (et très probablement pas les trouver).

Oui, les arguments de type suivent les mêmes règles syntaxiques que tout autre identifiant en Java, vous pouvez donc utiliser plusieurs lettres ABC ou même des noms qui peuvent prêter à confusion (l'utilisation d'un argument de type appelé String est légale, mais hautement déroutant).

Les noms d'argument de type lettre unique sont simplement une stratégie de dénomination très courante.

58
Joachim Sauer

Je me demandais comment Java sait quand les types donnés dans la superclasse vont être définis quand la sous-classe sera instansiée, et quand ils le seront) noms de classe réels (c'est-à-dire comment sait-il que T, E ne sont pas des noms de classe)?

Java s'en fiche. Si tu fais...

class MyGeneric<String> extends ArrayList<String> {
    String value;
}

est-il permis (même si cela n'est pas courant) d'utiliser plus d'une lettre pour les types génériques? Et si (à cause d'une grave erreur de planification) Les types entrent en conflit avec une classe existante, par exemple

Oui, vous pouvez utiliser n'importe quel identifiant Java Java valide pour les paramètres de type.

Les noms peuvent être en conflit, mais Java ne traitera pas cela comme une erreur. Les identifiants entre <...> sera toujours traité comme des paramètres de type, que l'identifiant corresponde à un nom de classe.

Cela peut devenir assez déroutant. Voici un exemple:

class MyGeneric<String> extends Java.util.ArrayList<String> {
    String value;
}

class Test {
    public static void main(String... args) throws Exception {
        MyGeneric<Integer> obj = new MyGeneric<Integer>();
        obj.value = 5;
        //          ^
        //          |
        //          '--- Assign an integer to what seems to be a String!
    }
}

Question similaire:

22
aioobe

Il n'y a aucun problème avec:

public class E{}
public class Foo<E>{}

Parce que dans le contexte de Foo<E>, E est un type.

2
Bohemian