[Las cosas que no interesan]
miércoles jun 06, 2007
SCJP for JSE5 - 8
1. ENCAPSULACIÓN.
El objetivo de la encapsulación es lograr código que se pueda modificar sin afectar el código de los demás. Esto se logra poniendo en práctica algunas recomendaciones:
- Proteja los atributos de instancia. (con algún modificador de acceso).
- Cree métodos públicos para acceder a los atributos, para ello use los estándares JavaBean para los métodos set() y get().
Ejemplo de una clase bien encapsulada:
class Algo{
private int propiedad;
public int getPropiedad(){
return propiedad;
}
public void setPropiedad(int valor){
propiedad = valor;
}
}
2. HERENCIA, IS-A (ES-UN) Y HAS-A (TIENE-UN).
La herencia es el mecanismo por excelencia de la programación orientada a objetos para reutilizar el código. La herencia permite el diseño de relaciones complejas entre los diferentes componentes de una aplicación y una de las cosas más importantes, el polimorfismo, que permite que cualquier clase sea tratada como uno de sus padres (algunas de las clases de las que hereda).
Dado el código:
class A{
public void hacerCosas(){
System.out.println("A está haciendo alguna cosa");
}
}
class B extends A{ }
class C extends B{ }
Las clases B y C heredan de A. B lo hace directamente y C lo hace a través de B; esto quiere decir que tanto B como C pueden ser tratadas como cualquiera de sus padres, esto es, B puede ser tratada como A y, C puede ser A o B. El siguiente código por ejemplo, es válido y la salida será 4 veces la frase "A está haciendo alguna cosa".
public static void main(String[] args) {
A clase1 = new A();
A clase2 = new B();
A clase3 = new C();
B clase4 = new C();
clase1.hacerCosas();
clase2.hacerCosas();
clase3.hacerCosas();
clase4.hacerCosas();
}
Lo mismo ocurre con los parámetros:
public static void unParametroGeneral(A parametro){
parametro.hacerCosas();
}
public static void main(String[] args) {
unParametroGeneral(new A());
unParametroGeneral(new B());
unParametroGeneral(new C());
}
El problema al tratar las clases como su padre, es que solo se puede acceder a los métodos y atributos de instancia declarados por el mismo padre; para acceder a los métodos y atributos específicos de cada clase, se debe usar una variable de su tipo.
IS-A y HAS-A
La relación IS-A (ES-UN) es una forma de decir "este objeto es de tipo XXX" y se refiere a la herencia entre clases o a la implementación de una interface específica.
Suponiendo que A y B son clases y que Y y Z son interfaces:
- A IS-A (ES-UN) B si A hereda de B directa o indirectamente.
- A IS-A X si A implementa X.
- X IS-A Y si X hereda directa o indirectamente de Y.
La relación HAS-A es mucho más simple y se refiere únicamente al uso que una clase hace de otra. Se dice que A HAS-A (TIENE-UN) B si A tiene un atributo de tipo B. Por ejemplo:
class A{}
class B{
private A atributo;
}
En este caso la clase B HAS-A A.
3. POLIMORFISMO
El polimorfismo se refiere a la capacidad de un objeto para comportarse de diferentes formas (poli-mórifico), esto en Java está dado por las clases de las que hereda y las interfaces que implementa, ambos, directa o indirectamente.
Un objeto puede ser tratado (lo mencioné anteriormente) como cualquiera de sus padres o las interfaces que implemente, es decir, como cualquiera de las clases o interfaces con las que pase el test IS-A, y claro, solo puede invocar los métodos que estén declarados en la clase que se use como tipo para la variable que apunta al objeto. Los métodos que se ejecutarán serán los de la instancia de la clase que realmente se haya creado.
Todo esto se entiende mejor con un ejemplo.
class Animal{
public void comer(){
System.out.println("Comiendo como Animal");
}
}
class Perro extends Animal{ }
class Labrador extends Perro{
public void comer(){
System.out.println("Comiendo como Labrador");
}
public void hacerCosasDivertidasDeLabrador(){
System.out.println("Soy un Perro Labrador haciendo cosas divertidas");
}
}
En este caso, las instancias de la clase Perro pueden ser tratadas como Animal o Perro y las de Labrador como Animal, Perro y Labrador. Pero claro, si por ejemplo se quiere acceder al método 'hacerCosasDivertidasDeLabrador()' de la clase Labrador debe hacerse a través de una variable de tipo Labrador.
Veamos algo de código:
public static void main(String[] args) {
Animal an = new Animal();
Animal pe = new Perro();
Animal la = new Labrador();
an.comer();
pe.comer();
la.comer();
}
Con el tipo Animal se pueden referenciar las instancias de las tres clases, por que Animal, Perro y Labrador cumplen el test 'IS-A Animal'. Pero los métodos que se acceden corresponden a cada una de las instancias que realmente se crearon. Al ejecutar la clase la salida es:
Comiendo como Animal
Comiendo como Animal
Comiendo como Labrador
Las líneas 'an.comer();' y 'pe.comer()' invocan ambos el mismo método implementado en la clase Animal, por que la clase Perro no tiene ninguno declarado, esto es, lo hace a través de herencia. La línea 'la.comer();' aunque tenga una referencia a través de la clase Animal, invoca el método implementado en la clase Perro por que es la instancia a la que realmente apunta.
Si introdujéramos la siguiente línea 'la.hacerCosasDivertidasDeLabrador()', tendríamos un error de compilación por que aunque la instancia en verdad sea de Labrador, la referencia a través Animal no tiene ni idea sobre la existencia del método. Un buen truco para descifrar este tipo de errores es que los llamados a los métodos se definen en tiempo de compilación, es decir, si el compilador no encuentra una relación directa entre la variable usada (herencia, implementación de una interface) y el método a llamar, lo único que puede hacer es mostrar un error. Pero esto que es clave, lo intentaré explicar mejor en otra entrada. Finalmente, para invocar correctamente el método 'hacerCosasDivertidasDeLabrador()', debemos crear una instancia de la clase Labrador y apuntar a ella (aunque a mucha gente no le gusta usar la palabra apuntador en Java) con una variable de ese mismo tipo, todo este enredo textual en dos líneas de código:
Labrador labra = new Labrador();
labra.hacerCosasDivertidasDeLabrador();
Algo muy importante saber y que debe ser entendido y practicado muy bien es que lo único que se selecciona dinámicamente basado en el objeto actual (en vez de la referencia) son los métodos de instancia. No sucede ni con los métodos estáticos ni con los atributos.
El Final.
De estos temas suelen salir las preguntas más complejas del examen (sin olvidarnos de los hilos) y es clave tenerlos muy claros, por eso es importante resolver un buen número de preguntas que los abarquen.
Posted at 12:19AM jun 06, 2007 by Carlos Alexander Zuluaga in Java | Comentarios[1]


Excelente explicación me ha servido mucho para comprender la herencia y polimorfismo.
Enviado por Roberto en junio 07, 2007 a las 10:51 AM COT #