lunes, 12 de septiembre de 2011

10.- Programación Orientada a Objetos

Se ha comentado anteriormente en este manual que Java es un lenguaje totalmente orientado a objetos. De hecho siempre hemos definido una clase pública con un método main que permite que se pueda visualizar en la pantalla el programa Java.
La gracia de la POO es que se hace que los problemas sean más sencillos, al permitir dividir el problema. Está división se hace en objetos, de forma que cada objeto funcione de forma totalmente independiente. Un objeto es un elemento del programa que posee sus propios datos y su propio funcionamiento.
Es decir un objeto está formado por datos (propiedades) y funciones que es capaz de realizar el objeto (métodos).
Antes de poder utilizar un objeto, se debe definir su clase. La clase es la definición de un tipo de objeto. Al definir una clase lo que se hace es indicar como funciona un determinado tipo de objetos. Luego, a partir de la clase, podremos crear objetos de esa clase.
Por ejemplo, si quisiéramos crear el juego del parchís en Java, una clase sería la casilla, otra las fichas, otra el dado, etc., etc. En el caso de la casilla, se definiría la clase para indicar su funcionamiento y sus propiedades, y luego se crearía tantos objetos casilla como casillas tenga el juego.
Lo mismo ocurriría con las fichas, la clase ficha definiría las propiedades de la ficha (color y posición por ejemplo) y su funcionamiento mediante sus métodos (por ejemplo un método sería mover, otro llegar a la meta, etc., etc., ), luego se crearían tantos objetos ficha, como fichas tenga el juego.

Propiedades de la POO

  • Encapsulamiento. El  mecanismo  de  herencia  permite  definir  nuevas  clases  partiendo  de  otras  ya existentes.  Las  clases  que  derivan  de  otras  heredan  automáticamente  todo  su
    comportamiento, pero además pueden introducir características particulares propias que
    las diferencian.
  • Ocultación. Hay una zona oculta al definir la clases (zona privada) que sólo es utilizada por esa clases y por alguna clase relacionada. Hay una zona pública (llamada también interfaz de la clase) que puede ser utilizada por cualquier parte del código.
  • Polimorfismo. Cada método de una clase puede tener varias definiciones distintas. En el caso del parchís: partida.empezar(4) empieza una partida para cuatro jugadores, partida.empezar(rojo, azul) empieza una partida de dos jugadores para los colores rojo y azul; estas son dos formas distintas de emplear el método empezar, que es polimórfico.
  • Herencia. Una clase puede heredar propiedades de otra.
Introducción al Concepto de Objeto

Un objeto es cualquier entidad representable en un programa informático, bien sea real (ordenador) o bien sea un concepto (transferencia). Un objeto en un sistema posee: una identidad, un estado y un comportamiento.
El estado marca las condiciones de existencia del objeto dentro del programa. Lógicamente este estado puede cambiar. Un coche puede estar parado, en marcha, estropeado, funcionando, sin gasolina, etc.
El comportamiento determina como responde el objeto ante peticiones de otros objetos. Por ejemplo un objeto conductor puede lanzar el mensaje arrancar a un coche.  El comportamiento determina qué es lo que hará el objeto. 
La identidad determina que cada objeto es único aunque tengan el mismo valor.
No existen dos objetos iguales. Lo que sí existe es dos referencias al mismo objeto.
Los objetos se manejan por referencias, existirá una referencia a un objeto. De modo que esa referencia permitirá cambiar los atributos del objeto. Incluso puede haber varias referencias al mismo objeto, de modo que si una referencia cambia el estado del objeto, el resto (lógicamente) mostrarán esos cambios.
Los objetos por valor son los que no usan referencias y usan copias de valores concretos. En Java estos objetos son los tipos simples: int, char, byte, short, long, float, double y boolean. El resto son todos objetos (incluidos los arrays y Strings).

Clases

Las clases son las plantillas para hacer objetos. Una clase sirve para definir una serie de objetos con propiedades (atributos), comportamientos (operaciones o métodos), y semántica comunes. Hay que pensar en una clase como un molde. A través de las clases se obtienen los objetos en sí.
Es decir antes de poder utilizar un objeto se debe definir la clase a la que pertenece, esa definición incluye:
  • Sus atributos. Es decir, los datos miembros de esa clase. Los datos pueden ser públicos (accesibles desde otra clase) o privados (sólo accesibles por código de su propia clase. También se las llama campos.
  • Sus métodos. Las funciones miembro de la clase. Son las acciones (u operaciones) que puede realizar la clase.
  • Código de inicialización. Para crear una clase normalmente hace falta realizar operaciones previas (es lo que se conoce como el constructor de la clase).
  • Otras clases. Dentro de una clase se pueden definir otras clases (clases internas, son consideradas como asociaciones dentro de UML).

El formato general para crear una clase en Java es:

                  [acceso] class nombreDeClase {
                   [acceso] [static] tipo atributo1;
                   [acceso] [static] tipo atributo2;
                   [acceso] [static] tipo atributo3;
                   ...
                   [access] [static] tipo método1(listaDeArgumentos) {
                   ...código del método...
                        }
                       ...
                   }

La palabra opcional static sirve para hacer que el método o la propiedad a la que precede se pueda utilizar de manera genérica (más adelante se hablará de clases genéricas), los métodos o propiedades así definidos se llaman atributos de clase y métodos de clase respectivamente. Su uso se verá más adelante. 
Ejemplo;


                   class Noria {
                        double radio;
                        void girar(int velocidad){
                       ...//definición del método
                     }
                        void parar(){...
                   }




Objetos

Se les llama instancias de clase. Son un elemento en sí de la clase (en el ejemplo del parchís, una ficha en concreto). Un objeto se crea utilizando el llamado constructor de la clase. El constructor es el método que permite iniciar el objeto. 

datos miembro (propiedades o atributos)

Para poder acceder a los atributos de un objeto, se utiliza esta sintaxis: 
          objeto.atributo

Por ejemplo:
          Noria.radio;

Métodos

Los métodos se utilizan de la misma forma que los atributos, excepto porque los métodos poseen siempre paréntesis, dentro de los cuales pueden ir valore snecesarios para la ejecución del método (parámetros):

              objeto.método(argumentosDelMétodo)

Los métodos siempre tienen paréntesis (es la diferencia con las propiedades) y dentro de los paréntesis se colocan los argumentos del método. Que son los datos que necesita el método para funcionar.
 Por ejemplo:

              MiNoria.gira(5);

Lo cual podría hacer que la Noria avance a 5 Km/h.

Herencia

En la POO tiene mucha importancia este concepto, la herencia es el mecanismo que permite crear clases basadas en otras existentes. Se dice que esas clases descienden de las primeras. Así por ejemplo, se podría crear una clase llamada vehículo cuyos métodos serían mover, parar, acelerar y frenar. Y después se podría crear una clase coche basada en la anterior que tendría esos mismos métodos (les heredaría) y además
añadiría algunos propios, por ejemplo abrirCapó o cambiarRueda.

Creación de Objetos de la Clase

Una vez definida la clase, se pueden utilizar objetos de la clase. Normalmente consta de dos pasos. Su declaración, y su creación. La declaración consiste en indicar que se va a utilizar un objeto de una clase determinada. Y se hace igual que cuando se declara una 
variable simple. Por ejemplo:

                     Noria noriaDePalencia;

Eso declara el objeto noriaDePalencia como objeto de tipo Noria; se supone que previamente se ha definido la clase Noria.


Para poder utilizar un objeto, hay que crearle de verdad. Eso consiste en utilizar el operador new. Por ejemplo:
                    noriaDePalencia = new Noria();

Al hacer esta operación el objeto reserva la memoria que necesita y se inicializa el objeto mediante su constructor. Más adelante veremos como definir el constructor.




miércoles, 7 de septiembre de 2011

9.- Clase String

Introducción


Para Java las cadenas de texto son objetos especiales. Los textos deben manejarse creando objetos de tipo String.
Ejemplo:

                          String texto1 = “¡Prueba de texto!”;

Las cadenas pueden ocupar varias líneas utilizando el operador de concatenación “+”.

                         String texto2 =”Este es un texto que ocupa “ + “varias líneas, no obstante se puede “+
                         “perfectamente encadenar”;
                      
También se pueden crear objetos String sin utilizar constantes entrecomilladas, usando otros constructores:

                         char[] palabra = {‘P’,’a’,’l’,’b’,’r’,’a’};//Array de char
                         String cadena = new String(palabra);
                         byte[] datos = {97,98,99};
                         String codificada = new String (datos, “8859_1”);

En el último ejemplo la cadena codificada se crea desde un array de tipo byte que contiene números que serán interpretados como códigos Unicode. Al asignar, el valor 8859_1 indica la tabla de códigos a utilizar.
comparación entre objetos String.

Los objetos String no pueden compararse directamente con los operadores de comparación. En su lugar se deben utilizar estas expresiones:

   cadena1.equals(cadena2). El resultado es true si la cadena1 es igual a la cadena2. Ambas cadenas son variables de tipo String.

   cadena1.equalsIgnoreCase(cadena2). Como la anterior, pero en este caso no se
tienen en cuenta mayúsculas y minúsculas.

   s1.compareTo(s2). Compara ambas cadenas, considerando el orden alfabético.
Si la primera cadena es mayor en orden alfabético que la segunda devuelve 1, si son iguales devuelve 0 y si es la segunda la mayor devuelve -1. Hay que tener en cuenta que el orden no es el del alfabeto español, sino que usa la tabla ASCII, en esa tabla la letra ñ es mucho mayor que la o.

    s1.compareToIgnoreCase(s2). Igual que la anterior, sólo que además ignora
las mayúsculas (disponible desde Java 1.2)


String.valueOf


Este método pertenece no sólo a la clase String, sino a otras y siempre es un método que convierte valores de una clase a otra. En el caso de los objetos String, permite convertir valores que no son de cadena a forma de cadena.
Ejemplos:
                        String numero = String.valueOf(1234);
                        String fecha = String.valueOf(new Date());

En el ejemplo se observa que este método pertenece a la clase String directamente, no hay que utilizar el nombre del objeto creado (como se verá más adelante, es un método estático).

Métodos de las variables de las cadenas.

Son métodos que poseen las propias variables de cadena. Para utilizarlos basta con
poner el nombre del método y sus parámetros después del nombre de la variable String.

Es decir: variableString.método(argumentos)

length


Permite devolver la longitud de una cadena (el número de caracteres de la cadena):

                        String texto1=”Prueba”;
                        System.out.println(texto1.length());//Escribe 6

Concatenar cadenas

Se puede hacer de dos formas, utilizando el método concat o con el operador +.
Ejemplo:

                        String s1=”Buenos ”, s2=”días”, s3, s4;
                        s3 = s1 + s2;
                        s4 = s1.concat(s2);

charAt

Devuelve un carácter de la cadena. El carácter a devolver se indica por su posición (el primer carácter es la posición 0) Si la posición es negativa o sobrepasa el tamaño de la cadena, ocurre un error de ejecución, una excepción tipo IndexOutOfBounds- Exception.
Ejemplo:
                        String s1=”Prueba”;
                        char c1=s1.charAt(2); //c1 valdrá ‘u’

substring

Da como resultado una porción del texto de la cadena. La porción se toma desde una posición inicial hasta una posición final (sin incluir esa posición final). Si las posiciones indicadas no son válidas ocurre una excepción de tipo IndexOutOfBounds- Exception. Se empieza a contar desde la posición 0.
Ejemplo:
                       String s1=”Buenos días”;
                       String s2=s1.substring(7,10); //s2 = día


indexOf


Devuelve la primera posición en la que aparece un determinado texto en la cadena. En el caso de que la cadena buscada no se encuentre, devuelve -1. El texto a buscar puede ser char o String.
Ejemplo:

                       String s1=”Quería decirte que quiero que te vayas”;
                       System.out.println(s1.indexOf(“que”)); //Da 15

Se puede buscar desde una determinada posición. En el ejemplo anterior:

                       System.out.println(s1.indexOf(“que”,16)); //Ahora da 26

lastIndexOf

Devuelve la última posición en la que aparece un determinado texto en la cadena. Es casi idéntica a la  anterior, sólo que busca desde el final.
Ejemplo:

                       String s1=”Quería decirte que quiero que te vayas”;
                       System.out.println(s1.lastIndexOf(“que”); //Da 26

También permite comenzar a buscar desde una determinada posición.

endsWith


Devuelve true si la cadena termina con un determinado texto.
Ejemplo:
                       String s1=”Quería decirte que quiero que te vayas”;
                       System.out.println(s1.endsWith(“vayas”);     //Da true
startsWith


Devuelve true si la cadena empieza con un determinado texto.

replace


Cambia todas las apariciones de un carácter por otro en el texto que se indique y lo
almacena como resultado. El texto original no se cambia, por lo que hay que asignar el
resultado de replace a un String para almacenar el texto cambiado:

                       String s1=”Mariposa”;
                       System.out.println(s1.replace(‘a’,’e’));    //Da Meripose
                       System.out.println(s1);     //Sigue valiendo Mariposa

replaceAll

Modifica en un texto cada entrada de una cadena por otra y devuelve el resultado. El
primer parámetro es el texto que se busca (que puede ser una expresión regular), el
segundo parámetro es el texto con el que se reemplaza el buscado. La cadena original no
se modifica.


                       String s1=”Cazar armadillos”;
                       System.out.println(s1.replace(“ar”,”er”));     //Da Cazer ermedillos
                       System.out.println(s1);    //Sigue valiendo Cazar armadilos

8.- Arrays y Cadenas

Unidimensionales


Un array es una colección de valores de un mismo tipo engrosados en la misma variable.
De forma que se puede acceder a cada valor independientemente. Para Java además un array es un objeto que tiene propiedades que se pueden manipular. 

Los arrays solucionan problemas concernientes al manejo de muchas variables que se refieren a datos similares. Por ejemplo si tuviéramos la necesidad de almacenar las notas de una clase con 18 alumnos, necesitaríamos 18 variables, con la tremenda lentitud de manejo que supone eso. Solamente calcular la nota media requeriría una tremenda línea de código.
Almacenar las notas supondría al menos 18 líneas de código.
Gracias a los arrays se puede crear un conjunto de variables con el mismo nombre. La diferencia será que un número (índice del array) distinguirá a cada variable. En el caso de las notas, se puede crear un array llamado notas, que representa a todas las notas de la clase. Para poner la nota del primer alumno se usaría notas[0], el
segundo sería notas[1], etc. (los corchetes permiten especificar el índice en concreto del
array).

La declaración de un array unidimensional se hace con esta sintaxis.

           tipo nombre[];

Ejemplo:
                  double cuentas[]; //Declara un array que almacenará valores
                                             // doubles



Declara un array de tipo double. Esta declaración indica para qué servirá el array, pero no reserva espacio en la RAM al no saberse todavía el tamaño del mismo. Tras la declaración del array, se tiene que iniciar. Eso lo realiza el operador new, que es el que realmente crea el array indicando un tamaño. Cuando se usa new es cuando se reserva el espacio necesario en memoria. Un array no inicializado es un array null. 

Ejemplo:

           

                    int notas[];                           //sería válido también int[] notas;
                    notas = new int[3];             //indica que el array constará de tres valores de tipo int
                                                           //También se puede hacer todo a la vez  int notas[]=new int[3];



En el ejemplo anterior se crea un array de tres enteros (con los tipos básicos se crea en memoria el array y se inicializan los valores, los números se inician a 0).


Los valores del array se asignan utilizando el índice del mismo entre corchetes:

                         notas[2]=8;

También se pueden asignar valores al array en la propia declaración:

                    int notas[] = {8, 7, 9};
                    int notas2[]= new int[] {8,7,9};//Equivalente a la anterior

Esto declara e inicializa un array de tres elementos. En el ejemplo lo que significa es que

                    notas[0] vale 8, notas[1] vale 7 y notas[2] vale 9.

En Java (como en otros lenguajes) el primer elemento de un array es el cero. El primer elemento del array notas, es notas[0]. Se pueden declarar arrays a cualquier tipo de datos (enteros, booleanos, doubles, ... e incluso objetos).

La ventaja de usar arrays (volviendo al caso de las notas) es que gracias a un simple
bucle for se puede rellenar o leer fácilmente todos los elementos de un array:

       //Calcular la media de las 18 notas
                    suma=0;
                    for (int i=0;i<=17;i++){
                    suma+=nota[i];
                      }
                    media=suma/18;

A un array se le puede inicializar las veces que haga falta:

                    int notas[] = new notas[16];
...
                    notas = new notas[25];

Pero hay que tener en cuenta que el segundo new hace que se pierda el contenido anterior. Realmente un array es una referencia a valores que se almacenan en memoria mediante el operador new, si el operador new se utiliza en la misma referencia, el anterior contenido se queda sin referencia y, por lo tanto se pierde.

Un array se puede asignar a otro array (si son del mismo tipo):

                           int notas[];
                           int ejemplo[]=new int[18];
                           notas=ejemplo;

En el último punto, notas equivale a ejemplo. Esta asignación provoca que cualquier cambio en notas también cambie el array ejemplos. Es decir esta asignación anterior, no copia los valores del array, sino que notas y ejemplo son referencias al mismo array.

Ejemplo:
                           int notas[]={3,3,3};
                           int ejemplo[]=notas;
                           ejemplo= notas;


Arrays Multidimensionales

Los arrays además pueden tener varias dimensiones. Entonces se habla de arrays de arrays (arrays que contienen arrays) 
Ejemplo:
               int notas[][];

notas es un array que contiene arrays de enteros

              notas = new int[3][12];         //notas está compuesto por 3 arrays
                                                          //de 12 enteros cada uno
              notas[0][0]=9;//el primer valor es 0

Puede haber más dimensiones incluso (notas[3][2][7]). Los arrays multidimensionales se pueden inicializar de forma más creativa incluso.
 Ejemplo:
                    int notas[][] = new int[5][];    //Hay 5 arrays de enteros
                    notas[0] = new int[100];     //El primer array es de 100 enteros
                    notas[1] = new int[230];     //El segundo de 230
                    notas[2] = new int[400];
                    notas[3] = new int[100];
                    notas[4] = new int[200];

Hay que tener en cuenta que en el ejemplo anterior, notas[0] es un array de 100 enteros. Mientras que notas, es un array de 5 arrays de enteros. Se pueden utilizar más de dos dimensiones si es necesario.

Longitud de un array

Los arrays poseen un método que permite determinar cuánto mide un array. Se trata de
length. Ejemplo (continuando del anterior):

             System.out.println(notas.length);      //Sale 5
             System.out.println(notas[2].length);      //Sale 400

La Clase Arrays

En el paquete java.utils se encuentra una clase estática llamada Arrays. Una clase estática permite ser utilizada como si fuera un objeto (como ocurre con Math). Esta clase posee métodos muy interesantes para utilizar sobre arrays.

Su uso es

Arrays.método(argumentos);


fill

Permite rellenar todo un array unidimensional con un determinado valor. Sus argumentos son el array a rellenar y el valor deseado:

                  int valores[]=new int[23];
                  Arrays.fill(valores,-1);//Todo el array vale -1

También permite decidir desde que índice hasta qué índice rellenamos:
Arrays.fill(valores,5,8,-1);//Del elemento 5 al 7 valdrán -1


equals

Compara dos arrays y devuelve true si son iguales. Se consideran iguales si son del
mismo tipo, tamaño y contienen los mismos valores.

sort

Permite ordenar un array en orden ascendente. Se pueden ordenar sólo una serie de
elementos desde un determinado punto hasta un determinado punto.

                   int x[]={4,5,2,3,7,8,2,3,9,5};
                  Arrays.sort(x);//Estará ordenado
                  Arrays.sort(x,2,5);//Ordena del 2º al 4º elemento

binarySearch

Permite buscar un elemento de forma ultrarrápida en un array ordenado (en un array
desordenado sus resultados son impredecibles). Devuelve el índice en el que está
colocado el elemento.
Ejemplo:
                    int x[]={1,2,3,4,5,6,7,8,9,10,11,12};
                    Arrays.sort(x);
                    System.out.println(Arrays.binarySearch(x,8));       //Da 7


toUpperCase

Devuelve la versión en mayúsculas de la cadena.

toLowerCase

Devuelve la versión en minúsculas de la cadena.

toCharArray

Obtiene un array de caracteres a partir de una cadena.




7.- Sentencias de Control de Flujo (Parte 2)

Sentencias Iterativas

El lenguaje Java, como la mayoría de los lenguajes, proporciona sentencias que permiten realizar una tarea una y otra vez hasta que se cumpla una determinada condición, dicha tarea viene definida por un conjunto de sentencias ag rupadas en un bloque. Las sentencias iterativas son for, while y do...while

La sentencia for

Esta sentencia se encuentra en la mayoría de los lenguajes de programación. El bucle for se empleará cuando conocemos el número de veces que se ejecutará una sentencia o un bloque de sentencias, tal como se indica en la figura. La forma general que adopta la sentencia for es

for(inicialización; condición; incremento)
          sentencia;



El primer término inicialización, se usa para inicializar una variable índice, que controla el número de veces que se ejecutará el bucle. La condición representa la condición que ha de ser satisfecha para que el bucle
continúe su ejecución.
El incremento representa la cantidad que se incrementa la variable índice en cada repetición.

Ejemplo: Escribir un programa que imprima los primeros 10 primeros números
enteros empezando por el cero.

for (int i = 0; i < 10; i++) {
   System.out.println(i);
}

El resultado será: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9

Ejemplo: Escribir un programa que imprima los números pare s positivos menores
o iguales que 20

for (int i=2; i <=20; i += 2) {
   System.out.println(i);
}

Ejemplo: Escribir un programa que imprima los números pares positivos menores
o iguales que 20 en orden decreciente

for (int i=20; i >= 2; i -= 2) {
   System.out.println(i);
}

Ejemplo: Escribir un programa que calcule el factorial de un número empleando
la sentencia iterativa for. Guardar el resultado en un número entero de tipo long .
Definición: el factorial de un número n es el resultado del producto 1*2*3* ... *(n-1)*n.

public class TestFactorial {
  public static void main(String[] args) {
     int numero=4;
     long resultado=1;
     for(int i=1; i<=numero; i++){
        resultado*=i;
     }
     System.out.println("El factorial es "+resultado);
   }
}

La sentencia while

A la palabra reservada while le sigue una condición encerrada entre paréntesis. El bloque de sentencias que le siguen se ejecuta siempre que la condición sea verdadera tal como se v e en la figura. La forma general que adopta la sentencia while es:

while (condición)
         sentencia;


Ejemplo: Escribir un programa que imprima los primeros 10 primeros números enteros empezando por el cero, empleando la sentencia iterativa while.

int i=0;
while (i<10) {
           System.out.println(i);
           i++;
}

Ejemplo: escribir un programa que calcule el factorial de un número empleando la sentencia iterativa while

public class TestWhileFactorial {
  public static void main(String[] args) {
     int numero=4;
     long resultado=1;
     while(numero>0){
        resultado*=numero;
        numero--;
     }
     System.out.println("El factorial es "+resultado);
   }
}

La sentencia do...while

Como hemos podido apreciar las sentencias for y while la condición está al principio del bucle, sin embargo, do...while la condición está al final del bucle, por lo que el bucle se ejecuta por lo menos una vez tal como se ve en la figura. do marca el comienzo del bucle y while el final del mismo. La forma general es:

do{
         sentencia;
}while(condición);


Ejemplo: Escribir un programa que imprima los primeros 10 primeros números enteros empezando por el cero, empleando la sentencia iterativa do..while.

int i=0;
do{
          System.out.println(i);
          i++;
}while(i < 10);

El bucle do...while, se usa menos que el bucle while, ya que habitualmente evaluamos la expresión que controla el bucle al comienzo, no al final. La sentencia break
A veces es necesario interrumpir la ejecución de un bucle for, while, o do...while.

for(int i = 0; i < 10; i++){
             if (i == 8) break;
             System.out.println(i);
}

Consideremos de nuevo el ejemplo del bucle for, que imprime los 10 primeros números enteros, se interrumpe la ejecución del bucle cuando se cumple la condición de que la variable contador i valga 8. El código se leerá: "salir del bucle cuando la variable contador i, sea igual a 8".

El código anterior es equivalente a

for(int i = 0; i <=8; i++)
             System.out.println(i);
 
La sentencia continue

La sentencia continue, fuerza al bucle a comenzar la siguiente iteración desde e l
principio. En la siguiente porción de código, se imprimen todos los números del 0
al 9 excepto el número 8.

for(int i = 0; i < 10; i++){
             if (i == 8) continue;
             System.out.println(i);
}