reales - ¿Por qué Java enlaza variables en tiempo de compilación?
libro de android studio en español pdf (4)
El comportamiento polimórfico del lenguaje java funciona con métodos y no con variables miembro: diseñaron el lenguaje para unir variables miembro en tiempo de compilación.
Considere el siguiente código de ejemplo
class MyClass {
public String var = "base";
public void printVar() {
System.out.println(var);
}
}
class MyDerivedClass extends MyClass {
public String var = "derived";
public void printVar() {
System.out.println(var);
}
}
public class Binding {
public static void main(String[] args) {
MyClass base = new MyClass();
MyClass derived = new MyDerivedClass();
System.out.println(base.var);
System.out.println(derived.var);
base.printVar();
derived.printVar();
}
}
da el siguiente resultado
base
base
base
derived
Las llamadas a métodos se resuelven en tiempo de ejecución y se llama al método anulado correcto, como se esperaba.
El acceso a las variables se resuelve en tiempo de compilación como más tarde aprendí.
Esperaba una salida como
base
derived
base
derived
porque en la clase derivada la redefinición de
var
sombrea la de la clase base.
¿Por qué el enlace de variables ocurre en tiempo de compilación y no en tiempo de ejecución?
¿Es esto solo por razones de rendimiento?
En Java, esto es por diseño. Porque, la configuración de los campos que se resolverán dinámicamente haría que las cosas se ejecuten un poco más lentamente. Y en realidad, no hay ninguna razón para hacerlo. Desde entonces, puede hacer que sus campos en cualquier clase sean privados y acceder a ellos con métodos que se resuelven dinámicamente .
Por lo tanto, los campos se resuelven mejor en tiempo de compilación :)
La razón se explica en la Especificación del lenguaje Java en un ejemplo en la Sección 15.11 , citado a continuación:
...
La última línea muestra que, de hecho, el campo al que se accede no depende de la clase de tiempo de ejecución del objeto referenciado; incluso si
s
contiene una referencia a un objeto de la claseT
, la expresiónsx
refiere al campox
de la claseS
, porque el tipo de la expresións
esS
Los objetos de la clase T contienen dos campos llamadosx
, uno para la claseT
y otro para su superclaseS
Esta falta de búsqueda dinámica de accesos de campo permite que los programas se ejecuten de manera eficiente con implementaciones sencillas. El poder de vinculación y anulación tardía está disponible, pero solo cuando se utilizan métodos de instancia ...
Entonces sí, el rendimiento es una razón. La especificación de cómo se evalúa la expresión de acceso de campo se establece de la siguiente manera:
Si el campo no es
static
:...
- Si el campo no es un
final
blanco, el resultado es el valor del campo miembro nombrado en el tipoT
encuentra en el objeto al que hace referencia el valor del primario .
donde
Primario
en su caso se refiere a la variable
derived
que es de tipo
MyClass
.
Otra razón, como sugirió @Clashsoft, es que en las subclases, los campos no se anulan, están ocultos . Por lo tanto, tiene sentido permitir a qué campos acceder en función del tipo declarado o utilizando un reparto. Esto también es cierto para los métodos estáticos. Es por eso que el campo se determina en función del tipo declarado. A diferencia de la anulación por métodos de instancia donde depende del tipo real. La cita anterior de JLS menciona esta razón implícitamente:
El poder de vinculación y anulación tardía está disponible, pero solo cuando se utilizan métodos de instancia.
Si bien puede tener razón sobre el rendimiento, hay otra razón por la cual los campos no se envían dinámicamente: no podría acceder al campo
MyClass.var
si tuviera una instancia de
MyDerivedClass
.
En general, no conozco ningún lenguaje de tipo estático que tenga una resolución variable dinámica.
Pero si realmente lo necesita, puede hacer getters o métodos de acceso (lo que debería hacerse en la mayoría de los casos para evitar campos
public
, de todos modos):
class MyClass
{
private String var = "base";
public String getVar() // or simply ''var()''
{
return this.var;
}
}
class MyDerivedClass extends MyClass {
private String var = "derived";
@Override
public String getVar() {
return this.var;
}
}