====== Clases y Objetos ====== La utilización de clases y objetos (ó instancias) es uno de los pilares de la programación orientada a objetos (POO). Debemos aprender a emplear ambos términos de una forma exacta. Los objetos en programación pueden representar cosas que tenemos en la vida real, pero nunca serán elementos de la vida real. Sin embargo nos pueden servir para representar esos elementos concretos de una forma abstracta dentro de un programa. La abstracción es algo esencial en la programación orientada a objetos. {{ :bloque3:classes_instances.png?400 |}} ===== Clase ===== Es la parte de un programa en Java donde se definen las __propiedades__ y __operaciones__ que van a tener los ejemplares (objetos, instancias) de dicha clase. Con una clase se define un nuevo tipo de datos (Scanner, String, Coche). //Se puede entender que una clase son los planos o el molde, con el que se indican todas las características o forma para poder crear un objeto (ejemplar) de esa clase//. ==== Declaración de una clase ==== modificadores class nombreClase{ declaracionesDeMiembros; } ==== Miembros de una clase ==== Dentro de una clase, como hemos visto hasta ahora, solo podemos definir dos cosas: __métodos y variables__. * Las variables definidas dentro del ámbito de la clase {dentro de los corchetes de la clase} son las variables de instancia. Otras definiciones son: variables miembro, variables de instancia, propiedades de la clase, atributos de la clase, etc. * Los métodos definidos dentro de la clase se conocen como métodos de instancia, o métodos miembro. Cada uno de los elementos de una clase (variables o métodos) se conoce como **miembros** de la clase. public class Coche{ //Atributos: definen el estado del objeto String matricula; int numRuedas; String marca; float kilometros; //Métodos: operaciones del objeto void arracar(){ } int acelerar(int intensidad){ } Además pueden existir otro tipo de miembros de una clase (métodos o variables) que son estáticos ''static''. A este tipo de miembros se les conoce como __métodos o variables de clase__. Se tratan unos puntos más [[bloque3:clasesobjetos#Modificador static|adelante]]. Las ''variables locales'' (de ámbito local) son aquellas que no son miembros de la clase, sino que están dentro del cuerpo de un método o bloque de código (entre corchetes). Si recordamos, una __variable de ámbito local__, solo puede ser accedida desde el mismo ámbito en el que se declara, o en ámbitos inferiores. O sea, dentro de los corchetes (bloque) en el que se declara o en bloques creados dentro del bloque en el que se declara. ===== Objeto ===== {{ :bloque3:clase-superclase.png?340|}} Un objeto es la materialización de una clase en un elemento o ejemplar de dicha clase. Existe en la memoria del ordenador (se crea) y tiene las propiedades (variables miembro) y las operaciones (métodos miembro) que se han indicado en la definición de la clase. Un objeto tiene un estado propio, que viene definido por el estado de sus atributos. Si creamos dos objetos de la misma clase, pueden tener estados distintos. //Se puede entender un objeto como el resultado de construir un ejemplar a partir de los **planos o molde** (clase) que hemos definido anteriormente.// ===== Instanciar una clase: Constructores ===== Crear un ejemplar (objeto) de una clase se conoce como **instanciar** una clase. Para crear un objeto o instancia de una clase, debemos llamar o ejecutar su __constructor__. ==== Operador new ==== Se necesita usar el operador ''new'' para llamar al constructor de una clase. Se ha usado en otras ocasiones: Scaner input; //llamada al constructor Scanner() //el constructor recibe un parámetro con el flujo de entrada input = new Scanner(System.in); String cadena; //llamada al constructor String() que crea una cadena vacía. cadena = new String(); //llamada al constructor String(String cadena) //crea una cadena con el valor del parámetro cadena = new String("fernando"); ==== Definir un constructor ==== La llamada a un constructor devuelve siempre __la referencia al objeto creado en memoria__ (heap). La declaración del constructor de una clase tiene una sintaxis parecida a la de los métodos, pero: * No tiene tipo de retorno, por lo que no hay return. * Su identificador (nombre) es el mismo que la clase. modificadores nombre_clase(){ //instrucciones } //Ejemplo public class Coche{ private String matricula; private int km; //Constructor de la clase Coche public Coche(){ //instrucciones que se realizan al crear un objeto Coche } } Los constructores también __pueden recibir parámetros__, pero recordamos que **nunca devuelven un valor**. public Coche(String cod_matricula){ matricula = cod_matricula; } Y así puedo crear instancias de la clase Coche utilizando los constructores que he definido: public static void main(String[] args){ Coche miCoche = new Coche(); Coche miOtroCoche = new Coche("FDS-1234"); } Concluyendo, ¿qué hace el operador **new** cuando precede al constructor de una clase? Devuelve el valor de la referencia del objeto que se acaba de crear: // Declaro una variable de la clase Coche Coche miVariable; // Asigno la referencia de un objeto Coche a la variable miVariable = new Coche(); La variable, no contiene el objeto sino la referencia (dirección) al lugar de la memoria en el que ha guardado. ==== Constructor no-args ==== Se conoce como el constructor que no recibe parámetros. Si en una clase no definimos explícitamente un constructor, Java creará implícitamente un constructor llamado **no-args** que tiene el siguiente aspecto: public Coche(){ } De este modo aunque no definamos un constructor siempre podremos instanciar una clase. ==== Operaciones de un Constructor ==== Los constructores se utilizan para inicializar los atributos de una clase que necesiten ser inicializados para ser usados, por ejemplo: arrays, listas, creación de objetos, etc. public class Alumno{ private String nombre; private int[] notas; private File foto; public Alumno(){ notas = new int[6]; } public Alumno(String nombre, String rutaFoto){ this.nombre = nombre; notas = new int[6]; foto = new File(rutaFoto); } } **Los atributos de la clase (variables de instancia) nunca se inicializan al ser declarados**. Esto no se aplica a las variables ''static'' (variables de clase) , ya que existen aunque no se llame al constructor. public class Alumno{ //Incorrecto y poco estético private String nombre = ""; private int[] notas = new int[10]; ===== Variables de referencia ===== //Toda variable que no es de __tipo primitivo__ es, sin lugar a dudas, una __variable de referencia__.// Las variables de referencia son todas las variables cuyo tipo de datos es una clase. No contienen al objeto en sí, sino una referencia (//dirección//) al objeto creado en la memoria del ordenador (heap). **Este es uno de los puntos más importantes del lenguaje Java.** Para obtener la referencia de un nuevo objeto usamos su constructor: //Creo 2 variables de referencia, vacías. Coche coche1; Coche coche2; //ahora creo un objeto y guardo su dirección (referencia) en la variable coche1 coche1 = new Coche(); //Cambio el valor del campo matrícula del objeto referenciado coche1.setMatricula("ASD-1234"); //Ahora asigno a la variable coche2 el valor de coche1 coche2 = coche1; //En este momento ambas variables tiene la dirección del mismo objeto //y (coche1 == coche2) es true //Muestro la matrícula que asigné al objeto desde coche1 System.out.println(coche2.getMatricula()); //Asigno a coche2 otro valor con la referencia de un nuevo objeto coche2 = new Coche(); //Ahora coche2 tiene un valor distinto: almacena otra dirección // y está referenciando a un nuevo objeto ==== Valor null==== El valor ''null'' representa el valor de referencia nulo ("sin valor"). Se usa para indicar la ausencia de referencia a un objeto. ==== Paso de parámetros ==== Toda variable contiene un valor y cuando se le pasa un parámetro a un método, se le pasa un valor, **ya sea un valor de referencia o un valor primitivo**. En otros lenguajes existe el paso de parámetros por referencia frente al paso por valor. __Java solo permite el paso de parámetros por valor__ (valores de referencia o primitivos). ===== Modificadores de visibilidad o acceso ===== Para indicar desde qué clases se puede acceder a los miembros de otra clase se usan los llamados modificadores de visibilidad. Usan al declarar los miembros de una clase (atributos, métodos, o constructores) y definen desde qué otras clases puedo acceder a sus miembros. * ''public'' : cualquier miembro público es accedido desde cualquier clase en cualquier paquete. * ''private'' : los miembros privados solo se pueden acceder desde dentro de la clase que los contiene. * ''protected'' : los miembros protegidos solo se pueden usar desde dentro de la propia clase o desde dentro de sus subclases (herencia de clases). * //default// : si no se indica modificador, se pueden acceder a los miembros de la clase también desde las clases que estén en el mismo paquete. Se conoce también como //package-private//. {{:bloque3:modificadoresvisibilidad.png?600|}} Por convenio, los __atributos__ de una clase se deben definir como ''private''. public class Coche{ private int matricula; public int getMatricula(){ return matricula; } } //Desde el método main de otra clase public static void main(String[] args){ Coche unCoche = new Coche(); unCoche.matricula; //No puedo acceder, es private unCoche.getMatricula(); //Puedo acceder, es public } ===== Métodos getters y setters ===== Como se acaba de comentar, los atributos de una clase se deben declarar ''private'' por convenio. Entonces se necesitan métodos públicos para acceder a los atributos y poder modificarlos. Estos métodos se conocen como **getters** y **setters**. private String nombre; private int edad; private boolean casado; public String getNombre(){ return nombre; } public void setNombre(String nombre){ this.nombre = nombre; } ... {{ :bloque3:gettersetters.png?200|}} Estos métodos se nombran como **get** cuando quiero obtener el valor, y como **set** cuando quiero establecerlo. En el caso de los atributos booleanos en lugar de **get**, se suele indicar **is**, aunque no afecta al funcionamiento. La mayoría de IDE's permiten generar getters y setters. En //Eclipse// cuando tengamos el cursor del ratón en el editor de una clase, hacemos click derecho y vamos al menu ''source'' -> ''Generate Getters and Setters''. ---- ===== Palabra reservada: this ===== La palabra ''this'' se usa dentro de un método o de un constructor en una clase y representa el objeto actual: el objeto cuyo método o constructor está siendo llamado. ''this'' contiene una referencia al objeto actual. Hay 2 razones para usarlo: * El nombre del parámetro en un método o constructor tiene el mismo nombre que un atributo de la clase. Usamos ''this'' para diferenciarlos. **Este es su uso principal**. * Un constructor usa otro constructor ya creado en la clase. Usamos ''this'', para llamar al constructor. public class Persona{ private String nombre; private int edad; private int altura; //Uso this para saber que uno el el atributo //Y el otro el parámetro public void setNombre(String nombre){ this.nombre = nombre; } public Persona(String nombre, int edad){ this.nombre = nombre; this.edad = edad; } //Pero tambien lo puedo usar para llamar a un constructor ya definido public Persona(String nombre, int edad, altura){ this(nombre,edad); this.altura = altura; } } ===== Sobrecarga de métodos y constructores ===== El concepto de sobrecarga (overload) consiste en crear varios métodos con el mismo nombre. Aplicado a constructores (todos tienen el mismo nombre) consiste en tener varios constructores. Es un aspecto que se trató en el tema de [[bloque2:metodosstatic#Sobrecarga de Métodos|métodos estáticos]] **Para que pueda sobrecargar constructores o métodos, cada uno debe diferenciarse de otro en el numero, o tipo de los parámetros que recibe**. Java solo nos permite crear más de un método o constructor con el mismo nombre si el número de parámetros o su tipo, es diferente a los de los demás métodos. El valor de retorno no se toma como dato diferenciador. Ejemplo de sobrecarga de método ''indexOf()'' de la clase String: {{ :bloque2:sobrecargastring.png?400 |}} ===== Modificador static ===== El modificador static se aplica principalmente a variables o a métodos de una clase. Ya lo hemos visto aplicado a [[bloque2:metodosstatic|métodos]]. **Variables miembro estáticas**: Una variable estática no se asocia a una instancia de una clase (objeto), sino a la clase misma. Esto es: no hay una copia de la variable estática por cada objeto de la clase, sino una sola copia por clase. A estas variables se les conoce como __variables de clase__. Aunque se creen varios objetos de una misma clase, el valor de sus variables estáticas es el mismo para todos los objetos, y si se modifican, se modifican para todos. Solo hay una copia en memoria. **Métodos miembro estáticos**: Al igual que las variables estáticas, los métodos estáticos no dependen de un objeto de la clase, y por eso se pueden llamar sin necesidad de crear un objeto de la clase. Se les llama __método de clase__. Dado que no es necesario crear un objeto para llamar a estos métodos, no puedes acceder a variables miembro de la clase que no sean estáticas. Esto tiene sentido, ya que si las variables no son estáticas dependen de un objeto, y como hemos dicho, no es necesario un objeto para llamar al método. ===== Inicialización de atributos de una clase ===== Desde el punto de vista del lugar donde se declaran existen dos tipos de variables: * **Variables miembro**: Se declaran en una clase, fuera de cualquier método. * **Variables locales**: Se declaran y usan en un bloque de código dentro de un método. Las variables miembro son inicializadas automáticamente, de la siguiente forma: * Las **numéricas** a 0. * Las **booleanas** a false. * Las **char** al caracter nulo (hexadecimal 0). * Las **variables de referencia** a null. Las variables miembro pueden inicializarse con valores distintos de los anteriores en su constructor. Las variables locales (de ámbito local) no se inicializan automáticamente. Se les debe asignar un valor antes de ser usadas. Los **atributos estáticos** solo pueden inicializarse en su declaración (no en un constructor). ===== Recolector de basura ===== Cuando ya no se necesita un objeto simplemente puede dejar de referenciarse. No existe una operación explícita para 'destruir' un objeto o liberar el área de memoria usada por él. Un objeto deja de referenciarse cuando no hay ninguna variable de referencia dentro del programa que contenga su valor de referencia: Coche miCoche = new Coche(); miCoche = null; //He perdido el valor de la referencia al objeto //Otro ejemplo: Coche miCoche = new Coche(); miCoche = new Coche(); //Pierdo la referencia del objeto anterior Una variable solo puede contener un valor, y cuando no hay ninguna variable que guarde la referencia a un objeto, lo habré perdido para siempre. La liberación de memoria la realiza el recolector de basura (garbage collector), que es una función de la JVM (Java Virtual Machine). El recolector revisa toda el área de memoria del programa y determina qué objetos pueden ser borrados de la memoria __porque ya no tienen referencias activas que los apunten__. El recolector de basura actúa cuando la JVM lo determina (tiene un mecanismo de actuación no trivial). No existe un momento concreto en que las áreas de memoria son liberadas, sino que lo determina en cada momento la JVM en función de sus necesidades de espacio. ===== Clase Object ===== La clase ''Object'' es la clase raíz de la cual heredan todas las clases. Esta herencia es implícita, no es necesario indicarlo en la subclase (mediante extends). Puede que una clase no herede de Object, pero tendrá una superclase que sí lo hace. La clase Object define una serie de métodos miembro que son heredados por todas las clases. Algunos de estos métodos se redefinen (o sobrescriben) en las clases que definamos. ===== Encapsulamiento y abstracción ===== La programación orientada a objetos (POO) es un paradigma de programación basado en unos pilares. Entre ellos podemos encontrar 4 principales: **abstracción**, **encapsulamiento**, **herencia** y **polimorfimo**. La **abstracción** se puede entender como la representación de entidades (pueden ser de la vida real) mediante elementos de un programa. Definimos esos elementos mediante las __clases__ (Coche, Vehiculo, Persona, Pasajero, etc) y los usamos mediante sus __objetos__. Además, estos elementos realizan una serie de operaciones, pero nosotros no tenemos por qué saber cómo se realizan están operaciones: el cómo se hace, formará parte de la clase, donde se definen cómo se hacen las cosas. A nosotros una clase nos ofrece una interfaz (métodos) mediante la cual realizar dichas operaciones, sin tener que preocuparnos de entender cómo se hacen o de implementar su funcionamiento cada vez que las usemos. Todo esto se conoce como **abstracción**. El concepto de **encapsulamiento** es otro pilar fundamental de la POO y está ligado a la abstracción. Consiste en aislar los miembros (propiedades y operaciones) del acceso exterior (ponerlos dentro de una clase). Así evitamos que otras partes del programa pueden modificar las propiedades de un objeto de forma errónea, y crearemos una interfaz para trabajar con el objeto y acceder a sus propiedades. Esta interfaz son los **métodos**. Es la forma en la que el objeto nos permite trabajar con él, sin poder tener acceso a su interior (implementación de operaciones, valor de las propiedades). La **herencia** y el **polimorfismo** se verán más adelante ya que también están ligados entre sí. ===== Otras palabras reservadas ===== Las siguientes palabras clave se irán viendo a medida que trabajemos con nuestras clases y ampliando conocimientos: * ''extends'' : Se usa para indicar cuál es la clase desde la que se hereda. * ''super'' : similar a ''this'', pero contiene una referencia a la superclase. * ''abstract'' : modificador para clases o métodos, se usa en las clases abstractas. * ''final'' : se aplica tanto a variables, clases o métodos, e indica que no se permiten //modificar//. * ''interface'' : similar a la palabra ''class'', define una clase abstracta pura, se conocen como interfaces. * ''implements'' : similar a ''extends'', se usa para indicar de qué interfaces se hereda. ---- (c) {{date> %Y}} Fernando Valdeón