Diferencia entre revisiones de «Prog. Fundamentos Programación Orientada a Objetos (POO)»
Ir a la navegación
Ir a la búsqueda
| Línea 382: | Línea 382: | ||
* Veremos más adelante los tipos de acceso así como el modificador 'static'. | * Veremos más adelante los tipos de acceso así como el modificador 'static'. | ||
| + | |||
| + | |||
| + | * Cuando declaramos un método tenemos que indicar: | ||
| + | :* Cabecera del método: Contiene el nombre del método, el tipo de dato que va a devolver, una serie de modificadores (como los modificadores de acceso), y opcionalmente una lista de parámetros (representan datos que vamos a enviar al procedimiento cuando lo llamemos). | ||
| + | :* Cuerpo del método: Conjunto de instrucciones que se encuentran entre { }, incluido declaración de variables, las cuales son locales al método (quiere decir que dichas variables sólo son 'visibles' (se puede acceder a ellas) dentro del método. Fuera de él no existen. | ||
| + | |||
| + | |||
| + | |||
: En nuestro ejemplo crearemos dos métodos de la forma siguiente: | : En nuestro ejemplo crearemos dos métodos de la forma siguiente: | ||
Revisión del 09:34 29 oct 2017
Sumario
Introducción
- Antes del paradigma de la POO se utilizaba la programación estructurada.
- Este tipo de programación se basa en un diseño descendente (metodología top-down) y se utilizan para implementar los programas tres estructuras básicas: secuencial-condicional-repetitiva.
- El programa consistía normalmente en un único archivo donde se encontraba todo el código fuente que daba una solución informática al problema del mundo real, en el que los datos se declaraban a nivel 'global' y definimos un conjunto de funciones, el que se trataban dichos datos y se informaba al usuario.
- Este es un tipo de programación orientado al tratamiento de datos, a los procedimientos.
- Cuando diseñas un programa utilizando este tipo de metodología piensas en las operaciones y partiendo de ellas, diseñas el programa.
- Por ejemplo, si quiero dar una solución informática a la gestión de un centro de enseñanza, podría pensar (metodología top-down):
- Necesito una gestión de los alumnos del centro.
- Necesito una gestión de los profesores del centro.
- Dentro de la gestión de alumnos tendré:
- Alta => función que pida los datos y los añada
- Baja => función que pida un identificador y de baja
- Modificación => función que pida los datos y los modifique
- Consulta => función que busque datos en base a diferentes criterios.
- Dentro de la gestión de profesores tendré:
- Alta => función que pida los datos y los añada
- Baja => función que pida un identificador y de baja
- Modificación => función que pida los datos y los modifique
- Consulta => función que busque datos en base a diferentes criterios.
- Los datos estarán definidos a nivel global, utilizando una estructura adecuada para guardarlos, como los arrays.
- En el paradigma de la POO, el diseño se realiza en base a los datos y utilizando un concepto mucho más 'humano' como es el de objeto.
- Un objeto es cualquier cosa que puedas identificar en el mundo real o que puedas a llegar a identificar utilizando la abstracción.
- Ejemplo de objetos:
- Un coche Opel negro matrícula 1234-ABC
- Una matriz matemática
- Un globo de color verde que lleva un niño
- El ordenador con el que estás trabajando
- En la POO cada de las características que posee un objeto se denomina atributo (en la Prog. Estructurada se llaman variables).
- Todos los objetos 'coches' tienen un conjunto de atributos comunes (matrícula, km recorridos, color,....) por lo que en programación, para poder crear esos objetos utilizamos otro concepto denominado clase.
- Una clase define todos los atributos que van a tener los objetos, pero no sus valores, sino los tipos y nombres de los atributos.
- Así puedo definir:
- Una clase Coche que tenga los atributos 'matrícula', 'km', 'color', 'estado'
- Una clase Matriz que tenga los atributos 'fila','columna'
- Una clase Globo, que tenga los atributos 'color','tamaño'
- Una clase Computador que tenga los atributos 'cpu','hd','memoria','velocidadActual'
- En una clase, a parte de definir los atributos, también se definen las funciones (métodos en la POO) que se pueden aplicar a los datos definidos en esa clase.
- Por ejemplo:
- La clase Globo puede tener un método 'hinchar' y otro 'deshinchar' que modificará el valor del atributo 'tamaño'.
- La clase Coche puede tener un método 'recorrer' que modifique el valor del atributo 'km', un método 'arranca','parar','acelerar','frenar' que cambie el atributo 'estado'.
- La clase Matriz puede tener un método 'sumar' para que modifique el valor del atributo 'matriz'.
- La clase Computador puede tener un método 'cambiarVelocidad' que modifique el valor del atributo 'velocidadActual'.
- En el ejemplo anterior de un centro de enseñanza, si aplicamos esta metodología tendríamos:
- Una clase 'Alumno' que representaría cada uno de los alumnos
- Con un método 'crear' que guardaría los datos de un nuevo alumno.
- Con un método 'modificar' que modificaría los datos de un alumno.
- El método 'eliminar' no sería necesario en esta clase ya que cuando un objeto no se utiliza, Java lo elimina con el proceso 'garbage collection'.
- Una clase 'Profesor' que representaría cada uno de los profesores.
- Con un método 'crear' que guardaría los datos de un nuevo profesor.
- Con un método 'modificar' que modificaría los datos de un profesor.
- El método 'eliminar' no sería necesario en esta clase ya que cuando un objeto no se utiliza, Java lo elimina con el proceso 'garbage collection'.
- Una clase Centro que representaría el centro donde trabajan y estudian los alumnos y profesores.
- Dentro de esta clase definiríamos:
- Un atributo que guardaría un array de 'objetos Alumnos' que representa todos los alumnos del centro.
- Un atributo que guardaría un array de 'objetos Profesores' que representa todos los profesores del centro.
- Un método 'crearAlumno' que crearía un nuevo objeto Alumno (llamando al método crear) y lo añadiría al array de Alumnos.
- Un método 'crearProfesor' que crearía un nuevo objeto Profesor (llamando al método crear) y lo añadiría al array de Profesores.
- Un método 'eliminarAlumno' que borraría un objeto Alumno del array de Alumnos.
- Un método 'eliminarProfesor' que borraría un objeto Profesor del array de Profesores.
- Un método 'modificarAlumno' que en base a un identificador (por ejemplo el nif) buscaría el objeto alumno dentro del array de Alumnos y llamaría al método 'modificar' de ese objeto.
- Un método 'modificarProfesor' que en base a un identificador (por ejemplo el nif) buscaría el objeto profesor dentro del array de Profesores y llamaría al método 'modificar' de ese objeto.
- Un método 'listarAlumnos' que en base a un criterio (nombre, nif,...) recorra el array de Alumnos, mostrando aquellos objetos cuyo criterio coincida con los valores guardados en cada uno de los objetos.
POO
Conceptos
Clases
- Una clase es un conjunto de datos y métodos que manejan esos datos.
- Los datos y los métodos definen las características de algún tipo de objeto.
- Por ejemplo, podemos describir un círculo por su punto (x,y) de su centro y por el valor de su radio.
- Cada círculo es diferente de los demás (en el centro o en el radio), pero como clase, todos los círculos tienen una serie de propiedades que sirven para dar una definición de círculo.
- Es decir, una clase consta de métodos (procedimientos) y atributos (variables), que se encuentran relacionados formando un todo que llamamos clase.
- Importante:
- El nombre de las clases en Java debe comenzar con la primera letra en mayúsculas y las siguientes primeras letras de cada palabra si tuviera más de una. Por ejemplo: ChaletsAdosados
- El nombre debe estar en singular
- En Java, la creación de una clase se lleva a cabo en dos pasos: la declaración de clase y su definición.
- La declaración general de una clase es la siguiente:
1 access class Nombre_Clase [extends NombreClase] [implements NombreClase,....] { // Comienzo del código de la clase 2 3 [access] [static] tipo variable_de_instancia1; // Declaramos variables 4 ..... 5 [access] [static] tipo variable_de_instanciaN; 6 ..... 7 8 [access] [static] tipo método1 (lista de parámetros) { // Declaramos métodos 9 ..... 10 } 11 ..... 12 [access] [static] tipo métodoN (lista de parámetros) { 13 ..... 14 } 15 } // Fin del código de la clase
- Más adelante veremos qué significan todas estas palabras clave ...
- Por ejemplo:
1 public class Alumno{ 2 String nif; 3 byte edad; 4 5 public void mostrarEdad(){....} // Imprime la edad 6 7 } // Fin de la clase
Objetos
- Una vez que se ha definido la clase del círculo, se pueden hacer cosas con ella.
- Para usar los métodos y acceder a los métodos datos, se necesita un círculo específico, no sirve la clase; se requiere una instancia de la clase: un objeto Círculo.
- La diferencia entre clase y objetos se puede ver al comparar un molde para hacer cookies con las cookies. El molde tiene todas las características de las cookies, pero no es ninguna galleta en particular.
- Cada cookie (objeto) es una instancia de la clase de cookie (molde). El proceso de crear un objeto de una clase se llama instanciar.
- Cada objeto tendrá un estado que estará conformado por los valores de sus atributos en un momento determinado.
Métodos
- Los métodos son funciones que pueden llamarse dentro de la clase o por otras clases.
- Son las acciones que se pueden realizar con un objeto dado.
- Hay muchas cosas que se pueden hacer con círculos: calcular un circunferencia, el área, ver si un determinado punto está dentro o fuera, etc.
- Los métodos definen el comportamiento de un objeto.
- Dependiendo a que clase pertenezca el objeto tendrá un comportamiento u otro.
- Constituyen la interfaz del objeto, es decir, la forma que tienen otros objetos o clases de comunicarse con un objeto y pedirle información o que realice cierta acción.
Programando clases-objetos-métodos
- Para aclarar todos estos conceptos, llevaremos a cabo el siguiente ejercicio.
- Supongamos que queremos implementar la siguiente clase:
- Esta clase tiene dos atributos (variables) que son el nombre y la edad.
- La forma de definir Java en esta clase es la siguiente:
1 public class Europeo { // Comienza el código de la clase 2 3 4 5 } //Termina el código de la clase
- Nota: La clase tiene un modificador de acceso público (public) para indicar que la clase puede ser utilizada por otras clases. Más adelante revisaremos estos conceptos.
- En nuestro caso, la clase Europeo tiene dos variables, que deben definirse.
- Para definir una variable dentro de una clase de la manera más simple: Tipo nombre_de_variable;
- En nuestro caso:
1 public class Europeo { // Comienza el código de la clase 2 String nombre; 3 int edad; 4 5 6 } //Termina el código de la clase
- Recuerda: Las variables 'miembro' (las que están definidas a nivel de clase) sí se inicializan si no les damos un valor inicial. Si son de tipo numérico se inicializan a 0, si son booleanas a false y si son de referencia o cadena se inicializan a null.
- Recuerda: Las variables 'miembro' son 'visibles' (se puede acceder a su valor) en toda la clase.
- En este momento, hemos definido el molde de las cookies.
- Es decir, definimos la clase, pero esta clase no tiene ningún valor concreto para los atributos nombre y edad.
- Los valores concretos están asociados con los objetos.
- Importante: Una vez que nuestra clase está escrita, es necesario guardarla en un archivo con el mismo nombre de la clase pública, en nuestro caso Europeo y extensión .java.
- Dentro de un único archivo físico, podemos haber definido varias clases. Pero de todos ellas, solo una puede tener el modificador 'public' y el archivo físico deben tener el mismo nombre que esa clase.
- Si no estuviéramos en el NetBeans tendríamos que 'compilar' esta clase con la orden: javac (ya visto anteriormente).
- Crearemos en Netbeans una clase de nombre 'Principal' que tenga el método main definido de la forma:
1 package aprendiendo; 2 3 /** 4 * 5 * @author clase 6 */ 7 public class Principal { 8 9 /** 10 * @param args the command line arguments 11 */ 12 public static void main(String[] args) { 13 // TODO code application logic here 14 } 15 16 }
Nota:> El nombre del paquete será diferente al vuestro.
- Ahora, el objetivo es usar la clase Europeo dentro de la clase Principal.
- Para esto crearemos (instanciaremos) 3 objetos de la clase Europeo con los siguientes datos:
- ¿Cómo definimos un objeto? Para esto debemos definir un objeto de la misma manera que uno se define variable: Nombre_clase nombre_objeto;
- En nuestro caso:
1 Europeos europeos1; // primer objeto 2 Europeos europeos2; // segundo objeto 3 Europeos europeos3 // tercer objeto
- Este es un primer paso, pero a mayores, debemos asignar memoria a estos objetos.
- Para esto, se usa el operador new, que reserva la memoria.
- Este operador sería equivalente al malloc de C.
- En Java no hay operador opuesto, es decir, la liberación de memoria (free en C).
- Lo máximo que podemos hacer es asignar un objeto al valor nulo y es Java que a través del proceso de recolección de basura (proceso especial, garbage collection) es responsable de liberar la memoria que ya no es utilizada por ningún objeto.
En nuestro caso:
1 europeo1 = new Europeo(); // reservamos memoria 2 europeo2 = new Europeo(); // reservamos memoria 3 europeo3 = new Europeo(); // reservamos memoria
- El proceso de reservar memoria se llama instanciación.
- Estas operaciones se pueden hacer a la vez (definición e instanciación):
1 Europeo europeo1 = new Europeo();
- En esta línea, estamos haciendo 3 operaciones:
- Una declaración: declaramos europeo1 de tipo Europeo.
- Una instanciación: reservamos memoria con el operador new.
- Inicialización: más adelante veremos que cuando realizamos la creación de instancias llamamos a uno método especial (procedimiento) llamado constructor que permite inicializar todas las variables. Por defecto, ya vimos que estar variable se inicializan.
- En este momento tenemos 3 objetos de la clase europea y, por lo tanto, cada objeto tendrá los mismos atributos que la clase a la que pertenece, en este caso dos atributos (nombre y edad).
- ¿ Cómo asignamos valores a ditas variables ?
- De la forma: obxecto.atributo = valor;
- En nuestro caso:
1 europeo1.nome = “Angel”; 2 europeo1.idade = 20; 3 europeo2.nome = “Pepe”; 4 europeo2.idade = 15; 5 europeo3.nome = “Jean”; 6 europeo3.idade = 17;
- El código completo quedaría así:
1 public class Principal { 2 public static void main(String arg[]) { 3 4 Europeos europeo1 = new Europeo(); 5 Europeos europeo2 = new Europeo(); 6 Europeos europeo3 = new Europeo(); 7 8 9 europeo1.nome = “Angel”; 10 europeo1.idade = 20; 11 europeo2.nome = “Pepe”; 12 europeo2.idade = 15; 13 europeo3.nome = “Jean”; 14 europeo3.idade = 17; 15 } 16 }
- Pero antes de poder compilar esta clase, es necesario resolver el siguiente problema. Como discutimos anteriormente, en Java, todas son clases. En nuestro caso, estamos utilizando la clase Europeo en la clase Principal.
- Por lo tanto, es necesario informar al compilador de Java que utilizaremos una clase.
- Por defecto, Java busca las clases que se encuentran en el directorio actual (en la compilación), por lo que si está en ese directorio, no es necesario hacer nada más.
- En Netbeans estaréis creando las clases en el mismo paquete, pero recordar que un paquete tiene una traducción 'física' en forma de directorio, por lo que todas las clases que se encuentren dentro del mismo paquete se pueden referenciar.
- Veremos más adelante que existe una sentencia import que se utiliza para indicar a una clase que pueda hacer uso de otras clases que están en otros paquetes (grupo de clases relacionadas).
- En el lenguaje Java, todas las clases se encuentran dentro de un paquete. Si no ponemos ningún paquete en su definición, Java las crea en el paquete por defecto.
- El paquete java.lang y el paquete actual se importan de forma predeterminada o el paquete por defecto (las clases que se encuentran en el directorio actual).
- Si no estuviéramos en el entorno NetBeans, desde consola tendríamos que indicarle a nuestra clase (cuando la compilemos) a dónde tiene que ir a buscar físicamente las clases que vamos a utilizar.
- Para ello hacemos uso de la variable de entorno classpath, la cual puede ser establecida gráficamente si estamos en Windows (MiPC, botón derecho, propiedades) o bien por línea de comandos de la forma (versión Windows):
1 javac –classpath c:\java Principal.java
- Siendo 'c:\java' el directorio donde nuestra clase (Principal.java) iría a buscar las clases que utiliza.
- Para poder ver los valores de las variables vamos a definir un método para cada una.
- Un método es un conjunto de instrucciones (bloque) identificado por un nombre (nombre del método) el cual puede ser llamado desde cualquier punto del programa, poniendo su nombre.
- En ese momento, la secuencia de ejecución del programa cambia, deja de ir secuencialmente y 'salta' al bloque de instrucciones que conforman el método y continúa su ejecución de forma secuencial.
- Cuando acaba de ejecutarse el método, 'vuelve' y continúa ejecutando las instrucciones que se encuentran a continuación de la llamada del método.
- La forma de definir un método es el siguiente:
1 [tipo de acceso][static] tipoDato_devuelta nombre_metodo (lista de parámetros) 2 { 3 instrucción 1; 4 instrucción 2; 5 .............. 6 instrucción n; 7 8 }
- Veremos más adelante los tipos de acceso así como el modificador 'static'.
- Cuando declaramos un método tenemos que indicar:
- Cabecera del método: Contiene el nombre del método, el tipo de dato que va a devolver, una serie de modificadores (como los modificadores de acceso), y opcionalmente una lista de parámetros (representan datos que vamos a enviar al procedimiento cuando lo llamemos).
- Cuerpo del método: Conjunto de instrucciones que se encuentran entre { }, incluido declaración de variables, las cuales son locales al método (quiere decir que dichas variables sólo son 'visibles' (se puede acceder a ellas) dentro del método. Fuera de él no existen.
- En nuestro ejemplo crearemos dos métodos de la forma siguiente:
1 public void impNombre() { // imprime el nombre 2 System.out.println("O nome é:" + nome); 3 }
- Ejercicio: Escribir el código del método impEdad.
- Estos métodos se definirán dentro de la clase Europeo, ya que manejan información que hace referencia a esa clase.
- Por lo tanto, el código de clase Europeo completo hasta ahora es el siguiente:
1 public class Europeo { // Comienza el código de la clase 2 String nombre; 3 int edad; 4 5 public void impNombre() { // imprime el nombre 6 System.out.println("O nome é:" + nome); 7 } 8 9 public void impEdad() { // imprime la idad 10 System.out.println("O nome é:" + idade); 11 } 12 13 } // Termina el código de la clase
- En este punto, tenemos que compilar la clase para obtener los bytescodes actualizado (Europeo.class) (en Netbeans ya lo hace automaticamente al ejecutar la clase Principal).
- En la clase Principal deberíamos llamar a estos métodos desde los objetos. Recuerde que un objeto posee todo los atributos y métodos definidos de la clase a la que pertenece.
- Ejercicio: Cómo llamar a un método desde el objeto para imprimir el nombre y la edad.
- El código de la clase principal completa es el siguiente:
1 public class Principal { 2 3 public static void main(String arg[]) { 4 Europeo europeo1 = new Europeo(); 5 Europeo europeo2 = new Europeo(); 6 Europeo europeo3 = new Europeo(); 7 8 9 europeo1.nombre = "Angel"; 10 europeo1.edad = 20; 11 europeo2.nombre = "Pepe"; 12 europeo2.edad = 15; 13 europeo3.nombre = "Jean"; 14 europeo3.edad = 17; 15 16 17 europeo1.impNombre(); 18 europeo1.impEdad(); 19 europeo2.impNombre(); 20 europeo2.impEdad(); 21 europeo3.impNombre(); 22 europeo3.impEdad(); 23 } 24 }
- Si ejecutamos la clase principal una vez compilada, la consola mostrará los datos de los 3 creados en Europa.
- Todo lenguaje de POO, como Java, tiene 3 características principales:
- Herencia
- Polimorfismo
- Encapsulación
- Definiremos cada uno de ellos y continuaremos con el ejemplo anterior.
- La primera característica es HERENCIA:
- Podemos establecer una relación entre 2 clases de tal manera que una de ellas "herede" todo lo que tiene la otra.
- La herencia significa que no tenemos que redefinir todo el código, por lo que es reutilizable.
- Pueden heredar tanto métodos como variables.
- Gráficamente, podría ser algo como esto:
- Como podemos ver, creamos dos subclases de la clase Europeo.
- Esto conduce tanto la clase Espanol como la Francés.
- La clase Frances hereda los métodos y variables de la clase Europeo, es decir, es como si ya dentro de su código se escribieran las definiciones de los atributos y métodos de clase Europeo.
- Más adelante veremos que no todo es heredado y que existen restricciones.
- También se debe tener en cuenta que en Java no se permite la herencia múltiple, es decir, que una clase hereda al mismo tiempo de dos o más clases.
- Gráficamente sería lo siguiente:
- Desde el punto de vista de la clase Europeo, la clase Espanol es una subclase de la clase Europeo.
- Desde el punto de vista de la clase Espanol, la clase Europeo es una superclase de la clase de Espanol.
- ¿ Cómo Java puede indicar que una clase es una subclase de otra ?
- A través de la palabra clave extends.
- En nuestro caso, supongamos que queremos almacenar la información referida al NIF (en el caso español) y al LIT (en el
caso francés).
- También queremos tener los métodos que imprimen esta información, de nombres impNif e ImpLit.
- Esta información pertenece a la clase Espanol y a la clase Frances, no pertenece a la clase Europeo.
- Es por eso que deberíamos definir una clase con todo lo que la clase Europeo tenía más sus propios atributos.
- En lugar de eso, crearemos dos subclases: Espanol y Frances que son subclases de la clase Europeo.
- Por lo tanto, crearemos dos archivos más, uno para la clase de Espanol y el otro para la clase de Frances.
- El nombre de archivo Espanol.java tendría lo siguiente:
1 public class Espanol extends Europeo { 2 3 String nif; 4 5 public void impNif() { 6 System.out.println("Nif:" + nif); 7 } 8 }
- Ejercicio: Hacer el código de la clase Francés.
- Solución:
1 public class Frances extends Europeo{ 2 3 String lit; 4 5 public void impLit() { 6 System.out.println("Lit:" + lit); 7 } 8 9 }
- Ejercicio: Compilar as dúas clases no mesmo ficheiro físico. Que nome debe ter ? Cantas clases públicas hai
dentro do ficheiro ?
- Ahora debemos modificar la clase Principal, ya que tenemos más información que se debe ajustar a la situacion:
- Resulta que europeo1 y europeo2 son españoles, por lo tanto, deben ser objetos de la clase de Espanol, mientras que europeo3 es francés, por lo que debe ser un objeto de la clase de Frances.
- Los cambios en la clase Principal son los siguientes:
- Dos de los objetos se convierten en objetos de la clase de Espanol y uno en un objeto de la clase de Frances:
- Espanol europeo1 = new Espanol();
- Espanol europeo2 = new Espanol();
- Frances europeo3 = new Frances();
- El resto del código se mantiene.
- Ejercicio: ¿ Por qué el objeto europeo1 puede utilizar los métodos y variables de la clase Europeo ?
- Solución: Porque la clase a la que pertenece (Espanol) se define como una subclase de la clase Europeo y por lo tanto hereda todos los métodos y atributos de la clase Europeo.
- Ejercicio: Los nuevos objetos tienen atributos propios (Nif y Lit)
- Asigna un valor e mándalos imprimir.
- Solución:
1 public class Principal { 2 3 public static void main(String arg[]) { 4 Espanol europeo1 = new Espanol(); 5 Espanol europeo2 = new Espanol(); 6 Frances europeo3 = new Frances(); 7 8 9 europeo1.nombre = "Angel"; 10 europeo1.edad = 20; 11 europeo2.nombre = "Pepe"; 12 europeo2.edad = 15; 13 europeo3.nombre = "Jean"; 14 europeo3.edad = 17; 15 16 17 europeo1.impNombre(); 18 europeo1.impEdad(); 19 europeo2.impNombre(); 20 europeo2.impEdad(); 21 europeo3.impNombre(); 22 europeo3.impEdad(); 23 24 europeo1.nif="1111111A"; 25 europeo2.nif="2222222A"; 26 europeo3.lit="XA1111"; 27 28 europeo1.impNif(); 29 europeo2.impNif(); 30 europeo3.impLit(); 31 32 33 } 34 }
- Como podemos ver, el objeto europeo3 no puede llamar al método impNif, ya que este es un método de clase Espanol.
- europeo3 es un objeto de la clase de Frances, por lo que tiene los atributos y métodos de la clase de Frances, además de los atributos y métodos de la clase Europeo ya que la clase Frances es una subclase de la clase Europeo.
- La herencia no tiene que limitarse a un solo nivel, y así podemos tener otra subclase que sea Gallego y que tenga el atributo nifGalego y un método para imprimirlo impNifGalego().
Para implementar esta solución, debemos crear otra clase del nombre Gallego dentro de un archivo físico del nombre Gallego.java y que 'extienda' de la clase Espanol.
1 public class Gallego extends Espanol { 2 3 String nifGallego; 4 5 public void impNifGallego() { 6 System.out.println("Nif galego:" + nifGallego); 7 } 8 9 }
Nota: Dependiendo de donde tengáis las clases, puede ser necesario el uso de la instrucción import. Si están en el mismo paquete no es necesario.
- Partimos del hecho de que europeo2 es gallego y, por lo tanto, tiene un valor nif_galego "GA111111", por lo que debemos modificar la clase principal:
1 ..... 2 ..... 3 Gallego europeo2 = new Gallego(); 4 .... 5 europeo2.nifGallego = "GA11111"; 6 europeo2.impNifGallego ();
- En este caso, europeo2 es un objeto de la clase Gallego, por lo que tiene las variables y métodos de la clase a la que pertenece, pero además esta clase es una subclase de la clase de Espanol, por lo que hereda todas las variables y métodos de esta clase, que a su vez es una subclase de la clase Europeo por lo que también hereda las variables e métodos de esta clase.
- La segunda características de la POO es el POLIMORFISMO.
- Esta característica hace referencia a la posibilidad de utilizar métodos definidos tanto en la superclase como en la subclases incluso si tienen el mismo nombre y argumentos.
- Un ejemplo:
- Supongamos que tenemos un método de nombre para impMaximosIngresos, que imprime los ingresos máximos que un europeo debe tener para hacer una declaración de hacienda.
- Estos ingresos se almacenarán en una variable do nombre maximosIngresos, con un valor de 12048 euros.
- Ejercicio: implementar la solución.
- Solución: Debemos de declarar la variable maximosIngresos en la clase Europeo.
1 short maximosIngresos = 12048;
- Observa cómo se inicializa esta variable, de modo que al crear un objeto esa clase tendrá dicho valor de forma predeterminada.
- Si no lo hacemos así, debemos de dar un valor en la clase principal de la forma: europeo1.maximosIngresos = 12048;
- Debemos de definir el método que imprime los ingresos máximos en la clase Europeo:
1 public void impMaximosIngresos() { // Imprime ingresos máximos 2 System.out.println ("Ingresos máximos son" + maximosIngresos + "euros"); 3 }
- y debemos modificar la clase Principal para imprimir esta variable:
- Por ejemplo: europeo1.impMaximosIngresos ();
- Sin embargo, queremos que imprima los ingresos máximos en pesetas para aquellos objetos que pertenecen a la clase Espanol o la clase Gallego.
- ¿Cómo podemos resolverlo? De dos maneras:
- Declarando un nuevo método en la clase de Espanol que imprima el ingreso máximo en pesetas dando otro nombre que no sea el de la superclase, por ejemplo, impMaximosIngresosPesetas.
- Declarar el método en la clase de Espanol, con el mismo nombre, pero imprimiendo la cantidad en pesetas.
- La opción b) es lo que se conoce como polimorfismo.
- En nuestro ejemplo, declararemos el siguiente método en clase Espanol:
1 @Override 2 public void impMaximosIngresos() { // imprime el ingreso máximo en pesetas 3 System.out.println ("Los ingresos máximos son" + maximosIngresos*166 + " pesetas"); 4 }
- Nota: El valor 166 tendría que estar definido en una constante.
- Si ahora cambiamos la clase Principal para imprimir el ingreso máximo de los 3 objetos (personas):
1 europeo1.impMaximosIngresos(); 2 europeo2.impMaximosIngresos(); 3 europeo3.impMaximosIngresos();
- Veremos que resulta que europeo1 y europeo2 imprimen el ingreso máximo en pesetas.
- El objeto europeo3 imprime en euros, ya que el método lo ha heredado de la clase Europeo.
- Su aplicación práctica la podríamos ver en el siguiente ejemplo.
- Supongamos que necesitamos un método que imprima los ingresos máximos de los objetos que le vamos a pasar en forma de parámetros.
- Dichos objetos podrán ser de la clase Frances, Espanol o Gallego.
- La definición del método sería la siguiente:
1 public static void tratarObjetos(Europeo europeo) { 2 3 europeo.impMaximosIngresos(); 4 }
- Como vemos, espera recibir un objeto de la clase Europeo. De esta forma podemos enviarle objetos de la clase Frances, Espanol o Gallego, ya que pertenecen a la Europeo.
- Cuando el objeto 'europeo' llame al método 'impMaximosIngresos()' lo hará en función de la clase a la que pertenezca el objeto, de tal forma que si el objeto que enviamos pertenece a la clase Espanol. llamará al método que imprime el importe máximo en pesetas, y si enviamos un objeto que pertenezca a la clase Frances, llamará al método que imprima en Euros.
- Si no lo hicierámos así, tendríamos que definir un método para imprimir objetos de la clase Espanol, otro para la clase Francés,...
- Otros ejemplos en el siguiente enlace.
- Por lo tanto, para que haya polimorfismo, es necesario definir métodos en clases diferentes relacionadas con la herencia y deben de tener:
- El mismo nombre
- Los mismos parámetros (tipo y número)
- El mismo tipo de dato de retorno
- Los modificadores de acceso solo pueden ser iguales o menos restrictivos (indicado en la imagen siguiente).
- El polimofismo implica que un objeto va a ejecutar un método en función de la clase a la que pertenece.
- La última característica es la ENCAPSULACIÓN: los bloques compuestos en Java están delimitados por dos llaves ({}).
- Las variables de Java solo son válidas desde el punto donde se declaran hasta el final del bloque donde están declaradas.
- Es posible tener múltiples niveles de bloques anidados, y cada uno puede contener sus propias variables locales.
- Sin embargo, no se puede declarar una variable con el mismo nombre que una de ámbito más exterior.
- Por ejemplo:
- Relacionados con la encapsulación están los modificadores de acceso, que modifican la visibilidad de las variables, clases y métodos (es decir, si se puede acceder al valor de una variable).
- Se puede acceder a un método, clase o variable definida como public desde cualquier lugar.
- Los métodos y variables:
- private: solo se acceden desde los métodos de la propia clase, no son heredados por las subclases y no son accesible desde ellos.
- protected: son visibles dentro de la clase, las subclases y las otras clases definidas dentro del mismo paquete (package).
- Un paquete (package) es un grupo de clases relacionadas que se encuentran en el mismo archivo o en archivos diferentes, pero dentro del mismo directorio físico.
- Todas las variables y métodos no privados se pueden ver desde todas las clases que pertenezcan al mismo paquete.
- Más adelante ampliaremos la información sobre paquetes, cómo hacer uno y qué sirven ...
- El siguiente cuadro es un resumen del anterior:
- Nota: Una x indica que puede usar el método / variable declarado con ese modificador.
- Profundizando un poco más en los conceptos diremos que un miembro (objeto, método, atributo...) privado es accesible solo para la clase en que se define
- Este acceso se usa para declarar miembros que solo deberían ser utilizados por la clase.
- Esto incluye a los objetos de estas clases que puedan ser utilizados por otras pero que si no fueran privados, podrían modificar los valores de sus atributos y dejar al objeto en un estado 'inconsistente'.
- Por ejemplo:
-- Ángel D. Fernández González -- (2017).