Si un jour vous voyez que ? hérite d'une classe, ne soyez pas surpris. Il s'agit bel et bien de la programmation, et plus concrétement, de l'utilisation d'un wildcard.
Le wildcard fait partie des generics. Il est utilisé comme paramètre d'instantation des types génériques. Il trouve son utilité dans les situations où en implémentant une interface, on ne sait pas sur quels paramètres on va travailler. Pour mieux comprendre, regardons l'exemple :
import java.util.List; import java.util.ArrayList; public class TestWildcard { public static void main(String[] args) { setItemsToPrint(); } public static void setItemsToPrint() { List<String> elements = new ArrayList<String>(); elements.add("test1"); elements.add("test2"); printItems(elements); } public static void printItems(List<Object> items) { for (Object o : items) { System.out.println(o); } } }
Si l'on essaie de compiler ce code, on reçoit une erreur :
TestWildcard.java:16: printItems(java.util.List<java.lang.Object>) in TestWildcard cannot be applied to (java.util.List<java.lang.String>) printItems(elements);
Pour faire marcher ce code et lui permettre d'utiliser les paramètres "universels" (Strings, Integers...), on doit faire appel à des wildcards. Cela va se traduire par ramplacer <Object> le fameux point d'interrogation. Voici le code correct :
import java.util.List; import java.util.ArrayList; public class TestWildcard { public static void main(String[] args) { setStringItemsToPrint(); setIntegerItemsToPrint(); } public static void setStringItemsToPrint() { List<String> elements = new ArrayList<String>(); elements.add("test1"); elements.add("test2"); printItems(elements); } public static void setIntegerItemsToPrint() { List<Integer> elements = new ArrayList<Integer>(); elements.add(1); elements.add(2); printItems(elements); } public static void printItems(List<?> items) { for (Object o : items) { System.out.println(o); } } }
Le wildcard peut être également couplé avec l'utilisation du polymorphisme.
import java.util.List; import java.util.ArrayList; public class TestWildcardPolymorphisme { public static void main(String[] args) { List<Pencil> penList = new ArrayList<Pencil>(); penList.add(new BlackPencil()); penList.add(new RedPencil()); penList.add(new BluePencil()); penList.add(new Rubber()); listPencils(penList); } public static void listPencils(List<? extends Pencil> pencils) { for (Pencil o : pencils) { System.out.println(o.getColor()); } } } interface Pencil { String getColor(); } class BlackPencil implements Pencil { public String getColor() { return "black"; } } class RedPencil implements Pencil { public String getColor() { return "red"; } } class BluePencil implements Pencil { public String getColor() { return "blue"; } } class Rubber { public void erase() { // do something } }
La compilation du code ci-dessus provoquera une erreur :
TestWildcardPolymorphisme.java:12: cannot find symbol symbol ee: method add(Rubber) location: interface java.util.List<Pencil> penList.add(new Rubber());
Afin de le résoudre, il faut enlever la ligne penList.add(new Rubber()); car Rubber n'implémente pas l'interface Pencil. Voici le code correct :
import java.util.List; import java.util.ArrayList; public class TestWildcardPolymorphisme { public static void main(String[] args) { List<Pencil> penList = new ArrayList<Pencil>(); penList.add(new BlackPencil()); penList.add(new RedPencil()); penList.add(new BluePencil()); // penList.add(new Rubber()); listPencils(penList); } public static void listPencils(List<? extends Pencil> pencils) { for (Pencil o : pencils) { System.out.println(o.getColor()); } } } interface Pencil { String getColor(); } class BlackPencil implements Pencil { public String getColor() { return "black"; } } class RedPencil implements Pencil { public String getColor() { return "red"; } } class BluePencil implements Pencil { public String getColor() { return "blue"; } } class Rubber { public void erase() { // do something } }