web-dev-qa-db-fra.com

Avertissement d'affectation non cochée

J'utilise Android Studio 1.1.0.

Cela ne provoque aucun avertissement:

public static class A {
    public Map<Integer, String> getMap() {
        return null;
    }
}

public static class B {
    public void processA(A a) {
        Map<Integer, String> map = a.getMap();
    }
}

Mais rendez A générique:

public static class A<T> {
    public Map<Integer, String> getMap() {
        return null;
    }
}

Et cette ligne:

Map<Integer, String> map = a.getMap();

vous reçoit un avertissement maintenant: "Unchecked assignment: 'Java.util.Map to Java.util.Map<Java.lang.Integer, Java.lang.String>'.

Même si la signature de getMap est totalement indépendante de T et que le code est sans ambiguïté concernant les types que contient Map.

Je sais que je peux me débarrasser de l'avertissement en réimplémentant processA comme suit:

public <T> void processA(A<T> a) {
    Map<Integer, String> map = a.getMap();
}

Mais pourquoi devrais-je faire ça? Qu'est-ce que T importe ici du tout?

Donc, la question est - pourquoi l'effacement de type doit-il non seulement affecter T (ce qui est compréhensible - si je passe une instance de A, T est un inconnu ), mais aussi une signature générique "codée en dur" comme <Integer, String> dans ce cas?

26
Konrad Morawski

Dans votre deuxième cas lorsque vous le faites:

public void processA(A a)

Qu'entendez-vous par A? Est-ce que ça veut dire que A<String> ou A<List<String>> ou quoi? Vous n'utilisez peut-être rien lié au type de A, mais bon le compilateur ne sait pas ce fait. Pour le compilateur, juste A est un signe de panique.

Dans votre cas, comme vous n'avez pas spécifiquement besoin de connaître le type de A, vous pouvez:

public void processA(A<?> a) {
    Map<Integer, String> map = a.getMap();
} 

Avoir un type d'argument A<?> signifie que vous ne vous souciez pas spécifiquement du type de A et spécifiez simplement un caractère générique. Pour vous, cela signifie: tout objet de A avec n'importe quel type comme le ferait son type générique. En réalité, cela signifie que vous ne connaissez pas le type. Son inutile parce que vous ne pouvez rien faire de A de manière sécurisée comme ? peut être pratiquement n'importe quoi!

Mais selon votre corps de méthode, il est tout à fait sensé d'utiliser A<?> car nulle part dans le corps, vous avez réellement besoin du type de A

18
Jatin

Lorsque vous voulez accepter un A<T> de n'importe quel type possible T, mais n'a pas besoin de T, ceci est correctement exprimé en utilisant un caractère générique et en écrivant A<?>. Cela supprimera l'avertissement de votre code:

public void processA(A<?> a) {
    Map<Integer, String> map = a.getMap();
}

L'utilisation du type nu A n'est pas traitée de manière équivalente. Comme expliqué dans Java Language Specification , les types bruts comme celui-ci ne sont pas destinés à être utilisés dans le nouveau code:

La conversion non contrôlée est utilisée pour permettre une interopération fluide du code hérité, écrit avant l'introduction des types génériques, avec les bibliothèques qui ont subi une conversion pour utiliser la généricité (un processus que nous appelons la générification). Dans de telles circonstances (notamment les clients de Collections Framework dans Java.util), le code hérité utilise des types bruts (par exemple Collection au lieu de Collection <String>). Les expressions de types bruts sont passées comme arguments aux méthodes de bibliothèque qui utilisent des versions paramétrées de ces mêmes types que les types de leurs paramètres formels correspondants.

De tels appels ne peuvent pas être montrés statiquement sûrs dans le système de type utilisant des génériques. Le rejet de tels appels invaliderait de grands corps de code existant et les empêcherait d'utiliser des versions plus récentes des bibliothèques. À son tour, cela découragerait les vendeurs de bibliothèques de profiter de la généricité. Pour éviter une telle tournure indésirable des événements, un type brut peut être converti en une invocation arbitraire de la déclaration de type générique à laquelle le type brut se réfère. Bien que la conversion ne soit pas saine, elle est tolérée comme une concession à l'aspect pratique. Un avertissement non contrôlé est émis dans de tels cas.

9
Dan Getz