Hola, echándole una mano a un amigo para las oposiciones hemos encontrado un código que no nos cuadra nada:
tenemos la clase A:
public class A {
char c = 'A';
static void f(){
System.out.println("A");
}
void g(){
this.f();
}
}
La clase B:
public class B extends A{
char c = 'B';
static void f(){
System.out.println("B");
}
void h(){
System.out.println("PEPE");
}
}
Y la clase C con el main:
public class C {
public static void main(String[] args){
A a = new A();
B b = new B();
A c = b;
System.out.println(a.c);
System.out.println(b.c);
System.out.println(c.c);
}
}
Y resulta que la salida es:
A
B
A
Yo esperaba que la última A fuera una B ya que a c le estamos asignando un objeto ya creado de tipo B y b.c devuelve efectivamente una B. ¿Aluién sabe porqué, cuando se supone que b y c son el mismo objeto nos devuelven resultados distintos? ¿Porqué o cómo toma el char de la clase A y no se sobre-escribe con el char de la clase B si tienen el mismo nombre?
He estado probando y pese a que inicialice los dos char en el constructor me sigue dando el mismo resultado:
char c = 'B';
public B() {
//super();
this.c = 'B';
}
solo obtengo el resultado que yo esperaba (A,B,B) cuando elimino el 'char c' de la clase B y hago el this.c en el constructor de B.
¿Alguien sabe explicarme esto? Gracias por adelantado :)
CREO que el problema radica en que inicializas el valor del char c al declararlo. Declaralo solo sin inicializarlo (inicializalo en el constructor) y entonces te dara la salida A B B.
Estoy espeso pero a verrrr
Haces A c = b;
Entonces c es una instancia de la clase A. b es una instancia de la clase B (que extiende la clase A). Como c "es del tipo" A, toma el valor que le daría a b si no estuviera "extendida".
Creo que no me acabo de explicar, pero bueno, por ahí andan los tiros creo yo.
Cita de: "Güarmigue"
public class C {
public static void main(String[] args){
A a = new A();
B b = new B();
ESTA LINEA ESTA MAL DEBERIA DE SER EN TODO CASO B c = b; si lo declaras como A te crea un objeto de tipo A y funciona porque B tiene la misma estructura que A, A c = b;
System.out.println(a.c);
System.out.println(b.c);
System.out.println(c.c);
}
}
A ver señores, si B hereda de A, hacer A c = b; es CORRECTISIMO!!!!!!!!!!
Cita de: "shephiroth"A ver señores, si B hereda de A, hacer A c = b; es CORRECTISIMO!!!!!!!!!!
Cierto no me habia dado cuenta de que heredaba.
Cita de: "Güarmigue"
Y resulta que la salida es:
A
B
A
Yo esperaba que la última A fuera una B ya que a c le estamos asignando un objeto ya creado de tipo B y b.c devuelve efectivamente una B. ¿Aluién sabe porqué, cuando se supone que b y c son el mismo objeto nos devuelven resultados distintos? ¿Porqué o cómo toma el char de la clase A y no se sobre-escribe con el char de la clase B si tienen el mismo nombre?
¿Puede ser porque f es un método estático? Prueba a quitar "static".
Cuantas respuestas! gracias a todos, pero aun no tenemos ganador... :?
A ver, repaso las posibilidades que me habéis dado:
shephiroth: En el post comento que aun inicializando en el constructor sigue dando la misma salida, así que el problema no es que inicialice al declarar (aunque ya sabemos que no es lo más correcto)
Ager: eso tendría sentido si la variable fuera static, pero no lo es, por tanto ¿No debería la variable pertenecer al objeto y por tanto ser "machacada"?
Lo de diferencial ya lo respondisteis...
Warchief: f es static, y eso tiene que ver para otro ejercicio, pero 'char c' no lo es, no debería verse afectado en ninguna manera porque uno de los métodos lo sea... (sino vaya show no?)
¿Alguna idea más? Gracias de nuevo por las respuestas!
Si alguna vez haz heredado una clase y sobreescrito algún método y dentro haces esto para llamar al método de la clase padre, lo entenderás mejor:
void metodo() {
super.metodo(); // llamar a metodo() en la clase padre
// hacer algo
}
Me explico...
a tiene una variable c que vale 'A'.
b tiene una variable c que vale 'B'.
Si c es de tipo A, aunque se le asigne un objeto del tipo B, c.c hace referencia a la variable c dentro de a.
Realmente hay dos variables: la c dentro de B y la c dentro de A.
Haz un método dentro de la clase B que haga esto y llamalo:
System.out.println( "A.c="+super.c ); // variable en el padre
System.out.println( "B.c="+c ); // variable c en this
También puedes añadir a esos System.out esta:
System.out.println( ((B)c).c );
Espero haberme explicado bien... :S
Sés, gracias por la respuesta, aciertas en tus afirmaciones, había comprobado lo del super y el this dentro del constructor de B. También probé lo del casting y funcionaba, pero la duda es:
¿Porqué al hacer c.c hago referencia a la variable c que se encuentra en A y no a la de B? ¿No es uno de los mecanismos de la herencia el sobrescribir los métodos y las variables?
LOL, ni caso a lo que puse de static, no había mirado que se hacía System.out.println, pensaba q se llamaba a f() ^^'
Duplicado.
Porque, al menos en Java, el polimorfismo vale para métodos, pero no para propiedades.
CitarPorque, al menos en Java, el polimorfismo vale para métodos, pero no para propiedades.
Lord_taran, este no sería un caso de polimorfismo (el polimorfismo en una variable no tiene sentido como tal... el polimorfirmo es el que una función pueda admitir parámetros de diferentes tipos al estar implementada varias veces ¿no? Yo solo quiero que coja la variable más cercana en la cascada de ámbitos ;P) Sino de un tema de ámbitos, ¿porqué teniendo una variable en una subclase, que tiene el mismo nombre y tipo que otra de su superclase no la devuelve (y de hecho dentro de la clase cualquier operación que se refiera a la variable o incluso a this.c se efectúa sobre la variable de la subclase, el problema es al acceder directamente a la variable desde fuera de la clase)
Sé que es una tontería, y que de todas formas lo suyo es hacer el set y el get, que eclipse los genera solos y punto, pero ya me pica la curiosidad... Y además parece que no tiene una respuesta sencilla cuando nadie da con ella...
Y, sin embargo, generalmente la gente suele esperar que siga el mismo principio que los métodos por lo que en los exámenes de certificación la respuesta que dan es la misma que yo he dado ;)
Por lo demás creo que con lo dicho con sés...
Cita de: "Güarmigue"Y además parece que no tiene una respuesta sencilla cuando nadie da con ella...
La respuesta ya te la ha dado Sés... :wink:
Saludos
Me refería un poco más al porqué que al como, ya que el como ya estaba comprobado empíricamente... como le comenté a sés ya había probado lo del casting y había manejado las dos variables dentro de la clase B, la duda me surge en porqué la primera variable que toma es la de A cuando en teoría debería ser la de B...
Pero ok, me conformo con saber que es así y ya está, lo tendré en cuenta a partir de ahora :) Gracias a todos por vuestras respuestas!! :D
Probablemente voy a decir obviedades que sabes de sobra, pero por si acaso te enseño un par de variaciones:
class A {
char c = 'A';
static void f(){
System.out.println("A");
}
void g(){
this.f();
}
}
class B extends A{
char c = 'B';
char d = 'N';
static void f(){
System.out.println("B");
}
void h(){
System.out.println("PEPE");
}
}
public class C {
public static void main(String[] args){
A a = new A();
B b = new B();
A c = b;
B d = (B)c;
System.out.println(a.c);
System.out.println(b.c);
System.out.println(c.c);
// System.out.println(c.d);
System.out.println(d.c); Si descomentamos peta
}
}
La salida es:
A
B
A
B
Y si descomentaramos la línea que intenta acceder a la variable definida en la subclase pero no en la superclase, daría error de compilación, ya que por mucho que estemos asignando un objeto de tipo B, c sigue siendo de tipo A.
Como digo probablemente sea un mensaje que no te aporte nada, pero weno :P
Eso no se me había ocurrido, así queda más claro, aunque es algo que me sigue sin gustar que ocurra :P pero supongo que será útil en algunos casos...
No es que no me aporte lord_taran, creo que me he expresado mal. Los otros casos los había probado, me aportan desde el punto de vista que confirman mis teorías (hombre, se vé que si devuelve una A, es que está pillando la variable de la superclase...), pero no me traen una explicación. Yo quería saber por qué, soy duro para los actos de fé :twisted:
Lo he estado pensando (si algunas veces pasa) y hemos sido (me incluyo) un poco torpes. si el objeto c es de tipo A, SIEMPRE accedera a A.c. independientemente de que B tenga otra variable que se llame de igual manera. Si quieres que B utilice la variable de A y por lo tanto que te de el resultado A B B lo que tienes que hacer es usar la herencia y no declararla en B, que ya la esta heredando de A. De esta manera (y solo de esta) al tener A c = b, c.c dara B y no A.