Foros - Stratos

Programadores => General Programadores => Mensaje iniciado por: Güarmigue en 14 de Junio de 2007, 01:05:19 PM

Título: duda ambitos java
Publicado por: Güarmigue en 14 de Junio de 2007, 01:05:19 PM
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 :)
Título: duda ambitos java
Publicado por: shephiroth en 14 de Junio de 2007, 01:17:31 PM
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.
Título: duda ambitos java
Publicado por: AgeR en 14 de Junio de 2007, 01:21:24 PM
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.
Título: Re: duda ambitos java
Publicado por: Diferencial en 14 de Junio de 2007, 01:23:52 PM
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);
}

}
Título: duda ambitos java
Publicado por: shephiroth en 14 de Junio de 2007, 01:26:23 PM
A ver señores, si B hereda de A, hacer A c = b; es CORRECTISIMO!!!!!!!!!!
Título: duda ambitos java
Publicado por: Diferencial en 14 de Junio de 2007, 01:28:17 PM
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.
Título: Re: duda ambitos java
Publicado por: Warchief en 14 de Junio de 2007, 01:43:37 PM
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".
Título: duda ambitos java
Publicado por: Güarmigue en 14 de Junio de 2007, 03:32:37 PM
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!
Título: duda ambitos java
Publicado por: sés en 14 de Junio de 2007, 04:06:51 PM
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
Título: duda ambitos java
Publicado por: Güarmigue en 14 de Junio de 2007, 04:32:58 PM
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?
Título: duda ambitos java
Publicado por: Warchief en 14 de Junio de 2007, 05:58:11 PM
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() ^^'
Título: duda ambitos java
Publicado por: Warchief en 14 de Junio de 2007, 05:58:44 PM
Duplicado.
Título: duda ambitos java
Publicado por: lord_taran en 14 de Junio de 2007, 06:07:26 PM
Porque, al menos en Java, el polimorfismo vale para métodos, pero no para propiedades.
Título: duda ambitos java
Publicado por: Güarmigue en 14 de Junio de 2007, 08:47:54 PM
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...
Título: duda ambitos java
Publicado por: lord_taran en 14 de Junio de 2007, 09:21:37 PM
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...
Título: duda ambitos java
Publicado por: Blankness en 14 de Junio de 2007, 09:35:02 PM
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
Título: duda ambitos java
Publicado por: Güarmigue en 14 de Junio de 2007, 10:26:44 PM
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
Título: duda ambitos java
Publicado por: lord_taran en 15 de Junio de 2007, 01:44:48 AM
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
Título: duda ambitos java
Publicado por: Güarmigue en 15 de Junio de 2007, 02:28:22 AM
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:
Título: duda ambitos java
Publicado por: shephiroth en 15 de Junio de 2007, 03:09:38 PM
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.