Buscar
Social
Ofertas laborales ES

Foro sobre Java SE > Instanciar SubClases A Partir De SuperClase

Java JDK 7.0 / Eclipse / NetBeans

Hola a todos

La siguiente instanciación:

SuperClase x = new SubClase();

1º ¿Cuál es su real valor? o en otras palabras ¿por qué razones técnicas tendría que reemplazar a: SubClase x = new SubClase();?

2º ¿Qué casos reales de aplicación se darían?

Desde ya Muchísimas Gracias

agosto 21, 2015 | Registered CommenterSkar.2007

Se llama polimorfismo. Por ejemplo:


Musician musician = new Pianist();

En este caso Pianist al ser subclase de Musician es también de tipo Musician. Si en tiempo de ejecución no supieras qué tipo de músico va a tocar un concierto, es cuando debes usar polimorfismo.


public void playConcert(Musician musician) {
musician.play();
}

En tiempo de ejecución puedes pasarle un Pianist, Guitarrist, Violinist y todo músico que se te ocurra y por cada subclase de Musician se ejecutará una lógica diferente. Esto es lo que hace el polimorfismo, define diferentes comportamientos a variaciones de un solo tipo.

Es como en el reino animal, en las ranas por ejemplo, hay especies polimórficas, las cuales si bien son ranas, tienen características diferentes.

agosto 21, 2015 | Unregistered CommenterM1ckey

Gracias M1ckey

Va quedando más claro, o no?

Bueno, esa razón por la cuál si no se sabe cuál es la "instancia final a crear" y que se realice en Tiempo De Ejecución, no es del todo correcta pues en la misma instrucción:

Musician musician = new Pianist();

ya se está determinando que se espera a un "específico Pianist" y no a un Guitarrist o Violinist.

Se da a entender entonces que la instancia final se ha de implementar en un bloque switch para manejar las diferentes alternativas: (abrevio)

Musician musician = new Pianist();
Musician musician = new Guitarrist();
Musician musician = new Violinist();

¿Es así, cómo se ha de implementar? o ...

¿de que forma óptima se Instancia en Tiempo De Ejecución una SubClase a partir de su SuperClase?,

pues si la propuesta alcanzada fuese la correcta, de igual manera en cada case de la estructura switch, la Instanciación de la SubClase se haría directamente a partir de la propia SubClase: Pianist musician = new Pianist();

Desde ya Muchísimas Gracias

agosto 21, 2015 | Registered CommenterSkar.2007

Ante todo, ten en cuenta que no puedes hacer switch sobre el tipo de una variable. Hace poco que he tenido que hacer eso mismo yo y la manera en que lo he resuelto es esta (a partir de Java 7 puedes usar String en los switch):


switch (lcObject.getClass().getSimpleName()) {
case "Pianist":

Dicho lo cual, ten en cuenta que tu ejemplo


Musician musician = new Pianist();

no es el mejor ejemplo literal de código real. Seguramente no harás muchas veces eso. Lo que sí puede que hagas es algo como esto:


List<Musician> orchestra = new ArrayList<>();

// Llena el array orchestra con los músicos
...

// Y, ahora, lo procesamos
for(Musician musician : orchestra) {
musician.doSomethingMusical();
}

Como ves, ahí no sabes el tipo específico de músico que estás procesando del array y, sin embargo, algunos de ellos serán pianistas, otros violinistas, etc. Si en ese bucle vas a hacer algo con el músico que se puede hacer con cualquier músico, como pedirle que afine, o que interprete una pieza, te da igual qué instrumento maneja. En cambio, no puedes pedirle que suelte o coja en sus manos el instrumento, salvo que en tu modelo de dominio que representa la aplicación que estás haciendo los pianistas sean tipos verdaderamente forzudos. :-)

Contestando a tu pregunta en negrita, "¿de que forma óptima se Instancia en Tiempo De Ejecución una SubClase a partir de su SuperClase?", una posible manera es tener un Factory que te devuelva un objeto Musician pero que internamente instancie la subclase apropiada a partir de los parámetros que le pases. Yo, por ejemplo, tengo una clase llamada LocaleFile que tiene varias subclases, que son las que realmente se instancian. En la clase LocaleFile he definido un método estático llamado createFile al que le paso como parámetro el nombre del archivo y, en función de su extensión, crea una subclase u otra.


public static LocaleFile createFile(String fileName, LocaleContainer parent) {
LocaleFile newFile;
String extension;
int extStart = fileName.lastIndexOf('.');

if (extStart == -1) {
extension = "(none)";
} else {
extension = fileName.substring(extStart +1).toLowerCase();
}

switch (extension) {
case "dtd":
newFile = new DtdFile();
break;
case "properties":
newFile = new PropertiesFile();
break;
case "ini":
newFile = new PropertiesFile();
break;
case "gif":
case "jpeg":
case "jpg":
case "png":
newFile = new ImageFile();
break;
...

Espero que así te sea más fácil entenderlo.

agosto 21, 2015 | Registered Commenterrickiees

@skar, es obvio que cuando instancias directamente no hay misterio, por eso mismo puse el método playConcert que recibe un objeto tipo Musician. En tiempo de ejecución se determinará qué tipo de músico tocará en el concierto, a esto se le llama polimorfismo y es la razón por la cual almacenas una instancia de una subclase en un objeto de una superclase.

Como dijo @rickiees, por ejemplo puedes tener un conjunto de objetos Musician que tocarán en el concierto y con un simple foreach y llamando al mismo método play para cada uno de ellos se ejecutará un comportamiento diferente.

De la misma forma ocurre cuando se trabaja con interfaces, es muy común tener una interface y varias implementaciones como lo hace la interface List. List implementa muchas clases y se puede decidir cuál implementación utilizar el tiempo de ejecución de acuerdo a lógica de negocio. Por ejemplo, en una ocasión se podría utilizar un LinkedList y en otra ocasión un ArrayList, dependiendo de la necesidad que se tenga en ese momento.

agosto 21, 2015 | Unregistered CommenterM1ckey

bueno agregando un poco más al tema

a mi pensar, cuando nos enseña herencia e interfaces siempre son ejemplos tan simples que da lugar a pasar de ella, debido que los ejemplos se pueden hacer sin ellos.

Asi que tratare de plantearte un escenario un poco más complejo a los que nos enseña.

Antes de enpesar,hay algo que tienes que tener claro cuando usas herencia o interfaces es para hacer tu código genérico y esto para hacerlo reutilizable y escalable, así que cuando quieras usarla siempre herencia o interfaces piensa en apis, es decir en código que no sea dependiente del contexto,

Imagina este escenario: tu quieres hacer un juego arcade, donde tienes varios elementos, obstáculos, premios, jugador, enemigos, etc.
entonces supongamos que tendrás una clase escenario que se encargue de dibujar todos estos elementos, pero quieres tener un método general que dibuje no importe de que elemento sea, esto para dar la posibilidad de agregar cualquier clase de elementos, sin tener que venir a modificar este método, pero como lo hacemos?

Pues usaremos herencia, haremos una clase que se llame Elemento, esta tendrá un método abstracto, que le llamaremos dibujar(Graphics g), y tendrá las propiedades, de posición en x, posición en y, ancho y alto,

bueno de esta clase heredara nuestro héroe, los enemigos, obstáculos. estas clases implementara el método dibujar, porque cada uno de estos elementos se dibuja de manera distinta.

va pero esto en que ayuda?, bueno cuando crees los elementos que lleve cada escenario
los almacenas en una lista de elementos. (aquí es donde ya tiene mas sentido tener una clase padre) ahora si podemos pensar en hacer un método general para dibujar el escenario.
Entonces en escenario podríamos realizar un método como el siguiente
public void dibujarEscenario(List<Elemento> elementos,Graphics g){
//dibujando el fondo.

//dibujando los elementos

for(Elemento objeto in elementos){
objeto.dibujar(g);//aqui es donde cada instancia se encarga de dibujar
//segun tu clase, pero para tu metodo todos son elementos

}

}

En resumen y regresando a tu pregunta original
SuperClase x = new SubClase(); debes de esto SubClase x = new SubClase()

de hecho cambiándolo a algo un poco más elaborado;

public Animal getAnimal(int TipoAnimal){
switch(TipoAnimal){
case Animal.perro:
return new Perro();
case Animal.gato:
return new Gato();
..
defualt: null;
}
}

Es porque el problema que estoy resolviendo me permite o exige procesar una familia de clases con un comportamiento común entre ellas, es decir que los animales emitan un sonido, que las personas caminen, que los empleados calculen una bonificación que depende del tipo de empleado que se trate, etc. y la pregunta más grande puedo hacer lo mismo sin herencia? si, pero sera más código, que tendrás que hacer uso del copy paste porque sera lo mismo solo que con algunas leves modificaciones.


Saludos.

agosto 22, 2015 | Registered Commenterjhosep