martes, 28 de julio de 2009

SCJP Declaraciones Inicializacion y Alcance 4

Métodos abstractos
Un método abstracto es un método que ha sido declarado pero que no ha sido implementado, en otras palabras el método no contiene código funcional. Una declaración de método abstracto no tiene las llaves de apertura y de cerradura { } en su lugar tiene un punto y comas ; en otras palabras no tiene un cuerpo, nosotros marcamos los métodos como abstractos para forzar a las subclases la implementación de dicho método. Por ejemplo si tenemos la siguiente clase abstracta:

public abstract class Vehiculo{
public abstract void frenar();
public abstract int kilometraje();
}

entonces las clases que extienden la clase anterior y que no sean abstractas deben dar una implementación a cada uno de los métodos abstractos:

public class Bicicleta extends Vehiculo{
public void frenar(){
-- Aqui la implementación del método frenar.
}
public int kilometraje(){
-- Aqui la implementación del método kilometraje.
}
}

Ojo, no podemos declarar un método abstracto en una clase que no es declarada tambien abstracta, por ejemplo lo siguiente es incorrecto:

-- Esta clase no es abstracta, es concreta.
public class Vehiculo{

-- La clase no es abstracta no tiene el modificador abstract
-- entonces un método abstracto es ilegal aquí.
public abstract void frenar();
}

Veamos otro ejemplo, si tenemos una clase abstracta como:

public abstract class Vehiculo{
public abstract void frenar(String tipoFreno, int tipoVehiculo);
}

y extendemos la clase de la siguiente manera:

public class Omnibus extends Vehiculo{
public void frenar(int tipoFreno, int tipoVehiculo){
-- Aqui la implementación del frenado.
}
}

Ahora, ¿la clase Omnibus extiende e implementa correctamente la clase abstracta Vehiculo?
No, claro que no, porque la clase Omnibus está sobrecargando(overloading) el método frenar no lo sobreescribe(overriding), por lo que la implementación en la subclase(Omnibus) es incorrecta, esto se puede ver porque el argumento en la clase Vehiculo es de tipo String y en la clase Omnibus de tipo int, para que el método abstracto pueda ser implementado correctamente en las subclases, estas deben de corresponder sus tipos de datos con los tipos de datos del método abstracto.

La siguiente clase implementa correctamente la clase abstracta, mira la diferencia con la anterior clase Omnibus:

public class Omnibus extends Vehiculo{
public void frenar(String tipoFreno, int tipoVehiculo){
-- Aqui la implementación del frenado.
}
}

Métodos sincronizados
La palabra clave synchronized indica que un método puede ser accedido solo por un hilo a la vez(saca tus libros de sistemas operativos para recordar que es un hilo), recuerda tambien que la palabra clave synchronized solo puede ser aplicada a métodos y solo a métodos no a variables, ni clases, una declaración típica de un método sincronizado es:

public synchronized long getSaldoDisponible(){
-- Implementación del método sincronizado
}


Métodos nativos
El modificador native indica que un método es implementado con código dependiente del sistema operativo, frecuentemente este código es 'C ' , la palabra clave native solo puede ser aplicado a métodos, no a variables o clases, y como los métodos abstractos no tiene un cuerpo por lo que finalizan con un punto y coma ;

Métodos con una lista de argumentos variable
Desde java5, nosotros podemos crear métodos que permiten tomar un número variable de argumentos, por ejemplo:

public class ClaseSimple{

public int sumar(int... operandos){
int suma = 0;
for(int operando:operandos)
suma = suma + operando;
return suma;
}

public void testSuma(){
-- Aqui podemos observar que la cantidad de
--argumentos para el método puede ser variable
int s0 = sumar();
int s1 = sumar(1,2,3);
int s2 = sumar(1,2,3,4,5);
int s3 = sumar(1,2);
int s4 = sumar(1,2,3,4,5,6,7,8,9);
}
}


Algunas declaraciones legales de métodos con cantidad de argumentos variable:

-- Espera primero un caracter, después cero o más caracteres
private void haceAlgo(char c, char... d){}

-- Espera primero un caracter, después cero o más enteros
private void haceAlgo(char c, int... d){}

-- Espera cero o más instancias de la clase ClaseX
private void haceAlgo(ClaseX... d){}

Algunas declaraciones ilegales de métodos con cantidad de argumentos variable:

-- Sintaxis incorrecta
private void haceAlgo(char d...){}

-- Solo podemos tener un argumento que sea variable
private void haceAlgo(char... d,char... d){}

-- El argumento variable debe de estar al final
private void haceAlgo(char... d,double x){}

Java Básico: Hola Mundo

A ver, muchos aún no han hecho su primea aplicación en Java ó no la han hecho sin un ide(Entorno de Desarrollo Integrado, mismo netbeans ó eclipse), el famoso hola mundo, pues allí les va los pasos:

1. Instalate el jdk(java development kit ó conjunto de herramientas de desarrollo de java), lo puedes descargar desde acá en esa página busca JDK 6 Update XX, descargalo e instalalo.

2. Una vez instalado el jdk coloca las variables de entorno para poder utilizar el jdk desde cualquier directorio o un entorno de mandatos, en windows lo puedes hacer así:

Escritorio/Icono Mi PC(Click Derecho->Propiedades)/Opciones Avanzadas/Variables de Entorno, allí creamos una variable de entorno JAVA_HOME y como valor le colocamos C:\Archivos de programa\Java\jdk1.6.0_14

Además agregamos a la variable de entorno PATH el valor
C:\Archivos de programa\Java\jdk1.6.0_14\bin

Ojo: por default el jdk es instalado en 'C:\Archivos de programa\Java\jdk1.x.0_yz', recuerda donde instalaste el jdk y colocale las variables de entorno adecuadas.

3. Crea tu entorno de desarrollo, es decir, crea las estructuras de directorios básicas, yo hice lo siguiente:

H:\appsjava\app1
H:\appsjava\app2

4. Crea tu archivo fuente(el que contendrá todo el código java), yo creé el archivo HolaMundo.java y lo coloqué en el directorio H:\appsjava\app1, el contenido de dicho archivo es el siguiente:

public class HolaMundo{
public static void main(String[] argumentos){
System.out.println("Hola Mundo en Java");
}
}

5. Compila tu archivo fuente de la siguiente manera:
5.1. Inicia un entorno de línea de comandos(dos) , en windows puedes hacer Inicio/Ejecutar y en la caja de texto coloca cmd, ahora pulsa aceptar, se abrirá el entorno de comandos de dos, desde aquí entra hasta el directorio donde colocaste tu archivo HolaMundo.java de la siguiente manera:

Microsoft Windows XP [Versión 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.
C:\Documents and Settings\Pc>H:
H:\>cd appsjava/app1
H:\appsjava\app1>

5.2 Ahora ya podemos compilar el archivito java que creamos de la siguiente manera:

H:\appsjava\app1>javac HolaMundo.java

5.3 Y si hacemos un listado del directorio con el comando dir, vemos que hay un nuevo archivo llamado HolaMundo.class que contiene el bytecode que la máquina virtual interpretará y ejecutará cuando ejecutemos con el comando java el archivo HolaMundo.class

H:\appsjava\app1>dir
El volumen de la unidad H es DATA_XP3
El número de serie del volumen es: 04B2-3766

Directorio de H:\appsjava\app1

28/07/2009 11:54 a.m. .
28/07/2009 11:54 a.m. ..
28/07/2009 11:54 a.m. 430 HolaMundo.class
28/07/2009 11:49 a.m. 119 HolaMundo.java
2 archivos 549 bytes
2 dirs 6,874,980,352 bytes libres

6. Ejecuta tu archivo con el comando java:
6.1 Ahora una vez compilado y generado el archivo HolaMundo.class procedemos a ejecutarlo con el comando java de la siguiente manera:

H:\appsjava\app1>java HolaMundo
Hola Mundo en Java

La linea anterior Hola Mundo en Java es el resultado de la ejecución de tu programa!.

A ver para los que les gusta algo más complicado, vamos a hacer que la cadena 'Hola Mundo en Java' se ejecute el número de veces que queramos, el numero de veces lo vamos a pasar como un argumento al llamar al programa, veamos como quedaría nuestro código:

public class HolaMundo{
public static void main(String[] argumentos){
for(int i=0; i < Integer.parseInt(argumentos[0]) ; i++)
System.out.println("Hola Mundo en Java");
}
}

Pero que es lo que ha cambiado en el programita?, hemos agregado una estructura repetitiva for y el cuerpo de esta estructura se va a ejecutar tantas veces como indique el primer argumento pasado al programa Integer.parseInt(argumentos[0]) , tenemos que parsear porque el arreglo argumentos contienen valores de tipo String String[] argumentos, por lo que Integer.parseInt(argumentos[0]) nos devolverá un entero

El resultado de la ejecución una vez compilado es el siguiente(vemos que ahora le pasamos un argumento al programa, un número que indica el número de veces que se muestra la cadena 'Hola Mundo en Java'):

H:\appsjava\app1>java HolaMundo 10
Hola Mundo en Java
Hola Mundo en Java
Hola Mundo en Java
Hola Mundo en Java
Hola Mundo en Java
Hola Mundo en Java
Hola Mundo en Java
Hola Mundo en Java
Hola Mundo en Java
Hola Mundo en Java

H:\appsjava\app1>java HolaMundo 3
Hola Mundo en Java
Hola Mundo en Java
Hola Mundo en Java

H:\appsjava\app1>java HolaMundo 6
Hola Mundo en Java
Hola Mundo en Java
Hola Mundo en Java
Hola Mundo en Java
Hola Mundo en Java
Hola Mundo en Java


lunes, 27 de julio de 2009

SCJP Declaraciones Inicializacion y Alcance 3

Declarando miembros de clase
Como vimos una clase puede tener solo 2(default y public) de los 4 modificadores de acceso que los miembros(métodos y variables de instancia) pueden usar: public, protected, default y private.
La protección por default que obtenemos es aquella cuando no escribimos el modificador de acceso en la declaración del miembro como:

public class Algo{
-- Si no escribimos el modificador de acceso a este miembro de
-- clase entonces asume el por default
int x;

-- Este miembro de clase declara explicitamente el tipo de
-- protección a private
private int y;
}

Los controles de acceso default y protected tienen exactamente el mismo comportamiento excepto por una diferencia: el miembro con control de acceso default puede ser accedido solo si la clase accediendo al miembro pertenece a el mismo paquete, a diferencia un miembro con control de acceso protected puede ser accedido(a través de herencia) por una subclase, incluso si la subclase está en un paquete diferente. Veamos algo de código para clarificar la teoria:

package miempresa.core;

public class ClaseA{

-- Si no especificamos el control de acceso a este
-- método entonces se le asigna default
int sumarA(int x,int y){
return (x+y);
}

-- Aqui le asignamos el control de acceso
--explicitamente a protected
protected int restarA(int x,int y){
return (x-y);
}
}


Ahora veamos otra clase que está en otro paquete y que referencia a la clase anterior:

package miempresa.util;
import miempresa.core.ClaseA;

-- La extensión de la ClaseA la podemos realizar ya que su
-- modificador es public
public class ClaseB extends ClaseA{

int sumarB(int x,int y){
-- Lo siguiente es incorrecto ya que sumarA tiene acceso por default
-- y está tratando de ser accedido por la ClaseB que se
-- encuentra en otro paquete
return sumarA(x,y);
}

-- Aqui le asignamos el control de acceso explicitamente a protected
-- Si se compilara solo esta parte entonces todo estaría OK. porque
-- el control de acceso de restarA es protected
protected int restarB(int x,int y){
return restarA(x,y);
}
}

Miembros públicos
Cuando un método o variable miembro es declarado público public significa que todas las otras clases(incluso las que no están en el mismo paquete) pueden acceder al miembro ( asumiendo que la clase es visible )

Miembros privados
Miembros marcados private no pueden ser accedidos por código en cualquier otra clase más que la propia clase en la cual el miembro private fué declarado.

Miembros protected
Veamos un ejemplo:

package miempresa.core;
public class ClaseA{
protected double sueldo;
}


El código anterior declara una variable sueldo como protegida protected. Esto hace la variable accesible a todas las otras clases dentro del paquete miempresa.core así como tambien heredable por cualquier subclase fuera del paquete miempresa.core. Ahora crearemos una subclase en un paquete diferente e intentaremos usar la variable sueldo.

package miempresa.rrhh;
import miempresa.core.ClaseA;
public class ClaseB extends ClaseA{
public void procesar(){
sueldo = 3000;
-- Como vemos heredamos la variable sueldo sin problemas
System.out.println("Mi sueldo fue:"+sueldo);
}
}

El código anterior compila bien, debemos notar que la subclase accede a la variable protegida a través de herencia extends. Pero que pasa si queremos acceder a la variable sueldo sin usar herencia, es decir, usando una instancia de la clase ClaseA, veamos:

package miempresa.rrhh;
import miempresa.core.ClaseA;
public class ClaseB extends ClaseA{
public void procesar(){
sueldo = 3000;
-- Como vemos heredamos la variable sueldo sin problemas
System.out.println("Mi sueldo fue:"+sueldo);

-- Ahora veamos que pasa si instanciamos
-- una clase y tratamos de acceder a la variable protegida
ClaseA claseA = new ClaseA();
-- Lo siguiente nos dará un error de compilación
-- porque la variable es protegida y solo es accesible a través
-- de herencia
System.out.println("Mi sueldo fue:"+claseA.sueldo);
}
}


Variables locales y modificadores de acceso.
Podemos aplicar los modificadores de acceso(public,protected,private) a las variables locales?, es decir el siguiente código es válido?:

public class ClaseA{
public void procesar(){
-- Variable local con modificador de acceso:
private int suma;
}
}

Pues claro que no, no tiene sentido colocar un modificador de acceso a una variable local, esa variable fué declarada solo para ser usada en el ámbito que le corresponde, en el ejemplo el ambito es el método procesar(). Como vemos ningún modificador de acceso puede ser asignado a una variable local, a una variable local solo le podemos asignar un modificador de no-acceso el cual es final, lo cual indica que solo es de lectura(no podemos asignarle un valor).

Métodos finales
La palabra clave final protege a un método de ser sobreescrito en una subclase, veamos un ejemplo, si nosotros tenemos una clase llamada UtilFechas que tiene un método fechaActual, de la siguiente manera:

public class UtilFechas{
public final String fechaActual(){
return "la fecha actual";
}
}

y alguien por allí trata de extender la clase anterior y trata de sobreescribir el método de la siguiente manera:

public class UtilFechasExtendido extends UtilFechas{
-- Esto trata de sobreescribir el método de UtilFechas
public String fechaActual(){
return "la fecha actual de UtilFechasExtendido";
}
}

Entonces el compilador observará que la clase UtilFechas ha marcado su método fechaActual como final (no podemos sobreescribirla) pero la clase UtilFechasExtendido trata de sobreescribirlo, por lo tanto al momento de compilar retornará un error al usuario.

Argumentos Finales
Los argumentos de los métodos son las declaraciones de variables que aparecen entre los parentesis en una declaración de un método, una declaración común de un método con varios argumentos luce así:

public int sumar(int x, int y, int z){
return (x+y+z);
}

El método anterior tiene tres argumentos int x, int y, int z

Los argumentos de los métodos son igual que las variables locales, esto significa que pueden tener el modificador final

public int sumar(int x, final int y, final int z){
return (x+y+z);
}

En el ejemplo anterior los argumentos int y, int z son marcados con el modificador final, lo cuál significa que sus valores no pueden ser cambiados, es decir no pueden asignarseles otro valor(no podemos hacer y = 78; ó z = 100; ) por lo que estos argumentos mantienen su valor como el parametro que fué usado al momento de llamar al método. Es decir si tenemos en otro metodo una llamada al método sumar de la siguiente manera:

int p1 = 10;
int p2 = 20;
int p3 = 30;
int suma = sumar(p1, p2, p3);

Entonces los parametros p2 y p3 se mantendrán inmutables(no cambia su valor) durante la ejecución del método.