El polimorfismo en Java a.) Selección dinámica de método Las dos clases implementadas a continuación tienen una relación subclase/superclase simple con un único método que se sobrescribe en la subclase: class claseAA { void metodoDinamico() { System.out.println("En el metodo dinamico de claseAA"); } } class claseBB extends claseAA { void metodoDinamico() { System.out.println("En el metodo dinamico de claseBB"); } } Por lo tanto si ejecutamos: claseAA referenciaAA = new claseBB(); referenciaAA.metodoDinamico(); La salida de este proyecto es: En el metodo dinamico de claseBB Se declara la variable de tipo claseA, y después se almacena una referencia a una instancia de la clase claseB en ella. Al llamar al método metodoDinamico() de claseA, el compilador de Java verifica que claseA tiene un método llamado metodoDinamico(), pero el intérprete de Java
observa que la referencia es realmente una instancia de claseB, por lo que llama al método metodoDinamico() de claseB en vez de al de claseA. Esta manera de polimorfismo dinamico en tiempo de ejecucion es uno de los mecanismos mas poderosos que proporciona el diseño orientado a
objetos para soportar la re
utilizacion del codigo y la robustez. b.) Sobrescritura de un método Mientras una jerarquia de
herencia puede interesar regresar a escribir el cuerpo de un metodo, para hacer una funcionalidad de distinto forma dependiendo del nivel de abstraccion en que nos encontremos. A esta transformación de funcionalidad se le llama sobrescritura de un metodo. Por ejemplo, en una herencia
entre una clase SerVivo y una clase hija Persona; si la clase SerVivo tuviese un metodo alimentarse(), deberia regresar a escribirse en el nivel de Persona, ya que que una persona no se alimenta ni
como un Animal, ni
como una Planta... La mejor forma de contemplar la
diferencia entre sobrescritura y sobrecarga es mediante un ejemplo. A continuacion se puede contemplar la implementacion de la sobrecarga de la distancia en 3D y la sobrescritura de la distancia en 2D. class MiPunto3D extends MiPunto { int x,y,z; double distancia(int pX, int pY) { // Sobrescritura int retorno=0;
retorno += ((x/z)-pX)*((x/z)-pX); retorno += ((y/z)-pY)*((y/z)-pY); return Math.sqrt( retorno ); } } Se inician los
objetos mediante las sentencias: MiPunto p3 = new MiPunto(1,1); MiPunto p4 = new MiPunto3D(2,2); Y llamando a los metodos de la próximo forma: p3.distancia(3,3); //Método MiPunto.distancia(pX,pY) p4.distancia(4,4); //Método MiPunto3D.distancia(pX,pY) Los métodos se seleccionan en función del tipo de la instancia en tiempo de ejecución, no a la clase en la cual se está ejecutando el método actual. A esto se le llama selección dinámica de método. c.) Sobrecarga de método Es probable que necesitemos crear mas de un metodo con el mismo nombre, pero con listas de parametros distintas. A esto se le llama sobrecarga del metodo. La sobrecarga de metodo se emplea para proporcionar a Java un comportamiento polimorfico. Un
ejemplo de uso de la sobrecarga es por ejemplo, el crear constructores alternativos en función de las coordenadas, tal y
como se hacía en la clase MiPunto: MiPunto( ) { //Constructor por defecto inicia( -1, -1 ); } MiPunto( int paramX, int paramY ) { // Parametrizado this.x = paramX; y = paramY; } Se llama a los constructores basandose en el numero y tipo de parametros que se les pase. Al numero de parametros con tipo de una secuencia especifica se le llama signatura de tipo. Java emplea estas signaturas de tipo para determinar a que metodo llamar. Para
diferenciar entre dos metodos, no se estiman los nombres de los parametros formales sino sus tipos: MiPunto p1 = new MiPunto(); // Constructor por defecto MiPunto p2 = new MiPunto( 5, 6 ); // Constructor parametrizado d.) Limitación de la sobreescritura: final Todos los metodos y las
variables de instancia se
pueden sobrescribir por defecto. Si se desea declarar que ya no se desea permitir que las subclases sobrescriban las
variables o metodos, estos se pueden declarar
como final. Esto se emplea a menudo para crear el equivalente de una constante de C++. Es un convenio de codificacion habitual escoger identificadores en mayusculas para las variables que sean final, por ejemplo: final int NUEVO_ARCHIVO = 1; d. las referencias polimórficas:
this y super a.) Entrada a la particular clase: this Aunque ya se explicó en el artículo de este tutorial el uso de la referencia this
como modificador de ámbito, también se la puede nombrar
como ejemplo de polimorfismo Ademas de
realizar continua referencia a la clase en la que se invoque, tambien vale para sustituir a sus constructores, utilizandola
como metodo: this(); // Constructor por defecto this( int paramX, int paramY ); // Constructor parametrizado b.) Entrada a la superclase: super Ya hemos visto el funcionamiento de la referencia this
como referencia de un objeto hacia si mismo. En Java tiene lugar otra referencia llamada super, que se refiere directamente a la superclase. La referencia super usa para alcanzar a metodos o
atributos de la superclase. Podiamos haber implementado el constructor de la clase MiPunto3D (hija de MiPunto) de la próximo forma: MiPunto3D( int x, int y, int z ) { super( x, y ); // Aquí se llama al constructor de MiPunto this.z = super.metodoSuma( x, y ); // Método de la superclase } Con una sentencia super.metodoSuma(x, y) se llamaría al método metodoSuma() de la superclase de la instancia this. Por el opuesto con super() llamamos al constructor de la superclase.