sirve - ¿Cómo se configura realmente la variable ''this'' en Java en el objeto actual?
static final java (5)
Añadiendo más información sobre la respuesta de @Tom Anderson, lo que explica muy bien el concepto de ocultación.
He añadido un constructor más en Child ( TestChild
) que imprime valores de i tanto en primario como en secundario.
Si desea obtener el valor de i
de child ( TestChild
), TestChild
el método en TestChild
.
class TestParent{
public int i = 100;
public void printName(){
System.err.println("TestParent:printName()");
System.err.println(this); //{TestChild@SOME_NUM} according to the Debugger.
System.err.println(this.i); //this.i is 100.
}
}
class TestChild extends TestParent{
public int i = 200;
public TestChild(){
System.out.println("TestChild.i and TestParent.i:"+this.i+":"+super.i);
}
public void printName(){
//super.printName();
System.err.println("TestChild:printName()");
System.err.println(this); //{TestChild@SOME_NUM} according to the Debugger.
System.err.println(this.i); //this.i is 200.
}
}
public class ThisTest {
public static void main(String[] args) {
TestParent parent = new TestChild();
parent.printName();
}
}
Caso 1: si comento la llamada a super.printName()
desde el niño, la versión infantil de TestChild.printName()
imprime el valor de i en TestChild
Salida:
TestChild.i and TestParent.i:200:100
TestChild:printName()
TestChild@43cda81e
200
Caso 2: TestChild.printName () llama a super.printName () como la primera línea en el método printName (). En este caso, el valor de padre e hijo se muestra en los métodos respectivos.
Salida:
TestChild.i and TestParent.i:200:100
TestParent:printName()
TestChild@43cda81e
100
TestChild:printName()
TestChild@43cda81e
200
Considerar:
class TestParent{
public int i = 100;
public void printName(){
System.err.println(this); //{TestChild@428} according to the Debugger.
System.err.println(this.i); //this.i is 100.
}
}
class TestChild extends TestParent{
public int i = 200;
}
public class ThisTest {
public static void main(String[] args) {
new TestChild().printName();
}
}
Sé que se han formulado preguntas similares, pero no pude entender bien la variable "esto" en Java.
Permítanme intentar explicar cómo entiendo el resultado de la imagen de arriba.
Dado que es un
new TestChild()
objetonew TestChild()
que está llamando al métodoprintName()
,this
variable en la línea 6 se establece en un objetoTestChild
: {TestChild @ 428} de acuerdo con el Depurador.Sin embargo, dado que Java no tiene un campo virtual, no estoy completamente seguro de lo que esto significa, pero conceptualmente lo entiendo como lo contrario de los métodos de Java, que admiten Polymorphism:
this.i
está configurado a 100 deTestParent
en compilación hora.Así que no importa qué sea
this
,this.i
en un métodoTestParent
siempre será la variablei
en la claseTestParent
.
No estoy seguro de que mi comprensión sea correcta, por favor corrígeme si me equivoco.
Y también, mi pregunta principal es,
¿Cómo se establece this
variable en el objeto actual que llama al método? ¿Cómo se implementa realmente?
Bueno, cuando se crea un nuevo objeto, ese objeto tiene una dirección en la memoria, por lo que puede pensar que es como si el objeto tuviera un miembro privado, this
se establece en la dirección cuando se crea el objeto. También puedes pensarlo de esta manera: obj.method(param)
es solo azúcar sintáctica para el method(obj, param);
Y this
es en realidad un parámetro del method
.
En esencia, no hay diferencia entre
this.foo()
y
anyObject.foo()
Como ambos son "implementados" de la misma manera. Tenga en cuenta que la orientación del objeto "al final" es solo una abstracción , y en la "realidad" lo que sucede es algo así como:
foo(callingObject)
En otras palabras: siempre que use alguna referencia de objeto para llamar a un método ... al final no hay una llamada en algún objeto. Porque en lo profundo del ensamblador y el código de la máquina, algo como "una llamada en algo" no existe.
Lo que realmente sucede es una llamada a una función; y el primer parámetro (implícito / invisible en el nivel de código fuente) es ese objeto.
Por cierto: puedes escribir eso en Java como:
class Bar {
void foo(Bar this) { ... }
y uso posterior
new Bar().foo();
Y para esto. FieldA, al final: tiene una referencia a alguna ubicación en la memoria; y una tabla que le dice en qué "compensación" encontrará el campo A.
Editar - sólo para el registro. Si está interesado en obtener más detalles sobre foo (excluya esto), puede dirigirse a esta question ; dando los detalles en la especificación de Java detrás de él!
Lo que sucede aquí es que hay dos campos completamente diferentes que se llaman i
; para usar sus nombres completos, uno es TestParent::i
y otro es TestChild::i
.
Debido a que el método printName
se define en TestParent
, cuando se refiere a i
, solo puede ver TestParent::i
, que se establece en 100.
Mientras que establece i
en 200 en TestChild
, los dos campos llamados i
son visibles, pero debido a que tienen el mismo nombre, TestChild::i
hides TestParent::i
, y termina configurando TestChild::i
y dejando TestParent::i
intacto
Para abordar directamente lo que ve en la salida: La llamada a imprimir ''this.i'' pasa como argumento a ''print ()'' el valor del campo ''i'' en el alcance actual, que es el alcance de la clase primaria . Por el contrario, la llamada para imprimir ''this'' se está traduciendo bajo el capó a una llamada para imprimir ''this.getClass (). GetName ()'' [en términos generales], y la llamada ''getClass ()'' obtiene el objeto de clase real , que es para la clase infantil.