Para entender este puzzle se necesita conocer lo mínimo de la JCF (Java Collection Framework).
El tema es el siguiente, resulta que a partir de la versión 1.2 de Java existe un framework de colecciones denominado JCF (Java Collection Framework) realizado en mayor parte por Josh Bloch, que dicho sea de paso es el autor del libro Effective Java (espero que conozca el libro).
Este framework provee muchas clases para manejar estructuras de datos y facilitar la vida al desarrollador. Una de estas tantas clases se denomina TreeSet. Esta clase representa un conjunto en forma de árbol y posee 4 constructores, prestar atención aquí:
1) TreeSet()
2) TreeSet(Collection<? extends E> coll)
3) TreeSet(Comparator<? super E> comp)
4) TreeSet(SortedSet<E> ss)
Puede verlo desde la documentación oficial aquí.
Para este puzzle sólo nos interesa el segundo y el cuarto constructor. El que recibe un Collection y el que recibe un SortedSet.
Ahora bien, para entender este puzzle, hay que tener en cuenta la jerarquía del TreeSet, es decir, ¿Qué interfaces implementa? ¿Qué clases extiende?
Como siempre lo puede ver de su documentación oficial (link de arriba) o bien verlo aquí mismo.
Jerarquía de clases:
Object
AbstractCollection<E>
AbstractSet<E>
TreeSet<E>
Interfaces que implementa:
Serializable, Cloneable, Iterable<E>, Collection<E>, NavigableSet<E>, Set<E>, SortedSet<E>.
Son varias interfaces que implementa pero ponga atención en la interfaz Collection y en la interfaz SortedSet, ¿las recuerda?... Son las mismas que necesitan los constructores del TreeSet. ¿Entiende por donde va la mano del puzzle?
Entonces reordenando un poco, recuerde los 2 constructores que dejamos al margen, es decir, el que recibe un objeto que implemente Collection y el que recibe un objeto que implemente SortedSet. Ambos constructores reciben una interfaz, pero estas interfaces son implementadas por la clase TreeSet.
¡Ambas interfaces (Collection y SortedSet) son implementadas por TreeSet y a su vez son necesarias en 2 de sus constructores!.
Si le paso un objeto TreeSet al contructor de otro TreeSet, ¿Cómo distingue el constructor a ejecutar? ¿Ejecuta el constructor de Collection porque TreeSet implementa Collection? pero... ¿TreeSet también implementa SortedSet entonces ejecuta el constructor de SortedSet? ¿Qué pasa?
Con esta larga introducción pasamos al código:
import java.util.*;
public class ConstructoresAmbiguos{
public static void main(String args[]){
TreeSet<String> ts = new TreeSet<>();
if(ts instanceof SortedSet){
System.out.println("true");
}
if(ts instanceof Collection){
System.out.println("true");
}
TreeSet<String> ts2 = new TreeSet<>(ts);
System.out.println("FIN");
}
}
El anterior código muestra el programa del puzzle. ¿Qué constructor se ejecutó? El TreeSet es tanto SortedSet y Collection, sin embargo el programa se ejecutó con éxito. ¿Qué ocurrió?
Luego, pruebe con el siguiente código que simula la situación planteada del TreeSet y vea que no compila por referencia ambigua...
public static void main(String args[]){
A a = new A();
A a2 = new A(a);
}
}
class A implements B, C{
public A(){}
public A(B b){}
public A(C c){}
}
interface B{}
interface C{}
¿Y ahora?... ¿Qué está pasando acá? ¿Acaso Java hace trampa con las clases del JCF?
No hay comentarios:
Publicar un comentario