37 votes

Affectation Liste d'Entier Dans une Liste de Chaîne de caractères

J'étais d'apprentissage Génériques en Java et je suis venu près d'une pièce très intéressante de code. Je sais en Java, il est illégal d'ajouter la liste d'un type à l'autre.

List<Integer> integerList = new ArrayList<Integer>();
List<String> stringList=integerList;

Ainsi, dans la deuxième ligne, j'obtiens une erreur de compilation.
Mais si je crée une méthode générique à l'intérieur d'une classe comme ça,

class  GenericClass <E>{
    void genericFunction(List<String> stringList) {
        stringList.add("foo");
    }
    // some other code
}

Et dans la classe principale appeler la méthode avec la liste d'Entier, je n'obtiens pas d'erreur.

public class Main {
  public static void main(String args[]) {

     GenericClass genericClass=new GenericClass();
     List<Integer> integerList= new ArrayList<Integer>();
     integerList.add(100);
     genericClass.genericFunction(integerList);
     System.out.println(integerList.get(0));
     System.out.println(integerList.get(1));
  }
}

Sortie
100
foo

Pourquoi je n'obtiens pas d'erreur?

23voto

Daniel Points 1302

Vous n'êtes pas obtenir toute erreur de compilation car en utilisant GenericClass<E> brut moyen :

GenericClass genericClass = new GenericClass();,

vous êtes pratiquement dire au compilateur de désactiver type générique vérifications parce que vous n'avez pas de soins.

Si l' :

void genericFunction(List<String> stringList)

devient

void genericFunction(List stringList) pour le compilateur.

Vous pouvez essayer la procédure suivante : GenericClass<?> genericClass , et vous remarquerez immédiatement que le compilateur prend conscience des médicaments génériques, la mauvaise utilisation, et il va vous montrer le message d'erreur :

The method genericFunction(List<String>) in the type GenericClass<capture#1-of ?> is not applicable for the arguments (List<Integer>)

Aussi, si vous essayez d'obtenir la classe de la 2e position de l'objet au moment de l'exécution:

System.out.println(integerList.get(1).getClass());

vous recevrez un message d'erreur: java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer.

19voto

Braj Points 28874

Vous avez mélangé Générique avec raw type. Elle compile bien, mais au moment de l'exécution, il peut échouer à cause d'une information Générique est perdu au moment de l'exécution.

Générique doit être utilisé pour suivre de tels bugs au moment de la compilation.

C'est mieux expliqué à qu'est Ce qu'une crue de type et pourquoi ne pas l'utiliser? dans le détail.


Avertissement: Type de sécurité: La méthode genericFunction(List) appartient à la crue de type GenericClass. Références de type générique GenericClass<E> devrait être paramétrable.

Si vous disposez de deux méthodes avec le même nom avec différents type Générique de la Liste puis c'erreur de compilation. Le compilateur ne peut pas résoudre de type Générique dans le cas de la méthode des arguments qui peuvent être prouvée par ci-dessous un exemple de code.

Exemple de code: (erreur du compilateur - pas valide méthode surchargée)

void genericFunction(List<String> stringList){...}
void genericFunction(List<Integer> stringList){...}

Faire quelques changements et essayer à nouveau:

class  GenericClass <E>{
    void genericFunction(List<E> stringList) {
        ...
    }
    // some other code
}

...

GenericClass<String> genericClass=new GenericClass<String>(); // Genreric object
List<Integer> integerList= new ArrayList<Integer>();
integerList.add(100);
genericClass.genericFunction(integerList); // compile time error

Créer des méthodes de sorte

class GenericClass<E> {
    private List<E> list = new ArrayList<E>();

    public void addAll(List<E> newList) {
        list.addAll(newList);
    }

    public void add(E e) {
        list.add(e);
    }

    public E get(int index) {
        return list.get(index);
    }
    // some other code
}

12voto

skiwi Points 8321

Ce qui se passe, parce que (ce qui est très surprenant pour moi), vous avez désactivé générique type de vérification pour l' ensemble de l' GenericClass classe.

Vous devez être conscient que vous êtes, tout d'abord, la construction d'une classe générique, sans argument de type ici:

GenericClass genericClass = new GenericClass();

Et appereantly, de ce fait, votre code suivant:

class GenericClass<E> {
    void genericFunction(List<String> stringList) {
        stringList.add("foo");
    }
    // some other code
}

obtenu raffiné à:

class GenericClass {
    void genericFunction(List stringList) {
        stringList.add("foo");
    }
    // some other code
}

Notez que List également devenu une crue de type, ce qui est plutôt surprenant pour moi.

Vous pouvez trouver la réponse ici, la référence à la JLS: http://stackoverflow.com/a/662257/2057294 comme l'explique Jon Skeet.

Je pense qu'il est juste que ce qui se passe (bien que pas ce que vous attendez), parce que si vous décidez d'utiliser des types, il est supposé que vous êtes à l'aide de Java 4 ou moins et n'ont pas accès à tous à des génériques de toute façon, de sorte qu'il peut aussi bien ne pas leur fournir des méthodes n'impliquant pas le type générique de la classe qui les a effacées.

6voto

webuster Points 1845

Pour ajouter d'autres réponses.

En effet, vous êtes le mélange brut (unparameterized) type de type paramétré qui provoque une perte de type et apparemment correct argument de passage à l' genericFunction lorsque le type de contrôles de sécurité ne doit pas vous permettre de.

Reste la question sur le pourquoi de l' List<String> type est perdu dans un unparameterized GenericClass objet. La raison pour laquelle le compilateur "désactive l'option" vérification de type, dans votre cas, est le type d'effacement mécanisme, qui dit (en termes simples) crus à l'objet appartient à une classe avec le contenu suivant:

class  GenericClass {
    void genericFunction(List stringList) {
        stringList.add("foo");
    }
    // some other code
}

Qui, comme vous le voyez ne pas faire n'importe quel type vérifie que ce soit sur le contenu de la liste étant passé (il efface les paramètres de type partout). Même plus, le type d'effacement également efface votre paramétré le type de l' integerList variable, ce qui le rend parfaitement adapté comme un argument pour votre genericFunction méthode.

Donc, comme d'autres l'ont souligné, il est toujours préférable d'aider à Java maintenir la sécurité de la vérification de type mécanismes intacte:

     GenericClass<?> genericClass=new GenericClass<Integer>();
     List<Integer> integerList= new ArrayList<Integer>();
     integerList.add(100);
     // no-no here
     genericClass.genericFunction(integerList);
     System.out.println(integerList.get(0));
     System.out.println(integerList.get(1));

Mais là encore, si vous le faites, le compilateur fait son travail et va bazooka sur vous.

Lire plus sur le type d'effacement ici. C'est une fonctionnalité intéressante qui permet de générique vérification de type, tout en gardant la compatibilité descendante avec les pré-génériques versions de Java.

0voto

Rahul Tripathi Points 64
class  GenericClass <E>{
    void genericFunction(List<String> stringList) {
        stringList.add("foo");
    }
    // some other code
}

lorsque vous écrivez juste après le nom de la classe.Il spécifie les paramètres de type.Ses une fonctionnalité générique.Cela introduit la variable de type E, qui peut être utilisé n'importe où à l'intérieur de la classe. Une variable de type peut être n'importe quel non-type primitif, vous indiquez: tout type de classe, tout type d'interface, tout type de tableau, ou même un autre type de variable.

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