una significa que para los imagenes imagen emplea como atributos atributo agregar java inheritance dynamic-binding

java - significa - los atributos alt



Enlace dinámico de Java y anulación de método (13)

Ayer tuve una entrevista telefónica técnica de dos horas (¡que pasé, woohoo!), Pero me olvidé por completo la siguiente pregunta con respecto a la vinculación dinámica en Java. Y es doblemente desconcertante porque solía enseñar este concepto a los estudiantes de pregrado cuando era TA hace unos años, por lo que la perspectiva de que les di información errónea es un poco inquietante ...

Este es el problema que me dieron:

/* What is the output of the following program? */ public class Test { public boolean equals( Test other ) { System.out.println( "Inside of Test.equals" ); return false; } public static void main( String [] args ) { Object t1 = new Test(); Object t2 = new Test(); Test t3 = new Test(); Object o1 = new Object(); int count = 0; System.out.println( count++ );// prints 0 t1.equals( t2 ) ; System.out.println( count++ );// prints 1 t1.equals( t3 ); System.out.println( count++ );// prints 2 t3.equals( o1 ); System.out.println( count++ );// prints 3 t3.equals(t3); System.out.println( count++ );// prints 4 t3.equals(t2); } }

Afirmé que la salida debería haber sido dos instrucciones de impresión separadas desde el método equals() anulado: en t1.equals(t3) y t3.equals(t3) . El último caso es bastante obvio, y con el primer caso, aunque t1 tiene una referencia de tipo Object, se ejemplifica como tipo Test, por lo que el enlace dinámico debe llamar a la forma anulada del método.

Aparentemente no. Mi entrevistador me animó a ejecutar el programa yo mismo, y he aquí que solo había una salida del método reemplazado: en la línea t3.equals(t3) .

Mi pregunta es, ¿por qué? Como ya mencioné, aunque t1 es una referencia de tipo Object (por lo que el enlace estático invocaría el método equals() Object), el enlace dinámico debería ocuparse de invocar la versión más específica del método en función del tipo de instancia de la referencia. ¿Qué me estoy perdiendo?


Alguna nota en Dynamic Binding (DD) y Static Binding̣̣̣ (SB) después de buscar un tiempo:

1. Ejecución de la ejecución : (Ref.1)

  • DB: en tiempo de ejecución
  • SB: tiempo de compilación

2.Utilizado para :

  • DB: anulación
  • SB: sobrecarga (estática, privada, final) (Ref.2)

Referencia:

  1. Ejecutar resolver significa que método prefiere usar
  2. Porque no se puede reemplazar el método con el modificador estático, privado o final
  3. http://javarevisited.blogspot.com/2012/03/what-is-static-and-dynamic-binding-in.html

Creo que la clave está en el hecho de que el método equals () no se ajusta al estándar: toma otro objeto Test, no un objeto Object y por lo tanto no reemplaza el método equals (). Esto significa que en realidad solo lo ha sobrecargado para hacer algo especial cuando se le da Objeto de prueba mientras lo da. Llamadas de objeto objeto Object.equals (Objeto o). Buscar ese código a través de cualquier IDE debería mostrarle dos métodos equals () para Test.


Curiosamente, en el código de Groovy (que podría compilarse en un archivo de clase), todas menos una de las llamadas ejecutarían la instrucción de impresión. (El que compara una Prueba con un Objeto claramente no llamará a la función Test.equals (Prueba)). Esto se debe a que groovy HACE tipados completamente dinámicos. Esto es particularmente interesante porque no tiene variables explícitamente tipadas dinámicamente. He leído en un par de lugares que esto se considera perjudicial, ya que los programadores esperan que Groovy haga lo de java.


El método equals de Test no anula el método equals de java.lang.Object . ¡Mira el tipo de parámetro! La clase de Test está sobrecarga es equals a un método que acepta una Test .

Si el método equals está destinado a anularse, debe usar la anotación @Override. Esto causaría un error de compilación para señalar este error común.


El método está sobrecargado en lugar de anulado. Igual siempre toma un objeto como parámetro.

Por cierto, tienes un artículo sobre esto en el java efectivo de Bloch (que deberías tener).



Está muy claro, que no hay ningún concepto de anulación aquí. Es una sobrecarga de método. el método Object() de la clase Object toma el parámetro de referencia de tipo Object y este método equal() toma el parámetro de referencia de tipo Test.


Java no es compatible con la covarianza en los parámetros, solo en los tipos de retorno.

En otras palabras, mientras que su tipo de devolución en un método de anulación puede ser un subtipo de lo que estaba en el reemplazado, eso no es cierto para los parámetros.

Si su parámetro para iguales en Object es Object, poner un igual con cualquier otra cosa en una subclase será un método sobrecargado, no anulado. Por lo tanto, la única situación en que se llamará ese método es cuando el tipo estático del parámetro es Prueba, como en el caso de T3.

Buena suerte con el proceso de entrevista de trabajo! Me encantaría que me entrevisten en una empresa que hace este tipo de preguntas en lugar de las preguntas habituales de estructuras de datos / datos que les enseño a mis alumnos.


Java usa enlace estático para métodos sobrecargados y enlace dinámico para los reemplazados. En su ejemplo, el método equals está sobrecargado (tiene un tipo de parámetro diferente de Object.equals ()), por lo que el método llamado está vinculado al tipo de referencia en tiempo de compilación.

Alguna discusión here

El hecho de que es el método de igualdad no es realmente relevante, aparte de que es un error común sobrecargar en lugar de anularlo, que ya conoce desde su respuesta al problema en la entrevista.

Editar: una buena descripción here también. Este ejemplo muestra un problema similar relacionado con el tipo de parámetro, pero causado por el mismo problema.

Creo que si el enlace fuera realmente dinámico, entonces cualquier caso en el que el llamador y el parámetro fueran una instancia de Prueba daría como resultado que se llamara al método reemplazado. Entonces t3.equals (o1) sería el único caso que no se imprimiría.


La respuesta a la pregunta "¿por qué?" así es como se define el lenguaje Java.

Para citar el artículo de Wikipedia sobre Covarianza y Contravarianza :

La covarianza de tipo de retorno se implementa en el lenguaje de programación Java versión J2SE 5.0. Los tipos de parámetros tienen que ser exactamente los mismos (invariantes) para la anulación de métodos, de lo contrario, el método se sobrecarga con una definición paralela.

Otros idiomas son diferentes


Si se agrega otro método que anula en lugar de sobrecargarlo, se explicará la llamada de vinculación dinámica en tiempo de ejecución.

/ * ¿Cuál es el resultado del siguiente programa? * /

public class DynamicBinding { public boolean equals(Test other) { System.out.println("Inside of Test.equals"); return false; } @Override public boolean equals(Object other) { System.out.println("Inside @override: this is dynamic binding"); return false; } public static void main(String[] args) { Object t1 = new Test(); Object t2 = new Test(); Test t3 = new Test(); Object o1 = new Object(); int count = 0; System.out.println(count++);// prints 0 t1.equals(t2); System.out.println(count++);// prints 1 t1.equals(t3); System.out.println(count++);// prints 2 t3.equals(o1); System.out.println(count++);// prints 3 t3.equals(t3); System.out.println(count++);// prints 4 t3.equals(t2); } }


Trataré de explicar esto a través de dos ejemplos que son las versiones extendidas de algunos de los ejemplos que encontré en línea.

public class Test { public boolean equals(Test other) { System.out.println("Inside of Test.equals"); return false; } @Override public boolean equals(Object other) { System.out.println("Inside of Test.equals ot type Object"); return false; } public static void main(String[] args) { Object t1 = new Test(); Object t2 = new Test(); Test t3 = new Test(); Object o1 = new Object(); int count = 0; System.out.println(count++); // prints 0 o1.equals(t2); System.out.println("/n" + count++); // prints 1 o1.equals(t3); System.out.println("/n" + count++);// prints 2 t1.equals(t2); System.out.println("/n" + count++);// prints 3 t1.equals(t3); System.out.println("/n" + count++);// prints 4 t3.equals(o1); System.out.println("/n" + count++);// prints 5 t3.equals(t3); System.out.println("/n" + count++);// prints 6 t3.equals(t2); } }

Aquí, para líneas con valores de conteo 0, 1, 2 y 3; tenemos referencia de Object para o1 y t1 en el método equals() . Por lo tanto, en tiempo de compilación, el método equals() del archivo Object.class estará delimitado.

Sin embargo, aunque la referencia de t1 es Object , tiene una inicialización de la clase Test .
Object t1 = new Test(); .
Por lo tanto, en tiempo de ejecución llama al public boolean equals(Object other) que es un

método reemplazado

.

Ahora, para valores de recuento como 4 y 6, nuevamente es sencillo que t3, que tiene referencia e inicialización de Test, llame al método equals() con el parámetro como referencias de Objeto y sea un

método sobrecargado

¡DE ACUERDO!

De nuevo, para comprender mejor qué método llamará el compilador, simplemente haga clic en el método y Eclipse resaltará los métodos de tipos similares que cree que llamarán en el momento de la compilación. Si no se llama en el momento de la compilación, esos métodos son un ejemplo de eliminación de métodos.