viernes, 21 de agosto de 2015

HERENCIA

La herencia es un mecanismo exigido a cualquier lenguaje que pretenda ser orientado a objetos. Consideraremos la herencia como la transmisión de los métodos y atributos de una clase a otra. Gracias a la herencia se pueden establecer jerarquías entre clases. Establecer una jerarquía es un proceso subjetivo, que depende del programador y de los matices de apreciación de cada uno.
La herencia nos permite definir una jerarquía en la que existirán clases padre y clases hijo, pudiéndo ser una clase padre de otra clase, e hijo de otra clase a la vez. No deben definirse jerarquías de herencia en la que una clase sea padre e hijo de la misma clase. Existen 2 tipos de herencia: La herencia simple y la herencia múltiple. En la herencia simple una clase sólo puede tener una clase padre, en la herencia múltiple, una clase puede tener más de una clase padre. Por ejemplo:
En la siguiente figura se muestra una jerarquía de clases, con herencia simple de 2 clases vertebrado e invertebrado, que heredan de la clase serVivo.
Jerarquía de clases: Herencia simple
En la siguiente figura se muestra una jerarquía de clases, con herencia múltiple de 1 clase hispano-argentino, que hereda de las clases español y argentino.
Jerarquía de clases: Herencia múltiple
Cuando una clase hereda de otra, la clase padre "transmite" todos sus atributos y métodos a la clase hija.

Clase abstracta
Al construir una jerarquía de herencia puede darse el caso de que ciertas operaciones de la clase padre no pueden ser completadas por diferentes motivos, o que dichas operaciones se hagan de una forma diferente en cada clase hija. Por ejemplo, en una clase serVivo existirá un método comer, pero ese método será diferente en una clase hija perro (los perros comen con la boca), y en una clase hija pájaro, ya que los pájaros comen con el pico (salvo una mutación extraña...). Por lo tanto, una clase será abstracta si tiene algún método diferido, es decir, declarado pero no definido. No podrá instanciarse ningún objeto de una clase abstracta.
Redefinición de métodos
Una clase hija de una clase abstracta puede redefinir los métodos diferidos de su clase padre abstracta.

Nota: Una clase hija de una clase abstracta no tiene porqué redefinir los métodos diferidos de la clase padre, podría ser una clase nieta de la clase abstracta la que hiciera la redefinición. Lo que es obligatorio es redefinir un método diferido en alguna clase descendiente de una clase abstracta.
El método debe redefinirse con los mismos parámetros que el método diferido, de lo contrario se estaría definiendo otro método (sobrecarga). Es aquí donde aparece el concepto de super. Esta palabra reservada hace referencia a un método perteneciente a la clase padre de la clase del objeto en cuestión.

ENCAPSULAMIENTO EN JAVA

Imaginemos que se crea una clase, una docena de programadores tienen acceso a dicha clase y la utilizan a discreción, posteriormente dicha clase comienza a comportarse de una manera inesperada debido a que los valores que algunas variables han tomado no fueron anticipados y todo comienza a desmoronarse. Para corregir el problema se crea una versión más nueva de dicha clase y listo.

Bueno, a esto le llamamos flexibilidad y capacidad de mantenimiento, ambas son características y beneficios de la programación Orientada a Objetos (OO) pero para que una clase pueda cumplir dichas funciones los programadores debemos de hacer algo. Imaginemos que creamos una clase con variables de instancia públicas a las cuales podemos acceder sin problemas desde fuera de la misma clase...
ejemplo de encapsulamiento
Analizando el código anterior podemos darnos cuenta de que las variables enteras tipo y clase son públicas y pueden ser accedidas directamente a través de una instancia de la clase MiClase, esto compila sin ningún problema, digamos que es 'legal', sin embargo, ¿qué pasa si ingresamos un valor que no se supone debe de tener una variable (en este caso el -5 que le asignamos a tipo)?, simplemente no hay nada que nos detenga para hacerlo. La única manera de proteger el código es escribiendo un método que nos permita regular los valores que cada variable puede tener y escondiendo las variables para que no se pueda acceder a ellas de manera directa, esto es el principio básico de encapsulamiento.

Si se desea flexibilidad, buen mantenimiento y extensibilidad, nuestro diseño en el código debe de incluir encapsulamiento, para ello debemos de hacer lo siguiente:
  1. Mantener las variables de instancia protegidas (puede ser con un modificador de acceso, p.ej., private).
  2. Hacer métodos de acceso públicos para forzar al acceso a las variables por medio de dichos métodos en lugar de acceder directamente.
  3. Utilizar las convenciones de código para los nombres de los métodos, p. ej., set y get.
El ejemplo anterior modificado para un buen encapsulamiento quedaría así:
ejemplo de encapsulamiento
Si nos fijamos un poquito, en el método setTipo() no existen validaciones para prevenir que un valor no válido sea asignado a la variable, sin embargo, el proveer de un método de este tipo desde el diseño inicial de la aplicación nos permite posteriormente modificar el comportamiento de la misma sin afectar los métodos utilizados, tal vez en un futuro se desee que dicha variable solamente pueda tener uno entre un rango de valores y se podrán aplicar posteriormente los cambios sin que haya repercusiones negativas.

METODOS SETTER Y GETTER

Los métodos get y set, son simples métodos que usamos en las clases para mostrar (get) o modificar (set) el valor de un atributo. El nombre del método siempre sera get o set y a continuación el nombre del atributo, su modificador siempre es public ya que queremos mostrar o modificar desde fuera la clase. 

Los Sets y Gets son la forma de acceder a atributos de una clase. Generalmente, se usan con los atributos privados, ya que a los públicos se puede acceder directamente sin tener que acudir a ellos.

Supongamos que tenemos la clase persona:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
public class Persona( ){
 
  private String nombre;
  private String apellidos;
  private int edad;
  private boolean sexo; // Tomaremos que el valor verdadero significa varon, y el falso mujer.
 
  public Persona( ){ }
 
  // Aquí empezamos a declarar gets y sets
 
  public String getNombre( ){
    return this.nombre;
  }
 
  public void setNombre(String nombre){
    this.nombre = nombre;
  }
 
  public String getApellidos( ){
    return this.apellidos;
  }
 
  public void setApellidos(String nombre){
    this.nombre = Apellidos;
  }
 
  public int getEdad( ){
    return this.edad;
  }
 
  public void setNombre(String edad){
    this.edad= edad;
  }
 
  public boolean getSexo( ){
    return this.sexo;
  }
 
  public void setNombre(String boolean ){
    this.boolean = boolean ;
  }
 
}

Como ves ahí, los métodos lo único que hacen es proporcionar un acceso a unos atributos que son privados y que no serían accesibles desde otras clases si no es por otros métodos.

Ahora, si queremos usar esta clase dentro de cualquier código y usar sus gets y sets... se haría lo siguiente:

1
2
3
4
5
6
7
8
Persona persona = new Persona( );
 
persona.setNombre("Sebastián");
persona.setApellidos("Barrionuevo");
persona.setEdad(23);
persona.setSexo(true);
 
String nombreCompleto = persona.getNombre( ) + " " + persona.getApellidos( );


Con ese código de ejemplo, estaríamos dandole valor a todos los atributos de la clase persona.
Luego, obtenemos el nombre y los apellidos para almacenarlos en otra variable de forma conjunta.

lunes, 10 de agosto de 2015

MÉTODOS EN JAVA

Un método en Java es un conjunto de instrucciones definidas dentro de una clase, que realizan una determinada tarea y a las que podemos invocar mediante un nombre.
  
Algunos métodos que hemos utilizado hasta ahora:
– Math.pow()
– Math.sqrt()
– Character.isDigit()
- System.out.println();

Cuando se llama a un método, la ejecución del programa pasa al método y cuando éste acaba, la ejecución continúa a partir del punto donde se produjo la llamada.
Utilizando métodos:
-  Podemos construir programas modulares.
-  Se consigue la reutilización de código. En lugar de escribir el mismo código repetido cuando se necesite, por ejemplo para validar una fecha, se hace una llamada al método que lo realiza.
En Java un método siempre pertenece a una clase.
Todo programa java tiene un método llamado main. Este método es el punto de entrada al programa y también el punto de salida.
1. ESTRUCTURA GENERAL DE UN MÉTODO JAVA 
La estructura general de un método Java es la siguiente:
[especificadores] tipoDevuelto nombreMetodo([lista parámetros]) [throws listaExcepciones]
{
    // instrucciones
   [return valor;]
}
Los elementos que aparecen entre corchetes son opcionales.

especificadores (opcional): determinan el tipo de acceso al método. Se verán en detalle más adelante.

tipoDevuelto: indica el tipo del valor que devuelve el método. En Java es imprescindible que en la declaración de un método, se indique el tipo de dato que ha de devolver. El dato se devuelve mediante la instrucción return. Si el método no devuelve ningún valor este tipo será void.
nombreMetodo: es el nombre que se le da al método. Para crearlo hay que seguir las mismas normas que para crear nombres de variables.
Lista de parámetros (opcional): después del nombre del método y siempre entre paréntesis puede aparecer una lista de parámetros (también llamados argumentos) separados por comas. Estos parámetros son los datos de entrada que recibe el método para operar con ellos. Un método puede recibir cero o más argumentos. Se debe especificar para cada argumento su tipo. Los paréntesis son obligatorios aunque estén vacíos.
throws listaExcepciones (opcional): indica las excepciones que puede generar y manipular el método.
return: se utiliza para devolver un valor. La palabra clave return va seguida de una expresión que será evaluada para saber el valor de retorno. Esta expresión puede ser compleja o puede ser simplemente el nombre de un objeto, una variable de tipo primitivo o una constante.
El tipo del valor de retorno debe coincidir con el tipoDevuelto que se ha indicado en la declaración del método.
Si el método no devuelve nada (tipoDevuelto = void) la instrucción return es opcional.
Un método puede devolver un tipo primitivo, un array, un String o un objeto.
Un método tiene un único punto de inicio, representado por la llave de inicio {. La ejecución de un método termina cuando se llega a la llave final } o cuando se ejecuta la instrucción return.
La instrucción return puede aparecer en cualquier lugar dentro del método, no tiene que estar necesariamente al final.
2. IMPLEMENTACIÓN DE MÉTODOS EN JAVA
Pasos para implementar un método:
1.     Describir lo que el método debe hacer
2.     Determinar las entradas del método
3.     Determinar los tipos de las entradas
4.     Determinar el tipo del valor retornado
5.     Escribir las instrucciones que forman el cuerpo del método
6.     Prueba del método: diseñar distintos casos de prueba
Ejemplo de método: método que suma dos números enteros.
import java.util.*;
public class Metodos1 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int numero1, numero2, resultado;
        System.out.print("Introduce primer número: ");
        numero1 = sc.nextInt();
        System.out.print("Introduce segundo número: ");
        numero2 = sc.nextInt();
        resultado = sumar(numero1, numero2);
        System.out.println("Suma: " + resultado);
    }
    public static int sumar(int a, int b){
           int c;
           c = a + b;
           return c;
    }
}
El método se llama sumar y recibe dos números enteros a y b.  En la llamada al método los valores de las variables numero1 y numero2 se copian en las variables a y b. El método suma los dos números y guarda el resultado en c. Finalmente devuelve mediante la instrucción return la suma calculada.
Ejemplo de programa Java que contiene un método con varios return:
Programa que lee por teclado un año y calcula y muestra si es bisiesto. Para realizar el cálculo utiliza un método llamado esBisiesto.

package bisiesto;
import java.util.*;
public class Bisiesto {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int año;
        System.out.print("Introduce año: ");
        año = sc.nextInt();
        if(esBisiesto(año))  //llamada al método
           System.out.println("Bisiesto");
        else
           System.out.println("No es bisiesto");
    }
    /**
     * método que calcula si un año es o no bisiesto
     */    
    public static boolean esBisiesto(int a){   
        if(a%4==0 && a%100!=0 || a%400==0)
           return true;
        else
           return false;
    }
}

En la llamada al método bisiesto, el valor de la variable año se copia en la variable a y el método trabaja con esta variable. El valor true ó false devuelto por return pasa a ser el valor de la condición.