una telefónica realizadas llamadas jtapi ejemplo desarrollar control centralita central aplicación java generics

java - telefónica - ¿Cuál es el punto de permitir testigos de tipo en todas las llamadas de método?



desarrollar una aplicación de control de llamadas realizadas en una centralita telefónica (4)

¿Se pregunta por qué "Type Witness" fue lanzado en Java? :RE

Para entender esto debemos comenzar la historia desde http://docs.oracle.com/javase/tutorial/java/generics/genTypeInference.html .

La inferencia de tipos es la capacidad de un compilador de Java de analizar cada invocación de método y la declaración correspondiente para determinar el tipo de argumento (o argumentos) que hacen que la invocación sea aplicable. El algoritmo de inferencia determina los tipos de los argumentos y, si está disponible, el tipo que se asigna o devuelve el resultado . Finalmente, el algoritmo de inferencia intenta encontrar el tipo más específico que funciona con todos los argumentos.

Si el algoritmo anterior aún no es capaz de determinar el tipo, tenemos el "Testigo de tipo" para indicar explícitamente qué tipo necesitamos. Por ejemplo:

public class TypeWitnessTest { public static void main(String[] args) { print(Collections.emptyList()); } static void print(List<String> list) { System.out.println(list); } }

El código anterior no compila:

TypeWitnessTest.java:11: error: method print in class TypeWitnessTest cannot be applied to given types; print(Collections.emptyList()); ^ required: List<String> found: List<Object> reason: actual argument List<Object> cannot be converted to List<String> by method invocation conversion 1 error

Entonces, tienes un Testigo Tipo para rescatar de esto:

public class TypeWitnessTest { public static void main(String[] args) { print(Collections.<String>emptyList()); } static void print(List<String> list) { System.out.println(list); } }

Esto es compilable y funciona bien, sin embargo, se ha mejorado más en Java 8 :
JEP 101: Inferencia de tipo objetivo generalizada

PD: comencé a partir de los fundamentos para que otros lectores de StackOverflow también puedan beneficiarse.

EDITAR :

Escriba Testigo en Testigo no genérico!

public class InternetTest { public static void main(String[] args) { String s; s = Internet.<String>genericReturn(); //Witness used in return type, returns a string s = Internet.<Integer>stringReturn(); //Witness ignored, returns a string } } class Internet { public static <T> T genericReturn() { return null; } public static String stringReturn() { return null; } }

Intenté simular el ejemplo de @Rogue usando javac 1.6.0_65 pero falla la compilación con el siguiente error:

javac InternetTest.java InternetTest.java:5: stringReturn() in Internet cannot be applied to <java.lang.Integer>() s = Internet.<Integer>stringReturn(); //Witness ignored, returns a string ^ 1 error

@Rogue: Si estaba usando una versión anterior a la que yo usé, entonces hágame saber su versión javac. Y si estabas entonces no está permitido ahora. :PAG

Digamos que tenemos dos métodos como los siguientes:

public static <T> T genericReturn() { /*...*/ } public static String stringReturn() { /*...*/ }

Al llamar a cualquier método, puede proporcionar el tipo testigo independientemente de si existe o no algún requisito:

String s; s = Internet.<String>genericReturn(); //Type witness used in return type, returns a String s = Internet.<Integer>stringReturn(); //Type witness ignored, returns a String

Sin embargo, no estoy viendo ningún uso realista para esto en Java, a menos que no se pueda inferir el tipo (lo que generalmente es indicativo de un problema mayor). Además, el hecho de que simplemente se ignore cuando no se usa adecuadamente parece ser contrario a la intuición. Entonces, ¿cuál es el punto de tener esto en Java en absoluto?


De la JLS §15.2.12.1 :

  • Si la invocación del método incluye argumentos de tipo explícito y el miembro es un método genérico, entonces el número de argumentos de tipo es igual al número de parámetros de tipo del método.

Esta cláusula implica que un método no genérico puede ser potencialmente aplicable a una invocación que proporciona argumentos de tipo explícito. De hecho, puede resultar aplicable. En tal caso, los argumentos de tipo simplemente serán ignorados.

Es seguido por la justificación.

Esta regla se deriva de cuestiones de compatibilidad y principios de sustituibilidad. Como las interfaces o las superclases pueden generarse independientemente de sus subtipos, podemos anular un método genérico con uno no genérico. Sin embargo, el método de anulación (no genérico) debe ser aplicable a las llamadas al método genérico, incluidas las llamadas que pasan explícitamente los argumentos de tipo. De lo contrario, el subtipo no sería sustituible por su supertipo generado.

En esta línea de razonamiento, construyamos un ejemplo. Supongamos que en Java 1.4, JDK tiene una clase

public class Foo { /** check obj, and return it */ public Object check(Object obj){ ... } }

Algunos usuarios escribieron una clase propietaria que extiende Foo y anula el método de check

public class MyFoo extends Foo { public Object check(Object obj){ ... } }

Cuando Java 1.5 introdujo los genéricos, Foo.check se genera como

public <T> T check(T obj)

El ambicioso objetivo de comparabilidad hacia atrás requiere que MyFoo aún MyFoo en Java 1.5 sin modificaciones; y MyFoo.check[Object->Object] sigue siendo un método de Foo.check[T->T] de Foo.check[T->T] .

Ahora, de acuerdo con la anterior justificación, ya que esta compila:

MyFoo myFoo = new MyFoo(); ((Foo)myFoo).<String>check("");

Esto debe compilar también:

myFoo.<String>check("");

a pesar de que MyFoo.check no es genérico.

Eso suena como un estiramiento. Pero incluso si compramos ese argumento, la solución sigue siendo demasiado amplia y exagerada. JLS podría haberlo myFoo.<String,String>check para que myFoo.<String,String>check y obj.<Blah>toString() sean ilegales, porque la aridad de los parámetros de tipo no coincide. Probablemente no tuvieron tiempo de arreglarlo, así que simplemente tomaron una ruta simple.


Es debido a la compatibilidad con versiones anteriores y / o posteriores (en el nivel de origen).

Imagine algo como la introducción de parámetros genéricos para algunas clases en Swing en JDK 7. También puede ocurrir con métodos (incluso con restricciones). Si algo resultó ser una mala idea, puede eliminarlos y la fuente que lo usa aún se compilará. En mi opinión, esa es la razón por la que esto está permitido, incluso si no se utiliza.

Aunque la flexibilidad es limitada. Si introdujo parámetros de tipo con n tipos, no podrá cambiar posteriormente a m tipos (de una forma compatible con la fuente) si m != 0 o m != n

(Entiendo que esto podría no responder a tu pregunta, ya que no soy el diseñador de Java, esta es solo mi idea / opinión).


Necesita el tipo testigo (el tipo en el diamante) cuando la inferencia de tipo no funcionará (consulte http://docs.oracle.com/javase/tutorial/java/generics/genTypeInference.html )

El ejemplo dado para esto es cuando las llamadas en cadena como:

processStringList(Collections.emptyList());

donde se define processStringList como:

void processStringList(List<String> stringList) { // process stringList }

Esto generará un error porque no puede convertir una List<Object> en una List<String> . Por lo tanto, se requiere el testigo. A pesar de que puede hacer esto en varios pasos, pero esto puede ser mucho más conveniente.