Foros - Stratos

Programadores => General Programadores => Mensaje iniciado por: jalbam en 26 de Marzo de 2008, 06:24:46 PM

Título: Casting de un padre a un hijo
Publicado por: jalbam en 26 de Marzo de 2008, 06:24:46 PM
Hola, buenas.

Tengo una duda con Java. Yo tenía entendido que es posible hacer un casting de un objeto "hijo" a uno "padre" (convertir un objeto que es la instancia de una clase que hereda de un padre, a una instancia de este padre), pero no al revés.

Por ejemplo, haciendo esto:

Padre padre = (Padre) hijo;

Pero no estaría permitido hacer esto otro:

Hijo hijo = (hijo) padre;

Recuerdo que Padre es una clase no abstracta, e Hijo es una clase tampoco abstracta y que hereda de Padre.

Sin embargo, Java me deja hacer esto:

Hijo hijo = (hijo) padre;


Pero no me deja hacer esto:

Hijo hijo = (hijo) new Padre();

¿Qué diferencia hay entre hacer casting a un objeto ya instanciado a hacerlo de una nueva instancia? Lo único que cambia a mi modo de ver es la forma de escribirlo (con un new), pero parece ser que para Java no. Java compila en ambos casos, pero en el segundo (con el new) da error lanzando una excepción.

Ya que estamos, esta duda me viene de que me he dado cuenta que es muy común hacer un casting de un objeto Graphics y convertirlo en Graphics2D, cuando Graphics2D es "hijo" de Graphics. ¿Cómo es posible  que se pueda convertir un objeto padre a un hijo? ¿Qué pasa con los métodos y propiedades que el padre no tenga? Si se pierden, ¿para qué nos sirve el casting?. Por cierto, ambas clases (Graphics y Graphics2D) son abstractas (a diferencia del ejemplo anterior con las clases Hijo y Padre, que no lo eran).

Siento la torpeza. Espero que alguien despeje estas dudas, que seguro que sí con los expertos que hay aquí ;)

Gracias por todo.
Título: Casting de un padre a un hijo
Publicado por: Vicente en 26 de Marzo de 2008, 06:57:47 PM
Hasta donde tengo entendido, tu puedes castear a lo que te de la gana :) Luego en tiempo de ejecución si el cast no es válido te dará un ClassCastException o como se llame en Java.

Es diferente castear que pasar por parámetro en una función por ejemplo, donde puedes pasar a un hijo por un padre pero no al revés (porque el hijo siempre implementará la funcionalidad del padre, pero el padre no tiene la del hijo).

Un saludo!

Vicente
Título: Casting de un padre a un hijo
Publicado por: jalbam en 26 de Marzo de 2008, 07:12:34 PM
Gracias por la respuesta :)

Pero sigo sin entender por qué es diferente hacer esto:
Hijo hijo = (hijo) padre;

a hacer esto:
Hijo hijo = (hijo) new Padre();

Efectivamente el fallo se produce en tiempo de ejecución.

Tampoco entiendo por qué se realiza un casting de Graphics para convertirlo en Graphics2D (que es un hijo suyo). ¿No se pierden los métodos y demás? ¿Qué se consigue con ello?
Título: Re: Casting de un padre a un hijo
Publicado por: Zaelsius en 26 de Marzo de 2008, 07:32:48 PM
Cita de: "jalbam"Java me deja hacer esto:

Hijo hijo = (hijo) padre;


Pero no me deja hacer esto:

Hijo hijo = (hijo) new Padre();

En el primer caso, no se sabe si el cast será válido hasta que no se ejecute, y es que "padre" bien podría apuntar a un objeto de tipo Hijo.

En el segundo caso, ya se sabe que el cast es inválido en tiempo de compilación, ya que creas un Padre de maner explícita.
Título: Casting de un padre a un hijo
Publicado por: jalbam en 26 de Marzo de 2008, 07:58:49 PM
Muchas gracias, has dado en el clavo :)

Ahora ya lo veo más claro.

Aunque lo raro es que el primero nunca me genera una excepción. ¿Por qué?

Sin embargo, el segundo sí me genera una. Pero ambos dejan compilar (Java sólo se da cuenta en tiempo de ejecución). ¿Cómo es que no se da cuenta el compilador?

Y, ya que en el primer caso me permite hacerlo, ¿qué obtengo con ello? ¿un objeto "hijo" con sólo los métodos del padre?

Siento la insistencia.
Título: Casting de un padre a un hijo
Publicado por: Buffon en 27 de Marzo de 2008, 09:27:02 AM
ambas clases tienen los mismos métodos o en hijo has añadido alguna funcionalidad nueva ?
Título: Casting de un padre a un hijo
Publicado por: Vicente en 27 de Marzo de 2008, 09:40:57 AM
Te estás liando creo yo jalbam.

Tu tienes las clases Padre e Hijo, e Hijo hereda de padre. Si haces:


Padre padre = new Padre();
Hijo hijo = (Hijo) padre;


Eso te va a petar en ejecución. Pero si haces:


Padre padre = new Hijo();
Hijo hijo = (Hijo) padre;


Eso te va a funcionar porque en el fondo la variable padre lo que contiene es una referencia a un objeto de tipo Hijo. Y después del cast tienes un Hijo lógicamente. El concepto de "un hijo con solo los métodos del padre" es totalmente erróneo. Si es un Hijo es un Hijo, no se puede estar dentro de una variable de tipo Hijo sin cumplir todo lo que significa ser un Hijo.

Por eso el segundo caso no funciona nunca, porque un Padre nunca cumplirá el ser un Hijo (ya que es la superclase de Hijo).

A ver si esto te ayuda. Un saludo!

Vicente

Edit: esto es así en Java, pero en los lenguajes con duck-typing realmente si hijo y padre fueran iguales, aunque uno herede de otro si que te funcionaría (así a grandes rasgos :p).
Título: Casting de un padre a un hijo
Publicado por: jalbam en 27 de Marzo de 2008, 01:10:09 PM
Buffon:
Sí, las dos clases (Padre e Hijo) tienen las dos los mismos métodos (de hecho sólo tienen un constructor igual y ya está).

Vicente:
El primer caso sí me funciona, ni siquiera me da error de ejecución. ¿Será por lo que he dicho antes de que tienen los mismos métodos?

CitarPor eso el segundo caso no funciona nunca, porque un Padre nunca cumplirá el ser un Hijo (ya que es la superclase de Hijo).

Parece ser que hay algún caso que sí funciona. Por eso tengo la duda. Esta duda me venía porque es muy común hacer casting convirtiendo un objeto Graphics a un objeto Graphics2D. En la documentación de Java se puede ver que Graphics es el padre (osea, que Graphics2D hereda de Graphics, con extends), y sin embargo lo estamos convirtiendo a un hijo. Es algo muy común que he leido en diversos sitios de Internet y parece ser que no da error. ¿Cómo y por qué es posible que no de error? Y, sobretodo, ¿qué conseguimos con ello? (me refiero a la ventaja de hacer algo así y a qué obtenemos de diferente con respecto a un objeto Graphics).

Muchas gracias por todo otra vez :)
Título: Casting de un padre a un hijo
Publicado por: Zaelsius en 27 de Marzo de 2008, 02:17:19 PM
Lo de Graphics2D y Graphics es algo histórico.

Graphics2D proporciona métodos de dibujado avanzados que Graphics no tiene, y aunque internamente Java trabaja con Graphics2D (si no, no podrías hacer las conversiones), las interfaces siguen usando Graphics por compatibilidad con código antiguo (razones históricas).

Tito Google:
CitarIn Java 1.2, the paintComponent method is supplied with a Graphics2D object (a subclass of Graphics), which contains a much richer set of drawing operations. It includes pen widths, dashed lines, image and gradient color fill patterns, the use of arbitrary local fonts, a floating point coordinate system, and a number of coordinate transformation operations. However, to maintain compatibility with Swing as used in Java 1.1, the declared type of the paintComponent argument is Graphics, so you have to cast it to Graphics2D before using it.
Título: Casting de un padre a un hijo
Publicado por: Vicente en 27 de Marzo de 2008, 03:28:23 PM
Cita de: "jalbam"Vicente:
El primer caso sí me funciona, ni siquiera me da error de ejecución. ¿Será por lo que he dicho antes de que tienen los mismos métodos?

Que no, que no puede funcionar, deja de pensar en cosas raras :p Si funciona con el graphics es por la cutro-jinchada esa que ha puesto Zaelsius. No puedes castear un padre que realmente sea un padre a un hijo, da igual que sean clones (excepto el aborto de Graphics). Puedes castear un padre que contiene a un hijo a hijo, pero eso era de esperar.

Pero vamos, pon exactamente aquí el código que te funciona y lo vemos.

Un saludo!

Vicente
Título: Casting de un padre a un hijo
Publicado por: Buffon en 28 de Marzo de 2008, 10:13:20 AM
Cita de: "Vicente"
Cita de: "jalbam"Vicente:
El primer caso sí me funciona, ni siquiera me da error de ejecución. ¿Será por lo que he dicho antes de que tienen los mismos métodos?

Que no, que no puede funcionar, deja de pensar en cosas raras :p Si funciona con el graphics es por la cutro-jinchada esa que ha puesto Zaelsius. No puedes castear un padre que realmente sea un padre a un hijo, da igual que sean clones (excepto el aborto de Graphics). Puedes castear un padre que contiene a un hijo a hijo, pero eso era de esperar.

Pero vamos, pon exactamente aquí el código que te funciona y lo vemos.

Un saludo!

Vicente

de hecho, si dejaran castear de padre a hijo, sería un bug de lenguaje acojonante.
Título: Casting de un padre a un hijo
Publicado por: jalbam en 29 de Marzo de 2008, 07:26:56 PM
Hola, buenas.

Siento el retraso pero no pude escribir antes.

Es cierto., teneis razón. He vuelto a hacer las pruebas y estaba equivocado. Recordaba que sí se podía hacer, aunque me habían dicho que no, pero efectivamente no se puede :) Lo siento.

Entonces que se permita el casting de Graphics a Graphics2D, que es un "hijo" suyo, es sólo por razones históricas y porque así lo permite explicitamente Java. ¿No? ¿Por curiosidad, hay alguna forma de hacer algo parecido o es imposible del todo?

Por cierto, es curioso lo de Graphics y Graphics2D. Ahora que estoy haciendo un Tetris y estoy utilizando Graphics, quizá tenga que cambiarlo a Graphics2D para hacerlo más "moderno" :)

Gracias otra vez :)
Título: Casting de un padre a un hijo
Publicado por: Vicente en 30 de Marzo de 2008, 02:53:12 PM
Es imposible y además no deberías necesitarlo. Si lo necesitas tienes algo chungo en tu diseño :S

Un saludo!

Vicente
Título: Casting de un padre a un hijo
Publicado por: jalbam en 30 de Marzo de 2008, 03:43:50 PM
No, no lo necesito. Sólo era por curiosidad.

Muchas gracias otra vez. Habeis resuelto mis dudas por completo.

Hasta pronto :)