Publicaciones de Estudiantes


Francisco Javier Pabón Molina
Titulo: Principios de Programación II

Area: Information Systems
Pais:
Perfil:
Programa:

Available for Download: Yes


Diseminar información, ideas innovadoras y conocimientos académicos es una función importante para Atlantic Internacional University. Publicaremos noticias, artículos, comentarios y otras publicaciones de nuestros estudiantes y otros colaboradores. Si desea contactar al autor por motivos profesionales favor enviar su petición por este medio.

 

 


 
 
  1. Introducción
En este ensayo titulado “Principles of programming: Object Oriented Programming”
pretendo dar un recorrido a este paradigma de programación actual que es
utilizado por miles de programadores a nivel mundial, y que se ha convertido en un
estándar en el desarrollo de aplicaciones tanto de escritorio, Web e Internet y
dispositivos móviles.
A lo largo del presente texto se ira describiendo el origen, evolución, tendencias
actuales y ciertos patrones de diseño, así como una vista aunque no muy profunda
si lo mas fiel posible a un lenguaje de programación que ha revolucionado el
presente y porque no decirlo también, el futuro de la programación actual, el
lenguaje Java.
¿Por qué Java?, en lo que va de mi corta pero interesante carrera profesional en
tecnologías de información he tenido contacto con un pequeño numero de
lenguajes, desde Pascal (del cual desarrollé el ensayo de Principles of
programming I), donde se trató la programación estructurada, dando una
minúscula exploración a Delphi, lenguaje C y haciendo uso de herramientas
propietarias en las cuales he tenido mas experiencia y profundización como ser la
suite Microsoft Visual Studio 6.0 en el que comencé a dar mis primeros pasos con
este estilo de programación de objetos y el cual en la actualidad sigo utilizando,
haciendo un cambio a la plataforma .Net y lo que se ha aplica actualmente el
concepto de framework1 de desarrollo, existiendo varias tendencias o estilos;
aunque las herramientas antes mencionadas proveen de cierta facilidad y
productividad al programador y desarrollador de aplicaciones, tienen la limitación
de la plataforma y ser propietarias2 y no en muchas universidades se encuentran
disponible para la enseñanza, es aquí donde entra Java.
Como se ira viendo, Java tiene la ventaja de ser multiplataforma y detallaré más a
fondo estas características en los siguientes apartados, y si uno como profesional
aplica para obtener un trabajo en el área de la programación, es casi una
obligación desde un punto de vista personal conocer y desempeñarse en ambas
plataformas y certificarse3, para ofrecer y brindarle mayores soluciones a la
empresa, organización o individuo que requiera de sus servicios.
También se pretende dar una pequeña crítica a este estilo de programación,
porque aunque todo tiene sus ventajas y desventajas, y como dije al principio, la
comunidad de desarrolladores es muy amplia, hay muchos de los cuales aun no
están del todo conformes y prefieren todavía otros estilos y metodologías.
1 En desarrollo de software, un framework es definido como una estructura de apoyo en la cual otro proyecto de software
puede ser organizado y desarrollado.
2 El uso de herramientas propietarias, generalmente ligadas a tecnologías específicas bajo el control de determinadas
empresas, contribuye a lograr una fuerte dependencia del futuro profesional en las mismas.
3 Actualmente, certificarse es un requisito en el mercado tecnológico. La competencia es cada vez mayor y debes estar
preparado para los cambios del mercado.

Las prácticas y desarrollos se harán con el JRE 5.0 Update 6 y como IDE me he
decidido por Eclipse Project del cual también detallaré mas adelante.
Agradecer a Atlantic International University por brindarme la oportunidad de poder
mostrar mis conocimientos y adquirir y profundizar los nuevos que he elegido en
vista a un mejor crecimiento profesional.
2. Paradigma de la Programación
Un paradigma es una forma de representar y manipular el conocimiento.
Representa un enfoque particular o filosofía para la construcción o ingeniería de
software. No es mejor uno que otro sino que cada uno tiene sus ventajas y
desventajas. También hay situaciones donde un paradigma es mejor que otro.
Un paradigma provee (y determina) la vista que el programador tiene de la
ejecución del programa. Por ejemplo, en un programa orientado a objetos, los
programadores pueden pensar en un programa como una colección de interacción
de objetos, mientras en un programa funcional un programa puede ser pensado
como una secuencia de evaluaciones de función sin estado.
Tal como diferentes grupos en ingeniería de software abogan por las diferentes
metodologías, los distintos lenguajes de programación abogan por los diferentes
paradigmas de programación. Algunos lenguajes son diseñados para apoyar un
paradigma particular (Smalltalk4 y Java apoyan la programación orientada a
objetos mientras Haskell5 y Scheme6 apoyan el paradigma de programación
funcional), otros lenguajes de programación apoyan múltiples paradigmas.
Algunos ejemplos de paradigmas de programación:
El paradigma imperativo es considerado el más común y está representado, por
ejemplo, por el C7 o por BASIC8.
• El paradigma funcional está representado por la familia de lenguajes LISP9,
en particular Scheme.
• El paradigma lógico, un ejemplo es PROLOG10.
Si bien puede seleccionarse la forma pura de estos paradigmas al momento de
programar, en la práctica es habitual que se mezclen. Tal es el caso de lenguajes
como C++, Delphi o Visual Basic, los cuales combinan el paradigma imperativo
con el orientado a objetos.
Por ejemplo, C++ es diseñado para apoyar los elementos de programación
procedural, programación basada a objetos, programación orientada a objetos, y
programación genérica.
4-10 Lenguajes de programación pertenecientes a distintos paradigmas.

Uno puede escribir un programa puramente procedural en C ++, puede escribir un
Sin embargo, los diseñadores y programadores deciden como construir un
programa que usa aquellos elementos de un paradigma. programa puramente
orientado a objetos en C ++, o puede escribir un programa que contiene los
elementos de ambos paradigmas.
En estos estilos es donde entra la controversia por parte de muchos
programadores en cuanto a cual es mejor o cumple sus necesidades, y con la
evolución de los lenguajes, van aplicándose nuevos paradigmas, por ejemplo el de
programación orientada a aspectos, el cual es reciente y su intención es permitir
una adecuada modularización y posibilitar una mejor separación de conceptos.
Varias tecnologías con nombres diferentes se encaminan a la consecución de los
mismos objetivos y así, el término POA (Programación Orientada a Aspectos) es
usado para referirse a varias tecnologías relacionadas.
Muchas veces nos encontramos, a la hora de programar, con problemas que no
podemos resolver de una manera adecuada con las técnicas habituales usadas en
la programación procedural o en la programación orientada a objetos. O que en
otro lenguaje se resuelven de forma más sencilla y tratamos de evitar en la
mayoría de las veces varias líneas de código. Con éstas, nos vemos forzados a
tomar decisiones de diseño que repercuten de manera importante en el desarrollo
de la aplicación y que nos alejan con frecuencia de otras posibilidades. Pero,
como se repite en este apartado, todo tiene sus ventajas y se hará un énfasis a la
programación orientada a objetos y sus fortalezas.
Algunos diseñadores de lenguajes han dado por sentado que la programación
orientada a objetos, de por sí, no es adecuada para resolver de manera sencilla
todos los problemas de programación, y hacen referencia al uso de lenguajes de
programación multiparadigma.
La descripción de los otros paradigmas se dejara para un futuro apartado.
3. Programación orientada a objetos
Aunque existen distintas terminologías para nombrar los mismos conceptos y
características importantes de la programación orientada a objetos, abreviada
POO, es importante entender la mayoría de ellos tanto por quien la desconoce
como por aquel que la conoce.
Las computadoras, más que máquinas, pueden considerarse como herramientas
que permiten ampliar la mente ("bicicletas para la mente", como se enorgullece de
decir Steve Jobs), además de un medio de expresión inherentemente diferente.
Como resultado, las herramientas empiezan a parecerse menos a máquinas y
más a partes de nuestra mente, al igual que ocurre con otros medios de expresión
como la escritura, la pintura, la escultura, la animación o la filmación de películas.

La programación orientada a objetos (POO) es una parte de este movimiento
dirigido a utilizar las computadoras como si de un medio de expresión se tratara.
La programación orientada a objetos asevera dar mayor flexibilidad, facilitando los
cambios a los programas y es ampliamente popular en la gran escala de
ingeniería de software. Además, los que proponen la POO argumentan que es
mas fácil de aprender para quienes son nuevos en la programación de
computadoras y que su abordaje a menudo es más fácil de desarrollar y mantener
prestándose así mismo más análisis directo, codificación y entendimiento de
situaciones complejas y procedimientos comparado a otros métodos de
programación.
4. ¿Qué es la POO?
La programación orientada a objetos es una evolución lógica de la programación
estructurada, en la que el concepto de variables locales a un procedimiento o
función, que no son accesibles a otros procedimientos y funciones, se hace
extensible a los propios subprogramas que acceden a estas variables. Pero la
programación orientada a objetos va mucho más allá. En realidad, cambia la
concepción de la metodología de diseño de los programas.
En la programación orientada a objetos, se definen objetos que conforman una
aplicación. Estos objetos están formados por una serie de características y
operaciones que se pueden realizar sobre los mismos. Estos objetos no están
aislados en la aplicación, sino que se comunican entre ellos.
Los programadores que emplean lenguajes procedurales, escriben funciones y
después les pasan datos. Los programadores que emplean lenguajes orientados a
objetos definen objetos con datos y métodos y después envían mensajes a los
objetos diciendo que realicen esos métodos en sí mismos.
4.1 Conceptos fundamentales
La programación orientada a objetos hace énfasis en los siguientes conceptos:
• Abstracción: Cada objeto en el sistema sirve como modelo de un "agente"
abstracto que puede realizar trabajo, informar y cambiar su estado, y
"comunicarse" con otros objetos en el sistema sin revelar cómo se
implementan estas características. Los procesos, las funciones o los
métodos pueden también ser abstraídos y cuando los están, una variedad
de técnicas son requeridas para ampliar una abstracción. Es la habilidad de
un programa de ignorar los detalles de un objeto. Por ejemplo “Rin Tin Tin”
el perro puede ser tratado como perro la mayoría de las veces, menos
cuando es abstraído apropiadamente al nivel de canido (superclase de
perro) o carnívoro (superclase de canido) y así sucesivamente.

• Encapsulamiento: También llamada "ocultación de la información", esto
asegura que los objetos no pueden cambiar el estado interno de otros
objetos de maneras inesperadas; solamente los propios métodos internos
del objeto pueden acceder a su estado. Cada tipo de objeto expone una
interfaz a otros objetos que especifica cómo otros objetos pueden
interactuar con él. Algunos lenguajes relajan esto, permitiendo un acceso
directo a los datos internos del objeto de una manera controlada y limitando
el grado de abstracción.
• Polimorfismo: Las referencias y las colecciones de objetos pueden
contener objetos de diferentes tipos, y la invocación de un comportamiento
en una referencia producirá el comportamiento correcto para el tipo real del
objeto referenciado. Cuando esto ocurre en "tiempo de ejecución", esta
última característica se llama asignación tardía o asignación dinámica.
Algunos lenguajes proporcionan medios más estáticos (en "tiempo de
compilación") de polimorfismo, tales como las plantillas y la sobrecarga de
operadores de C++.
• Herencia: Organiza y facilita el polimorfismo y la encapsulación permitiendo
a los objetos ser definidos y creados como tipos especializados de objetos
preexistentes. Estos pueden compartir (y extender) su comportamiento sin
tener que reimplementar su comportamiento. Esto suele hacerse
habitualmente agrupando los objetos en clases o Class y las clases en
árboles o enrejados que reflejan un comportamiento común.
Cada uno de estos conceptos se irá detallando más a fondo en los siguientes
apartados.
4.2 ¿Qué es un Objeto?
La respuesta a esta pregunta en términos ajenos a la programación parece simple.
Un objeto es una persona, animal o cosa. Se distingue de otros objetos por tener
unas determinadas características y “sirve” para algo, o dicho de otra forma, se
pueden realizar distintas operaciones con/sobre ese objeto.
Por ejemplo: Una casa es un objeto.
CARACTERÍSTICAS: Número de pisos, altura total en metros, color de la
fachada, número de ventanas, número de puertas, ciudad, calle y número donde
está ubicada, etc.
OPERACIONES: Construir, destruir, pintar fachada, modificar alguna de las
características, como por ejemplo, abrir una nueva ventana, etc.
Evidentemente, cada objeto puede definirse en función de multitud de
características y se pueden realizar innumerables operaciones sobre él. Ya en
términos de programación, será misión del programador determinar qué
características y que operaciones interesa mantener sobre un objeto. Por ejemplo,

sobre el objeto casa puede no ser necesario conocer su ubicación y por lo tanto,
dichas características no formarán parte del objeto definido por el programador. Lo
mismo podría decirse sobre las operaciones.
Pensar en términos de objetos es muy parecido a cómo lo haríamos en la vida
real. Por ejemplo vamos a pensar en un coche para tratar de modelizarlo en un
esquema de POO. Diríamos que el coche es el elemento principal que tiene una
serie de características, como podrían ser el color, el modelo o la marca. Además
tiene una serie de funcionalidades asociadas, como pueden ser ponerse en
marcha, parar o aparcar.
En terminología de programación orientada a objetos, a las características del
objeto se les denomina ATRIBUTOS y a las operaciones MÉTODOS. Cada uno de
estos métodos es un procedimiento o una función perteneciente a un objeto.
Un objeto está formado por una serie de características o datos (atributos) y una
serie de operaciones (métodos). No puede concebirse únicamente en función de
los datos o de las operaciones sino en su conjunto.
4.3 Abstracción
Todos los lenguajes de programación proporcionan abstracciones. Puede incluso
afirmarse que la complejidad de los problemas a resolver es directamente
proporcional a la clase (tipo) y calidad de las abstracciones a utilizar, entendiendo
por tipo "clase", aquello que se desea abstraer. El lenguaje ensamblador es una
pequeña abstracción de la máquina subyacente. Muchos de los lenguajes
denominados "imperativos" desarrollados a continuación del antes mencionado
ensamblador (como Fortran, BASIC y C) eran abstracciones a su vez del lenguaje
citado. Estos lenguajes supusieron una gran mejora sobre el lenguaje
ensamblador, pero su abstracción principal aún exigía pensar en términos de la
estructura del computador más que en la del problema en sí a resolver. El
programador que haga uso de estos lenguajes debe establecer una asociación
entre el modelo de la máquina (dentro del "espacio de la solución", que es donde
se modela el problema, por ejemplo, un computador) y el modelo del problema
que de hecho trata de resolver (en el "espacio del problema", que es donde de
hecho el problema existe).

La abstracción consiste en aislar un elemento de su contexto o del resto de los
elementos que lo acompañan. El término se refiere al énfasis en el "¿qué hace?"
más que en el "¿cómo lo hace?". El común denominador en la evolución de los
lenguajes de programación, desde los clásicos o imperativos hasta los orientados
a objetos, ha sido el nivel de abstracción del que cada uno de ellos hace uso.
Se sabe que los lenguajes de programación son las herramientas mediante las
cuales los diseñadores de lenguajes pueden implementar los modelos abstractos.
La abstracción ofrecida por los lenguajes de programación se puede dividir en dos
categorías: abstracción de datos (pertenecientes a los datos) y abstracción de
control (perteneciente a las estructuras de control).
La abstracción encarada desde el punto de vista de la programación orientada a
objetos expresa las características esenciales de un objeto, las mismas distinguen
al objeto de los demás. Además de distinguir entre los objetos provee límites
conceptuales. Entonces se puede decir que la encapsulación separa las
características esenciales de las no dentro de un objeto. Si un objeto tiene mas
características de las necesarias los mismos resultarán difíciles de usar, modificar,
construir y comprender.
La misma genera una ilusión de simplicidad dado a que minimiza la cantidad de
características que definen a un objeto.
Y todo es un objeto. Hay que pensar en cualquier objeto como una variable:
almacena datos, permite que se le "hagan peticiones", pidiéndole que desempeñe
por sí mismo determinadas operaciones, etc. En teoría, puede acogerse cualquier
componente conceptual del problema a resolver (bien sean perros, edificios,
servicios, etc.) y representarlos como objetos dentro de un programa.
4.4 Métodos y mensajes
Un término que se utiliza más frecuentemente en Java y POO es método, al ser
"una manera de hacer algo". Si se desea, es posible seguir pensando en
funciones. Verdaderamente sólo hay una diferencia sintáctica, pero de ahora en
adelante se usará el término "método" en lugar del término "función".
Los métodos son las operaciones que pueden realizarse sobre el objeto, que
normalmente estarán incorporados en forma de programas (código) que el objeto
es capaz de ejecutar y que también pone a disposición de sus descendientes a
través de la herencia.
Las partes fundamentales de un método son su nombre, sus parámetros, el tipo
de retorno y el cuerpo.
He aquí su forma básica:
tipoRetorno nombreMetodo ( /* lista de parámetros */ ) {

/ * Cuerpo del método */
}
El tipo de retorno es el tipo del valor que surge del método tras ser invocado. La
lista de parámetros indica los tipos y nombres de las informaciones que es
necesario pasar a ese método. Cada método se identifica unívocamente mediante
el nombre del método y la lista de parámetros.
En Java los métodos pueden crearse como parte de una clase. Es posible que un
método pueda ser invocado sólo por un objeto2, y ese objeto debe ser capaz de
llevar a cabo esa llamada al método. Si se invoca erróneamente a un método de
un objeto, se generará un error en tiempo de compilación. Se invoca a un método
de un objeto escribiendo el nombre del objeto seguido de un punto y el nombre del
método con su lista de argumentos, como: nombreObjeto.nombreMetodo (arg1,
arg2, arg3). Por ejemplo, si se tiene un método f ( ) que no recibe ningún
parámetro y devuelve un dato de tipo int, y si se tiene un objeto a para el que
puede invocarse a f ( ), es posible escribir:
int x = a.f ();
El tipo del valor de retorno debe ser compatible con el tipo de x.
Este acto de invocar a un método suele denominarse envío de un mensaje a un
objeto. En el ejemplo de arriba, el mensaje es f ( ) y el objeto es a. La
programación orientada a objetos suele resumirse como un simple "envío de
mensajes a objetos".
Un ejemplo claro sería el siguiente:
. Ejemplo de Clase Mamífero:
Datos Métodos
Color Desplazarse
Tamaño Masticar
Peso Digerir
Cantidad de dientes Respirar
Cuadrúpedo/bípedo Parpadear
Edad Dormir
Ahora veamos un ejemplo más cercano a la informática: Una ventana. Clase
Ventana:

Datos Métodos
Etiqueta de encabezado
Cerrarse
Abrirse
Tipo de letra encabezado Minimizarse
Maximizarse
Color de Fondo
Color de letra encabezado
Como puede verse, en esencia la POO lo que nos permite es ampliar el tipo de
datos con los que se puede trabajar.
Todos los hombres comparten las características de la clase hombre. Sin
embargo todos los hombres son distintos entre sí, en estatura, pigmentación, etc.
A cada uno de los hombres particulares se le llama “objetos de la clase
hombre”. Cada niño que nace es una instanciación de la clase hombre.
Entonces, los métodos los podemos considerar sinónimos de comportamientos,
operaciones, procedimientos.
La aplicación de los métodos dará distintos resultados dependiendo de los
valores con los que trabaje.
Para poder mandar mensajes a los objetos, necesitamos un operador, a este le
llamamos el operador de envío. Cada lenguaje puede tener el suyo, pero es
frecuente que se utilicen los dos puntos (‘:’) o el punto (‘.’) (En C++ es el punto
simple, igual que para referirnos a los elementos de los struct’s).
Así, si queremos enviarle el mensaje Caminar al objeto Juan de la clase hombre,
escribiríamos lo siguiente:
El operador de envío hace que se ejecute la porción del código agrupada bajo el
nombre del método, y el método trabajara con los datos propios de la instancia de
la clase a la que se refiera.

Referencias a sí mismo
Un caso especial ocurre cuando estamos codificando un método de una clase y
tenemos que referirnos a un dato o un método del propio objeto; estamos creando
la clase, o por así decirlo, dentro del objeto mismo.
Entonces, para referirse al propio objeto, en OOP se hace uso de el mismo, si
mismo, self (en ingles). Self (algunos lenguajes utilizan “self”, pero lo mas común
es que utilicen “this”11: así lo hacen C++ y Java, por ejemplo.) en OOP se refiere al
propio objeto con el que se esta trabajando. Por lo tanto, si estamos escribiendo
un método de una clase y queremos enviar un mensaje al propio objeto,
escribiríamos:
This.Ocultar ( );
En este punto, puede parecer que un programa no es más que un montón de
objetos con métodos que toman otros objetos como parámetros y envían
mensajes a esos otros objetos. Esto es, sin duda, mucho de lo que está curriendo,
pero en otros apartados se verá cómo hacer el trabajo de bajo nivel detallado,
tomando decisiones dentro de un método.
4.5 Encapsulado y ocultación de la información: Clases
El concepto de clase, es simplemente una abstracción que hacemos de nuestra
experiencia sensible. El ser humano tiende a agrupar seres o cosas –objetos- con
características similares en grupos –clases-. Así, aun cuando existen por ejemplo
multitud de vasos diferentes, podemos reconocer un vaso en cuanto lo vemos,
incluso aun cuando ese modelo concreto de vaso no lo hayamos visto nunca. El
concepto vaso es una abstracción de nuestra experiencia sensible. Al igual que
ciertos ejemplos que pusimos en el apartado anterior.
Quizás el ejemplo mas claro para exponer esto lo tengamos en las taxonomías;
los biólogos han dividido a todo ser (vivo o inerte) sobre la tierra en clases.
11 ver el apartado 12.5

Ellos, llaman a cada una de estas parcelas reino, tipo, clase, especie, orden,
familia, género, etc.; sin embargo, nosotros a todas las llamaremos del mismo
modo: clase. Así, hablaremos de la clase animal, clase vegetal y clase mineral, o
de la clase félidos y de las clases leo (león) y tigres (tigre).
Cada clase posee unas cualidades que la diferencian de las otras. Así, por
ejemplo, los vegetales se diferencian de los minerales –entre otras muchas cosas-
en que los primeros son seres vivos y los minerales no. De los animales se
diferencian en que las plantas son capaces de sintetizar clorofila a partir de la luz
solar y los animales no.
Como vemos, el ser humano tiende, de un modo natural a clasificar los objetos del
mundo que le rodean en clases; son definiciones estructuralistas de la naturaleza
al estilo de la escuela francesa de Saussure12.
Encapsulación
Un método de una clase puede llamar a otros métodos de su misma clase y pude
cambiar los valores de los datos de su misma clase. Es esta la forma correcta de
hacerse: los datos de una clase solo deben ser alterados por los métodos de su
clase; y no de forma directa (que es como cambiamos los valores de las variables
en un programa). Esta es una regla de oro que no debe de olvidarse: todos los
datos de una clase son privados y se accede a ellos mediante métodos
públicos.
12 Ferdinand de Saussure. Lingüista suizo, considerado el fundador de la lingüística moderna.

Según los dos modos comentados, tomemos como ejemplo un objeto
perteneciente a la clase marco, modificaremos su dato nY1 (coordenada superior
izquierda) de dos modos distintos: directamente y mediante el método PonerY1 ( ).
Cambio directo: oCajaGeneral.nY1 = 12;
Cambio mediante invocación de método: oCajaGeneral.PonerY1 (12);
Es más cómodo el primer método, ya que hay que escribir menos para cambiar el
valor del dato y además, a la hora de construir la clase, no es necesario crear un
método para cambiar cada uno de los datos del objeto. Sin embargo, y como se
ha ido comentando, la OOP recomienda efusivamente que se utilice el segundo
procedimiento. La razón es bien simple: una clase debe ser una estructura
cerrada, no se debe poder acceder a ella si no es a través de los métodos
definidos para ella. Si hacemos nY1 público (para que pueda ser accedido
directamente), estamos violando el principio de encapsulación.
Encapsulación es la característica de la POO que hace que un objeto sea una
caja negra. Se le envía un mensaje al objeto y este responde ejecutando el
método apropiado.
Un método de una clase puede llamar a métodos de la misma clase.
Gracias a la encapsulación una clase que ha sido programada y probada puede
usarse sin temor a que la programación de otros objetos basados en dichas clases
tengan errores.
En lugar de considerar el programa como una enorme entidad, la encapsulación
permite dividir un programa en componentes más pequeños e independientes.
Cada componente es autónomo y realiza su labor independientemente de los
demás componentes.
La encapsulación mantiene esa independencia ocultando los detalles internos de
cada componente, mediante una interfaz externa.
Una interfaz lista los servicios proporcionados por un componente. La interfaz
actúa como un contrato con el mundo exterior que define exactamente lo que una
entidad externa puede hacer con el objeto.
Una interfaz es un panel de control para el objeto. Al definir una interfaz puede
especificarse cuales métodos serán definidos como públicos, privados y
protegidos.
Los métodos públicos son aquellos que están disponibles para todo aquel que
cree objetos basados en la clase.

Los métodos privados son aquellos que solo son invocados por otros métodos de
la clase.
Cuando un comportamiento se desee poner a disposición del mundo exterior,
debe tener acceso público. Lo que se desee ocultar debe tener acceso
protegido o privado.
¿Porqué utilizar encapsulación?
. Independencia: Se puede reutilizar el objeto en cualquier parte. Cuando se
encapsulan de forma apropiada los objetos, estos no están limitados a un
programa en particular. Para utilizarlo solo hay que poner en acción su
interfaz.
. Transparencia: La encapsulación le permite hacer cambios transparentes
al objeto, en tanto no se altere la interfaz.
. Autonomía: El uso de un objeto encapsulado no causará efectos
secundarios inesperados entre el objeto y el resto del programa. Puesto
que el objeto es autónomo, no tendrá ninguna interacción con el programa
más allá de lo establecido por la interfaz.
Gracias a la encapsulación, una clase, cuando ha sido programada y probada
hasta comprobar que no tiene fallos, podemos usarla sin miedo a que al
programar otros objetos estos puedan interferir con los primeros produciendo
efectos colaterales indeseables que arruinen nuestro trabajo; esto también permite
depurar (eliminar errores de programación) con suma facilidad, ya que si un objeto
falla, el error solo puede estar en esa clase y no en ninguna otra.
4.6 Modularidad
Un modulo puede definirse diversamente, pero generalmente debe ser un
componente de un sistema mas grande, y opera independientemente dentro de
las funciones de ese sistema con los otros componentes.
La modularidad es la propiedad que mide hasta que punto han estado
compuestos de partes separadas llamadas módulos. Los programas tienen
muchas relaciones mutuas directas entre cualquiera de dos partes aleatorias del
código del programa.
4.7 Polimorfismo
Se denomina polimorfismo a la capacidad del código de un programa para ser
utilizado con diferentes tipos de datos u objetos. También se puede aplicar a la
propiedad que poseen algunas operaciones de tener un comportamiento diferente
dependiendo del objeto (o tipo de dato) sobre el que se aplican.

El concepto de polimorfismo se puede aplicar tanto a funciones como a tipos de
datos. Así nacen los conceptos de funciones polimórficas y tipos polimórficos. Las
primeras son aquellas funciones que pueden evaluarse y/o ser aplicadas a
diferentes tipos de datos de forma indistinta; los tipos polimórficos, por su parte,
son aquellos tipos de datos que contienen al menos un elemento cuyo tipo no está
especificado.
Se puede clasificar el polimorfismo en dos grandes clases:
• Polimorfismo dinámico (o polimorfismo ad hoc) es aquél en el que el
código no incluye ningún tipo de especificación sobre el tipo de datos sobre
el que se trabaja. Así, puede ser utilizado a todo tipo de datos compatible.
• Polimorfismo estático (o polimorfismo paramétrico) es aquél en el que
los tipos a los que se aplica el polimorfismo deben ser explicitados y
declarados uno por uno antes de poder ser utilizados.
El polimorfismo dinámico unido a la herencia es lo que en ocasiones se conoce
como programación genérica.
Pongamos por ejemplo las clase hombre, vaca y perro, si todos les damos la
orden –enviamos el mensaje-Come, cada uno de ellos sabe como hacerlo y
realizara este comportamiento a su modo.
Veamos otro ejemplo algo más ilustrativo. Tomemos las clases barco, avión y
coche, todas ellas derivadas de la clase padre vehículo; si les enviamos el
mensaje Desplázate, cada una de ellas sabe como hacerlo.
Realmente, y para ser exactos, los mensajes no se envían a las clases, sino a
todos o algunos de los objetos instaciados de las clases. Así, por ejemplo,
podemos decirle a los objetos Juan Sebastián el Cano y Kontiqui, de la clase
barco que se desplacen, con los que el resto de los objetos de esa clase
permanecerán inmóviles.
Del mismo modo, si tenemos en pantalla cinco recuadros (marcos) y tres textos,
podemos decirle a tres de los recuadros y a dos de los textos que cambien de
color y no decírselo a los demás objetos. Todos estos sabrán como hacerlo
porque hemos redefinido para cada uno de ellos su método Pintarse que bien
podría estar en la clase padre Visual (conjunto de objetos que pueden visualizarse
en pantalla).
En programación tradicional, debemos crear un nombre distinto para la acción de
pintarse, si se trata de un texto o de un marco; en POO el mismo nombre nos sirve
para todas las clases creadas si así lo queremos, lo que suele ser habitual. El
mismo nombre suele usarse para realizar acciones similares en clases diferentes.

Si enviamos el mensaje Imprímete a objetos de distintas clases, cada uno se
imprimirá como le corresponda, ya que todos saben como hacerlo.
El polimorfismo facilita el trabajo, ya que gracias a él, el número de nombre de
métodos que tenemos que recordar disminuye ostensiblemente.
La mayor ventaja la obtendremos en métodos con igual nombre aplicados a las
clases que se encuentran próximas a la raíz del árbol de clases, ya que estos
métodos afectaran a todas las clases que de ellas se deriven.
4.8 Jerarquización: Herencia y Objetos compuestos
Herencia
Esta es la cualidad más importante de un sistema POO, la que nos dará mayor
potencia y productividad, permitiéndonos ahorrar horas y horas de codificación y
de depuración de errores.
Sería mejor si pudiéramos hacer uso de una clase ya existente, clonarla, y
después hacer al "clon" las adiciones y modificaciones que sean necesarias.
Efectivamente, esto se logra mediante la herencia, con la excepción de que si se
cambia la clase original (denominada la clase base, clase súper o clase padre), el
"clon" modificado (denominado clase derivada, clase heredada, subclase o clase
hijo) también reflejaría esos cambios.
Puede haber más de una clase derivada. Un tipo hace más que definir los límites
de un conjunto de objetos; también tiene relaciones con otros tipos. Dos tipos
pueden tener características y comportamientos en común, pero un tipo puede
contener más características que otro y también puede manipular más mensajes
(o gestionarlos de manera distinta). La herencia expresa esta semejanza entre
tipos haciendo uso del concepto de tipos base y tipos derivados. Un tipo base
contiene todas las características y comportamientos que comparten los tipos que
de él se derivan. A partir del tipo base, es posible derivar otros tipos para expresar
las distintas maneras de llevar a cabo esta idea.
Por ejemplo, una máquina de reciclaje de basura clasifica los desperdicios. El tipo
base es "basura", y cada desperdicio tiene su propio peso, valor, etc. y puede ser
fragmentado, derretido o descompuesto.
Así, se derivan tipos de basura más específicos que pueden tener características
adicionales (una botella tiene un color), o comportamientos (el aluminio se puede
modelar, una lata de acero tiene capacidades magnéticas). Además, algunos
comportamientos pueden ser distintos (el valor del papel depende de su tipo y
condición). El uso de la herencia permite construir una jerarquía de tipos que
expresa el problema que se trata de resolver en términos de los propios tipos.

Un segundo ejemplo es el clásico de la "figura geométrica" utilizada generalmente
en sistemas de diseño por computador o en simulaciones de juegos. El tipo base
es "figura" y cada una de ellas tiene un tamaño, color, posición, etc. Cada figura
puede dibujarse, borrarse, moverse, colorearse, etc.
A partir de ésta, se pueden derivar (heredar) figuras específicas: círculos,
cuadrados, triángulos, etc., pudiendo tener cada uno de los cuales características
y comportamientos adicionales. Algunos comportamientos pueden ser distintos,
como pudiera ser el cálculo del área de los distintos tipos de figuras. La jerarquía
de tipos engloba tanto las similitudes como las diferencias entre las figuras.
Otro ejemplo, la clase león que se comenta en la figura de la clasificación
taxonómica en el apartado 4.5, hereda cualidades –métodos- de todas las clases
predecesoras –padres- y posee métodos propios, diferentes a los del resto de las
clases. Es decir, las clases van especializándose según se avanza en el árbol
taxonómico. Cada vez que creamos una clase heredada de otra (la padre)
añadimos métodos a la clase padre o modificamos alguno de los métodos de la
clase padre.
Veamos que hereda la clase león de sus clases padre:
Clase Que hereda
Vertebrados Espina dorsal
Mamíferos Se alimenta con leche materna
Carnívoros Al ser adultos se alimentan de carne
La clase león hereda todos los métodos de las clases padre y añade métodos
nuevos que forman su clase distinguiéndola del resto de las clases: por ejemplo el
color de su piel.
Pongamos ahora un ejemplo algo más informático: supongamos que usted ha
construido una clase que le permite leer números enteros desde teclado con un
formato determinado, calcular su IVA y almacenarlos en un archivo. Si desea
poder hacer lo mismo con números reales (para que admitan decimales), solo
deberá crear una nueva subclase para que herede de la clase padre todos sus

métodos y redefinirá solo el método de lectura de teclado. Esta nueva clase sabe
almacenar y mostrar los números con formato porque lo sabe su clase padre.
Las cualidades comunes que comparten distintas clases, pueden y deben
agruparse para formar una clase padre. Por ejemplo, usted podría derivar las
clases presupuesto y factura de la superclase pedidos, ya que estas clases
comparten características comunes. De este modo, la clase padre poseería los
métodos comunes a todas ellas y solo tendríamos que añadir aquellos métodos
propios de cada una de las subclases, pudiendo reutilizar el código escrito en la
superclase desde cada una de las clases derivadas. Así, si enseñamos a la clase
padre a imprimirse, cada uno de los objetos de las clases inferiores sabrán
automáticamente y sin escribir ni una sola línea más de código imprimirse.
Es así, que la herencia es la cualidad mas importante de la POO ya que le permite
reutilizar todo el código escrito para las superclases re-escribiendo solo aquellas
diferencias que existan entre estas y las subclases.
Muchas veces las clases –especialmente aquellas que se encuentran próximas a
la raíz en el árbol de la jerarquía de clases- son abstractas. Es decir, solo existen
para proporcionar una base para la creación de clases mas especificas, y por lo
tanto no puede instanciarse de ellas; son las clases virtuales.
Una subclase hereda de su superclase solo aquellos miembros visibles desde la
clase hija y por lo tanto solo puede redefinir estos.
Una subclase tiene forzosamente que redefinir aquellos métodos que han sido
definidos como abstractos en la clase padre o padres.
Es habitual que la herencia suscite un pequeño debate: ¿debería la herencia
superponer sólo las funciones de la clase base (sin añadir nuevas funciones
miembro que no se encuentren en ésta)?. Esto significaría que el tipo derivado sea
exactamente el mismo tipo que el de la clase base, puesto que tendría
exactamente la misma interfaz. Consecuentemente, es posible sustituir un objeto
de la clase derivada por otro de la clase base. A esto se le puede considerar
sustitución pura, y a menudo se le llama el principio de sustitución. De cierta
forma, ésta es la manera ideal de tratar la herencia. Habitualmente, a la relación
entre la clase base y sus derivadas que sigue esta filosofía se le denomina
relación es-un, pues es posible decir que "un círculo es un polígono". Una manera
de probar la herencia es determinar si es posible aplicar la relación es-un a las
clases en liza, y tiene sentido.
Hay veces en las que es necesario añadir nuevos elementos a la interfaz del tipo
derivado, extendiendo así la interfaz y creando un nuevo tipo. Éste puede ser
también sustituido por el tipo base, pero la sustitución no es perfecta pues las
nuevas funciones no serían accesibles desde el tipo base. Esta relación puede
describirse como la relación es-como-un" el nuevo tipo tiene la interfaz del viejo

pero además contiene otras funciones, así que no se puede decir que sean
exactamente iguales. Considérese por ejemplo un acondicionador de aire.
Supongamos que una casa está cableada y tiene las botoneras para refrescarla,
es decir, tiene una interfaz que permite controlar la temperatura. Imagínese que se
estropea el acondicionador de aire y se reemplaza por una bomba de calor que
puede tanto enfriar como calentar. La bomba de calor es-como-un acondicionador
de aire, pero puede hacer más funciones. Dado que el sistema de control de la
casa está diseñado exclusivamente para controlar el enfriado, se encuentra
restringido a la comunicación con la parte "enfriadora" del nuevo objeto. Es
necesario extender la interfaz del nuevo objeto, y el sistema existente únicamente
conoce la interfaz original.
Por supuesto, una vez que uno ve este diseño, está claro que la clase base
"sistema de enfriado" no es lo suficientemente general, y debería renombrarse a
"sistema de control de temperatura" de manera que también pueda incluir
calentamiento -punto en el que el principio de sustitución funcionará. Sin embargo,
este diagrama es un ejemplo de lo que puede ocurrir en el diseño y en el mundo
real.
Cuando se ve el principio de sustitución es fácil sentir que este principio (la
sustitución pura) es la única manera de hacer las cosas, y de hecho, es bueno
para los diseños que funcionen así. Pero hay veces que está claro que hay que
añadir nuevas funciones a la interfaz de la clase derivada.
4.9 Ligadura Dinámica
La ligadura en las llamadas a métodos
La conexión de una llamada a un método se denomina ligadura. Cuando se lleva a
cabo la ligadura antes de ejecutar el programa (por parte del compilador y el
montador, cuando lo hay) se denomina ligadura temprana. Puede que este
término parezca extraño pues nunca ha sido una opción con los lenguajes
procedurales. Los compiladores de C tienen un único modo de invocar a un
método utilizando la ligadura temprana.

La solución es la ligadura tardía, que implica que la correspondencia se da en
tiempo de ejecución, basándose en el tipo de objeto. La ligadura tardía se
denomina también dinámica o en tiempo de ejecución.
Cuando un lenguaje implementa la ligadura tardía, debe haber algún mecanismo
para determinar el tipo de objeto en tiempo de ejecución e invocar al método
adecuado. Es decir, el compilador sigue sin saber el tipo de objeto, pero el
mecanismo de llamada a métodos averigua e invoca al cuerpo de método
correcto. El mecanismo de la ligadura tardía varía de un lenguaje a otro, pero se
puede imaginar que es necesario instalar algún tipo de información en los objetos.
Toda ligadura de métodos en Java se basa en la ligadura tardía a menos que se
haya declarado un método como constante. Esto significa que ordinariamente no
es necesario tomar decisiones sobre si se dará la ligadura tardía, sino que esta
decisión se tomará automáticamente.
5. Diseño tradicional vrs. Diseño OO
Como hemos visto hasta ahora, el Diseño Orientado a Objetos ofrece muchas
alternativas para la resolución de problemas al programador, y hemos mencionado
también los distintos paradigmas de programación.
Ahora, repasemos puntos clave del diseño OO:
• El diseño OO se enfoca sobre objetos y clases basados en el mundo real.
• Hace un énfasis en el estado, comportamientos e interacciones de objetos
• Provee las siguientes ventajas:
o Desarrollo rápido de aplicaciones (RAD)
o Aumenta la calidad
o Provee un fácil mantenimiento
o Mejora la modificación
o Incrementa el reutilizamiento de software
Pero como todo en este mundo, también tiene sus limitaciones e inconvenientes.
De las primeras no cabe ni hablar, porque aun cuando sea el sistema mas
apropiado del que se dispone para programar, todavía se enfrenta con ciertos
problemas de diseño.
El mayor inconveniente real proviene de un “error” de planteamiento; y como casi
siempre, estos son de mucha mayor dificultad a la hora de solucionarlos. El
problema, según comenta uno de los mejores analistas de hoy en día, Jeff
Duntemann15, en un articulo de la revista Dr. Dobbs16, es que “la encapsulación y
la herencia se hallan en esquinas opuestas de la casa”.
15 Escritor, Editor, Tecnólogo. Más en www.duntemann.com
16 Dr. Dobbs Journal, más en www.ddj.com

Es decir, la encapsulación choca frontalmente con la herencia, y sin embargo, son
dos piedras angulares de la POO.
Por un lado decimos que los objetos deben ser totalmente independientes y
autónomos, y por otro, al heredar unas clases de otras, estamos dejando fuera de
un objeto perteneciente a una clase hija gran parte de la información que esta
necesita para poder comportarse.
Otro inconveniente que se puede observar es el que estriba en la imposibilidad de
utilización conjunta de objetos de distintos programadores.
Un ejemplo simple, supongamos que se monta un coche en un garaje, puede
comprar un carburador de cualquier marca y montarlo en un coche de otra marca,
unos asientos de uno y montarlos en la carrocería de otro; esto mismo puede
hacerse en POO.
Si Microsoft fabrica la clase Menú, que deriva de la clase Visual y Borland fabrica
la clase Ventana aunque también derive de la clase Visual, no puede conseguir
coger el menú de una y la ventana de la otra, a menos que todas las clases
superiores (en este caso solo una) sean exactamente iguales: tengan el mismo
nombre, contengan los mismos datos y los mismos métodos y en estos, todos los
parámetros deben coincidir en orden y en tipo.
Este problema por ahora no tiene solución, y lo peor es que no se vislumbra que la
tenga en un futuro próximo, ya que para ello seria necesario normalizar las clases
(al menos las mas habituales), pero si no nos ponemos de acuerdo para utilizar un
mismo HTML ¿Cómo nos vamos a poner de acuerdo para esto?
Critica
Los taxonomías jerárquicas no coinciden a menudo con el mundo real y los
cambios del mundo real según algunos críticos, y debe evitarse. Sin embargo,
muchos defensores de POO también hacen pensar en evitar las jerarquías y usar
las técnicas de POO en cambio como la composición.
También, muchos sienten que POO corre lo opuesto a la filosofía de planeación
correlativa y base de datos relacionales, mientras se vuelve a los arreglos de la
base de datos de navegación de los años sesenta. No está claro que ésta es la
falta de POO, desde que la planeación de bases de datos es fundamentalmente
basada en las diferentes premisas que la planeación basada en objetos. En
cualquier caso, las bases de datos relacionales trazan a las asociaciones en los
modelos basados en objetos, y las diferencias parecen ser completamente
debidas a las diferencias en el enfoque.
Hay una historia de desinterpretación de la relación entre planear basado en
objetos y en la correlación a lo que puede enturbiar este problema. Hay también,
variaciones en las opiniones sobre los papeles y definiciones de cada uno.

La desigualdad de impedancia entre las bases de datos y POO se causa por la
diferencia de balanza entre funcionamientos realizados por los objetos y bases de
datos; las transacciones de la base de datos, la unidad más pequeña de trabajo
realizada por las bases de datos, son mucho más grandes que cualquier
funcionamiento proporcionado por los objetos de POO.
Mientras se exige que POO es buena para "aplicaciones grandes”, otros sienten
que deben reducirse las aplicaciones grandes en cambio a muchas aplicaciones
pequeñas, como procedimientos manejados a eventos que " se alimentan" fuera
de una base de datos y armazones de interfaz de usuario basadas en
declaratorias de programación.
Está reconocido que POO necesariamente no quiere decir falta de complejidad.
6. Evolución de los Lenguajes Orientados a Objetos
Los conceptos de la programación orientada a objetos tienen origen en Simula 67,
un lenguaje diseñado para hacer simulaciones, creado por Ole-Johan Dahl y
Kristen Nygaard del Centro de Cómputo Noruego en Oslo. Según se informa, la
historia es que trabajaban en simulaciones de naves, y fueron confundidos por la
explosión combinatoria de cómo las diversas cualidades de diversas naves podían
afectar unas a las otras. La idea ocurrió para agrupar los diversos tipos de naves
en diversas clases de objetos, siendo responsable cada clase de objetos de definir
sus propios datos y comportamientos. Fueron refinados más tarde en Smalltalk,
que fue desarrollado en Simula en Xerox PARC(Palo Alto Research Center) pero
diseñado para ser un sistema completamente dinámico en el cual los objetos se
podrían crear y modificar "en marcha" en lugar de tener un sistema basado en
programas estáticos.
La programación orientada a objetos tomó posición como la metodología de
programación dominante a mediados de los años ochenta, en gran parte debido a
la influencia de C++, una extensión del lenguaje de programación C. Su
dominación fue consolidada gracias al auge de las Interfaces gráficas de usuario
(GUI por sus siglas en ingles), para los cuales la programación orientada a objetos
está particularmente bien adaptada.
En el ETH de Zürich, Niklaus Wirth y sus colegas tuvieron también investigaciones
como tópicos de abstracción de datos y programación modular. El lenguaje
Modula-2 incluye ambos, y su diseño sucesor, Oberon incluye una aproximación
distintiva a orientación a objetos, clases y semejantes. El acercamiento es
diferente a Smalltalk, y muy diferente a C++.
Las características de Orientación a Objetos han sido añadidas a muchos
lenguajes existentes durante el tiempo, incluyendo Ada, BASIC, Lisp, Fortran,
Pascal, y otros. Agregando esos aspectos a lenguajes que no fueron inicialmente
diseñados para ello condujo a problemas con la compatibilidad y mantenimiento
de código. Los lenguajes Orientados a Objetos “Puros”, por otra parte, carecían de

aspectos que muchos programadores han venido dependiendo. Para cruzar esta
brecha, muchos intentos han sido hechos para crear nuevos lenguajes basados en
métodos Orientados a Objetos pero permitiendo algunos aspectos procedurales
en formas “seguras”.
El lenguaje Eiffel de Bertrand Meyer’s17 fue un temprano y moderadamente exitoso
lenguaje con esos objetivos.
En la década pasada Java ha emergido ampliamente en uso parcialmente por su
similitud a C y C++, pero quizás lo más importante de su implementación es el uso
de una maquina virtual que es proyectada a correr código inalterado sobre muchas
plataformas distintas. Esta ultima característica lo ha hecho muy atractivo en
amplias tiendas de desarrollo y ambientes heterogéneos.
La iniciativa de la plataforma .NET de Microsoft ha tenido un objetivo similar e
incluye/soporta varios nuevos lenguajes, o variantes de algunos viejos.
Más recientemente, un número de lenguajes ha surgido para ser primariamente
orientados a objetos aun compatibles con la metodología procedural, tales como
Python y Ruby. Al lado de Java, probablemente el mas comercial lenguaje
orientado a objetos reciente es Visual Basic .NET y C# diseñados para la
plataforma .NET de Microsoft.
Tal como la programación procedural lleva a refinamientos de técnicas como la
programación estructurada, el software orientado a objetos moderno diseña
métodos que incluye refinamiento como el uso de diseño de patrones, diseño por
convenios, y lenguajes de modelado (tal es UML, usado en ingeniería de
software).
17 Bertrand Meyer, (nacido en Francia en 1950). Es uno de los primeros y vocales más proponentes de la POO. Sus libros
sobre “Construcción de Software” son considerados los mejores trabajos presentes para la presentación de POO.

Para el aprendizaje
En el pasado, han existido muchas disputas como cual es el mejor lenguaje para
comenzar con la programación orientada a objetos. Hay dos diferentes enfoques a
tomar cuando se comienza con este estilo de programación. El primero es la idea
que lo mejor es empezar con un lenguaje simple como Java, donde el aprendizaje
se enfoca sobre la orientación a objetos y no es perturbado por semánticas
complejas del lenguaje. Aun así, otra razón es que lo mejor es empezar con un
lenguaje más complicado como C++, el cual soporta con más precisión todas las
estructuras y capacidades prescritas por el lenguaje de modelado unificado (UML),
aunque no hay un lenguaje conocido el cual esencialmente soporte totalmente las
capacidades de UML. En la versión utilizada para el entorno de desarrollo Eclipse
para este ensayo esta instalado la versión Eclipse UML 3.10 Free Edition de
Omondo.
7. Lenguajes orientados a objetos
Entre los lenguajes orientados a objetos destacan los siguientes:
• Smalltalk
• Objective-C
• C++
• Ada 95
• Java
• Ocaml
• Python
• Delphi
• Lexico (en castellano)
• C#
• Eiffel
• Ruby
• ActionScript
• Visual Basic
• PHP
• PowerBuilder
• Clarion
Estos lenguajes de programación son muy avanzados en orientación a objetos.
Al igual que C++ otros lenguajes, como OOCOBOL, OOLISP, OOPROLOG y
Object REXX, han sido creados añadiendo extensiones orientadas a objetos a un
lenguaje de programación clásico.
Un nuevo paso en la abstracción de paradigmas de programación es la
Programación Orientada a Aspectos (POA). Aunque es todavía una metodología

en estado de maduración, cada vez atrae a más investigadores e incluso
proyectos comerciales en todo el mundo.
8. Java
8.1 ¿Qué es Java?
Java es un lenguaje de desarrollo de propósito general, y como tal es válido para
realizar todo tipo de aplicaciones profesionales.
Entonces, ¿es simplemente otro lenguaje más? Definitivamente no. Incluye una
combinación de características que lo hacen único y está siendo adoptado por
multitud de fabricantes como herramienta básica para el desarrollo de aplicaciones
comerciales de gran repercusión.
¿Qué lo hace distinto de los demás lenguajes?
Una de las características más importantes es que los programas “ejecutables”,
creados por el compilador de Java, son independientes de la arquitectura. Se
ejecutan indistintamente en una gran variedad de equipos con diferentes
microprocesadores y sistemas operativos.
• De momento, es público. Puede conseguirse un JDK (Java Developer's Kit) o
Kit de desarrollo de aplicaciones Java gratis. No se sabe si en un futuro seguirá
siéndolo.
• Permite escribir Applets (pequeños programas que se insertan en una página
HTML) y se ejecutan en el ordenador local.
• Se pueden escribir aplicaciones para intrarredes, aplicaciones cliente/servidor,
aplicaciones distribuidas en redes locales y en Internet.
• Es fácil de aprender y está bien estructurado.
• Las aplicaciones son fiables. Puede controlarse su seguridad frente al acceso a
recursos del sistema y es capaz de gestionar permisos y criptografía. También,
según Sun, la seguridad frente a virus a través de redes locales e Internet está
garantizada. Aunque al igual que ha ocurrido con otras tecnologías y
aplicaciones, se han descubierto, y posteriormente subsanado, “agujeros” en la
seguridad de Java.
¿Qué se puede programar con Java?
Si tenía preconcebida la idea de que con Java sólo se programan applets para
páginas Web, está completamente equivocado. Ya que Java es un lenguaje de
propósito general, puede programarse en él cualquier cosa:
• Aplicaciones independientes. Como con cualquier otro lenguaje de propósito
general.
• Applets. Pequeñas aplicaciones que se ejecutan en un documento HTML,
siempre y cuando el navegador soporte Java, como ocurre con los

navegadores HotJava y las últimas versiones de Netscape y el explorador de
Internet de Microsoft.
Para todo aquel que no conozca la programación orientada a objetos, este
lenguaje es ideal para aprender todos sus conceptos, ya que en cada paso de su
aprendizaje se va comprobando que las cosas se hacen en la forma natural de
hacerlas, sin sorpresas ni comportamientos extraños de los programas. A medida
que se va aprendiendo, se va fomentando en el programador, y sin esfuerzo, un
buen estilo de programación orientada a objetos. En realidad, no puede ser de otra
forma, ya que Java impide “hacer cosas extrañas” y, además, no permite
“abandonar” la programación orientada a objetos, como ocurre con otros lenguajes
de programación. Esto es bastante conveniente, de lo contrario, un programador
que está aprendiendo puede sentir la tentación de “volver” a lo que conoce (la
programación tradicional).
8.2 Breve Historia de Java
El lenguaje Java™ fue creado por Sun Microsystems Inc. en un proceso por
etapas que arranca en 1990, año en el que Sun creó un grupo de trabajo, liderado
por James Gosling, para desarrollar un sistema para controlar electrodomésticos e
incluso PDAs o Asistentes Personales (pequeños ordenadores) que, además,
permitiera la conexión a redes de ordenadores. Se pretendía crear un hardware
polivalente, con un Sistema Operativo eficiente (SunOS) y un lenguaje de
desarrollo denominado Oak (roble), el precursor de Java. El proyecto finalizó en
1992 y resultó un completo fracaso debido al excesivo coste del producto, con
relación a alternativas similares, tras lo cual el grupo se disolvió.
Por entonces aparece Mosaic y la World Wide Web. Después de la disolución del
grupo de trabajo, únicamente quedaba del proyecto el lenguaje Oak. Gracias a
una acertada decisión de distribuir libremente el lenguaje por la Red de Redes y al
auge y la facilidad de acceso a Internet, propiciado por la WWW, el lenguaje se
popularizó y se consiguió que una gran cantidad de programadores lo depurasen y
terminasen de perfilar la forma y usos del mismo. A partir de este momento, el
lenguaje se difunde a una velocidad vertiginosa, añadiéndosele numerosas clases
y funcionalidad para TCP/IP. El nombre del lenguaje tuvo que ser cambiado ya
que existía otro llamado Oak. El nombre “Java” surgió en una de las sesiones de
“brainstorming” celebradas por el equipo de desarrollo del lenguaje. Buscaban un
nombre que evocara la esencia de la tecnología (viveza, animación, rapidez,
interactividad…). Java fue elegido de entre muchísimas propuestas. No es un
acrónimo, sino únicamente algo humeante, caliente y que a muchos
programadores les gusta beber en grandes cantidades: una taza de café (Java en
argot Inglés americano). De esta forma, Sun lanzó las primeras versiones de Java
a principios de 1995.
Desde entonces, Sun ha sabido manejar inteligentemente el éxito obtenido por su
lenguaje, concediéndose licencias a cualquiera sin ningún problema, fomentando

su uso entre la comunidad informática y extendiendo las especificaciones y
funcionalidad del lenguaje.
8.3 Características de Java
• Es intrínsecamente orientado a objetos.
• Funciona perfectamente en red.
• Aprovecha características de la mayoría de los lenguajes modernos evitando
sus inconvenientes. En particular los del C++.
• Tiene una gran funcionalidad gracias a sus librerías (clases).
• NO tiene punteros manejables por el programador, aunque los maneja interna
y transparentemente.
• El manejo de la memoria no es un problema, la gestiona el propio lenguaje y
no el programador.
• Genera aplicaciones con pocos errores posibles.
• Incorpora Multi-Threading (para permitir la ejecución de tareas concurrentes
dentro de un mismo programa).
El lenguaje Java puede considerarse como una evolución del C++. La sintaxis es
parecida a la de este lenguaje, por lo que se hace referencia a dicho lenguaje. A
pesar de que puede considerarse como una evolución del C++ no acarrea los
inconvenientes del mismo, ya que Java fue diseñado “partiendo de cero”, es decir,
un lenguaje “puro” y no necesitaba ser compatible con versiones anteriores de
ningún lenguaje como ocurre con C++ y C.
Gracias a que fue diseñado “partiendo de cero” ha conseguido convertirse en un
lenguaje orientado a objetos puro, limpio y práctico. No permite programar
mediante otra técnica que no sea la programación orientada a objetos y, una vez
superado el aprendizaje de la programación orientada a objetos, es realmente
sencillo aprender Java.
¿El lenguaje es Compilado o Interpretado? Ni una cosa ni la otra. Aunque
estrictamente hablando es interpretado, necesita de un proceso previo de
compilación. Una vez “compilado” el programa, se crea un archivo que almacena
lo que se denomina bytecodes o j_code (seudo código prácticamente al nivel de
código máquina). Para ejecutarlo, es necesario un “intérprete”, la JVM (Java
Virtual Machine) máquina virtual Java. De esta forma, es posible compilar el
programa en una estación UNIX y ejecutarlo en otra con Windows utilizando la
máquina virtual Java para Windows. Esta JVM se encarga de leer los bytecodes y
traducirlos a instrucciones ejecutables directamente en un determinado
microprocesador, de una forma bastante eficiente.
Que el programa deba ser “interpretado” no hace que sea poco eficiente en cuanto
a velocidad, ya que la interpretación se hace prácticamente al nivel de código
máquina. Por ejemplo, es mucho más rápido que cualquier otro programa
interpretado como por ejemplo Visual Basic, aunque es más lento que el mismo

programa escrito en C++. Esta deficiencia en cuanto a la velocidad, puede ser
aminorada por los compiladores Just-In-Time (JIT). Un compilador JIT transforma
los bytecodes de un programa o un applet en código nativo de la plataforma donde
se ejecuta, por lo que es más rápido. Suelen ser incorporados por los
navegadores, como Netscape o Internet Explorer.
El lenguaje Java es robusto. Las aplicaciones creadas en este lenguaje son
susceptibles de contener pocos errores, principalmente porque la gestión de
memoria y punteros es realizada por el propio lenguaje y no por el programador.
Bien es sabido que la mayoría de los errores en las aplicaciones vienen
producidos por fallos en la gestión de punteros o la asignación y liberación de
memoria. Además, el lenguaje contiene estructuras para la detección de
excepciones (errores de ejecución previstos) y permite obligar al programador a
escribir código fiable mediante la declaración de excepciones posibles para una
determinada clase reutilizable.
La Máquina Virtual Java (JVM)
La máquina virtual Java es la idea revolucionaria18 del lenguaje. Es la entidad que
proporciona la independencia de plataforma para los programas Java “compilados”
en byte-code.
18 Otros sistemas en el pasado, como por ejemplo el Pascal UCSD compilaban a un código intermedio (p-code) que luego
era interpretado al ejecutar el programa.

Un mismo programa fuente compilado en distintas plataformas o sistemas
operativos, genera el mismo archivo en byte-code. Esto es lógico, ya que se
supone que el compilador de Java traduce el archivo fuente a código ejecutable
por una máquina que únicamente existe en forma virtual (aunque se trabaja en la
construcción de microprocesadores que ejecuten directamente el byte-code).
Evidentemente, si un mismo programa en byte-code puede ser ejecutado en
distintas plataformas es porque existe un traductor de ese byte-code a código
nativo de la máquina sobre la que se ejecuta. Esta tarea es realizada por la JVM.
Existe una versión distinta de esta JVM para cada plataforma. Esta JVM se carga
en memoria y va traduciendo “al vuelo”, los byte-codes a código máquina. La JVM
no ocupa mucho espacio en memoria, piénsese que fue diseñada para poder
ejecutarse sobre pequeños electrodomésticos como teléfonos, televisores, etc.
8.4 Novedades en la versión 1.5
1. Introducción
En este documento se resumen las principales novedades que ofrece la versión
1.5 de Java, separándolas en diferentes áreas. Para una explicación más
detallada, consultar la página de Sun:
http://java.sun.com/j2se/1.5.0/docs/relnotes/features.html

2. Novedades en la máquina virtual
Autoajuste de memoria mejorado
La capacidad de autoajustar la cantidad de memoria necesaria (pila, recolector de
basura, etc.) se ve mejorada en esta versión.
Compartir clases
Al instalar la máquina virtual, se cargan en memoria un conjunto de clases del
sistema, en forma de representación interna, de forma que las siguientes llamadas
a la máquina virtual ya encuentren estas clases mapeadas en memoria, y se
permita que los datos de estas clases se compartan entre múltiples procesos
dentro de la JVM.
Ajuste del recolector de basura
Relacionado con el autoajuste de memoria, el recolector de basura también se
autoadapta a las necesidades de memoria de la aplicación, para evitar que el
usuario tenga que ajustar su tamaño y características desde línea de comandos.
Tratamiento de errores fatales
El mecanismo de listado de errores fatales se ha mejorado de forma que se
obtengan mejores diagnósticos a partir de las salidas generadas por dichos
errores.
3. Novedades en el lenguaje
Tipos de datos parametrizados (generics)
Esta mejora permite tener colecciones de tipos concretos de datos, lo que permite
asegurar que los datos que se van a almacenar van a ser compatibles con un
determinado tipo o tipos. Por ejemplo, podemos crear un Vector que sólo
almacene Strings, o una HashMap que tome como claves Integers y como valores
Vectors. Además, con esto nos ahorramos las conversiones cast al tipo que
deseemos, puesto que la colección ya se asume que será de dicho tipo.
Ejemplo
// Vector de cadenas
Vector<String> v = new Vector<String>();
v.addElement("Hola");
String s = v.getElementAt(0);
v.addElement(new Integer(20)); // Daría error!!
// HashMap con claves enteras y valores de vectores

HashMap<Integer, Vector> hm = new HashMap<Integer, Vector>();
hm.put(1, v);
Vector v2 = hm.get(1);
Autoboxing
Esta nueva característica evita al programador tener que establecer
correspondencias manuales entre los tipos simples (int, double, etc.) y sus
correspondientes wrappers o tipos complejos (Integer, Double, etc.). Podremos
utilizar un int donde se espere un objeto complejo (Integer), y viceversa.
Ejemplo
Vector<Integer> v = new Vector<Integer>();
v.addElement(30);
Integer n = v.getElementAt(0);
n = n+1;
Mejoras en Ciclos
Se mejoran las posibilidades de recorrer colecciones y arrays, previniendo índices
fuera de rango, y pudiendo recorrer colecciones sin necesidad de acceder a sus
iteradores (Iterator).
Ejemplo
// Recorre e imprime todos los elementos de un array
int[] arrayInt = {1, 20, 30, 2, 3, 5};
for(int elemento: arrayInt)
System.out.println (elemento);
// Recorre e imprime todos los elementos de un Vector
Vector<String> v = new Vector<String>();
for(String cadena: v)
System.out.println (cadena);
Tipo enum
El tipo enum que se introduce permite definir un conjunto de posibles valores o
estados, que luego podremos utilizar donde queramos:
Ejemplo
// Define una lista de 3 valores y luego comprueba en un switch// cuál es el valor que tiene un objeto de ese tipo
enum EstadoCivil {soltero, casado, divorciado};
EstadoCivil ec = EstadoCivil.casado;
ec = EstadoCivil.soltero;
switch(ec)
{

case soltero: System.out.println("Es soltero");
break;
case casado: System.out.println("Es casado");
break;
case divorciado:System.out.println("Es divorciado");
break;
}
Imports estáticos
Los imports estáticos permiten importar los elementos estáticos de una clase, de
forma que para referenciarlos no tengamos que poner siempre como prefijo el
nombre de la clase. Por ejemplo, podemos utilizar las constantes de color de la
clase java.awt.Color, o bien los métodos matemáticos de la case Math.
Ejemplo
import static java.awt.Color;
import static java.lang.Math;
public class...
{
...
JLabel lbl = new JLabel();
lbl.setBackground(white); // Antes sería
Color.white
...
double raiz = sqrt(1252.2); // Antes sería
Math.sqrt(...)
}
Argumentos variables
Ahora Java permite pasar un número variable de argumentos a una función (como
sucede con funciones como printf en C). Esto se consigue mediante la expresión
"..." a partir del momento en que queramos tener un número variable de
argumentos.
Ejemplo
// Funcion que tiene un parámetro String obligatorio
// y n parámetros int opcionales
public void miFunc(String param, int... args)
{
...
// Una forma de procesar n parametros variables
for (int argumento: args)
{
...
}
...

}
...
miFunc("Hola", 1, 20, 30, 2);
miFunc("Adios");
Metainformación
Se tiene la posibilidad de añadir ciertas anotaciones en campos, métodos, clases y
otros elementos, que permitan a las herramientas de desarrollo o de despliegue
leerlas y realizar ciertas tareas. Por ejemplo, generar archivos fuentes, archivos
XML, o un Stub de métodos para utilizar remotamente con RMI.
Un ejemplo más claro lo tenemos en las anotaciones que ya se utilizan para la
herramienta Javadoc. Las marcas @deprecated no afectan al comportamiento de
los métodos que las llevan, pero previenen al compilador para que muestre una
advertencia indicando que el método que se utiliza está desaconsejado. También
se tienen otras marcas @param, @return, @see, etc., que utiliza Javadoc para
generar las páginas de documentación y las relaciones entre ellas.
Ejemplo
// Definición de una interfaz mediante metainformacion
public @interface MiInterfaz
{
int metodo1();
String metodo2();
}
4. Novedades en librerías principales
Red
Se han añadido cambios y mejoras para el trabajo en red, como:
• Soporte para IPv6 en Windows XP y 2003
• Establecimiento de timeouts para conectar y leer
• API para lanzar aplicaciones RMI a través de inetd
• La clase InetAddress permite testear si una URL es alcanzable (utilidad
ping)
• Otras mejoras en el tratamiento de cookies, servidores proxy, tratamiento
de URLs, etc.

Seguridad
Hay bastantes mejoras en seguridad. Se da soporte a más estándares de
seguridad (SASL, OCSP, TSP, etc.), hay mejoras en la escalabilidad a través de
SSLEngine, en criptografía, etc.
Internacionalización
Mediante la internacionalización podemos construir una aplicación que se adapte
a varios idiomas, formatos monetarios, de fecha, etc., sin tener que reprogramarla.
En este aspecto, se añaden mejoras en la versión 1.5, relacionadas con:
• La gestión de juegos de caracteres se basa en el formato Unicode 4.0, lo
que afecta a las clases Character y String, entre otras.
• La clase DecimalFormat se ha modificado para poder procesar elementos
de tipo BigDecimal o BigInteger sin perder precisión
• Se han añadido nuevos Locales soportados, como el vietnamita.
Formateador
La clase Formatter permite dar formato (justificación y alineamiento, formatos
numéricos, de fecha, etc.) a las cadenas y otros tipos de datos, siguiendo un estilo
parecido al printf de C. También se permite mediante la interfaz Formattable dar
formatos (limitados) a tipos creados por el usuario.
Ejemplo
// Uso de formatter para construir cadenas formateadas
StringBuilder sb = new StringBuilder();
Formatter f = new Formatter(sb, Locale.US);
f.format("Hola, %1$2s, esta es tu visita numero %2$d", "Pepe",
20);
// Resultaría: "Hola, Pepe, esta es tu visita numero 20"
// También se tienen unos métodos predefinidos en ciertas clases
System.out.format("Hola, %1$2s, esta es tu visita numero %2$d",
"Pepe", 20);
System.err.printf("Hola, %1$2s, esta es tu visita numero %2$d",
"Pepe", 20);
String s = String.format("Hola, %1$2s", "Pepe");
Escaneador
La clase Scanner permite parsear un flujo de entrada (archivo, cadena de texto,
stream de datos, etc.), y extraer tokens siguiendo un determinado patrón o tipo de
datos. También se permite trabajar con expresiones regulares para indicar qué
patrones se deben buscar.

Ejemplo
// Lectura de enteros de la entrada estándar
Scanner sc = Scanner.create(System.in);
int n = sc.nextInt();
// Lectura de todos los doubles de un archivo
Scanner sc = Scanner.create(new File("miFich.txt"));
while (sc.hasNextDouble())
double d = sc.nextDouble();
// Uso de otros delimitadores
String s = "Esto hola es hola 1 hola ejemplo";
Scanner sc = Scanner.create(s).useDelimiter("\\s*hola\\s*");
System.out.println(sc.next());
System.out.println(sc.next());
System.out.println(sc.next());
// Sacaría Esto \n es \n 1
Arquitectura de JavaBeans
La arquitectura de JavaBeans se encuentra dentro del paquete java.beans. Se ha
añadido una nueva clase, IndexedPropertyChangeEvent, subclase de
PropertyChangeEvent, para dar soporte a eventos que respondan a cambios en
propiedades indexadas (propiedades que utilicen un índice para identificar la parte
del bean que haya cambiado). También se han añadido mejoras a la hora de crear
editores de propiedades de beans (PropertyEditor), como el método
createPropertyEditor(...), y constructores públicos para la clase
PropertyEditorSupport.
Arquitectura de colecciones
Como se ha comentado antes, las colecciones (estructura que contiene clases e
interfaces como Collection, Vector, ArrayList, etc.) dan soporte a nuevas
características del lenguaje, como el autoboxing, mejoras en los Ciclos (for) , y el
uso de generics. Además, se han añadido interfaces nuevos, como Queue,
BlockingQueue y ConcurrentMap, con algunas implementaciones concretas de
dichas interfaces. Además, se tienen nuevas implementaciones de List, Set y Map.
Manipulación de bits
Los wrappers de tipos simples (es decir, clases como Integer, Long, Double, Char)
soportan operaciones de bits, como highestOneBit, lowestOneBit, rotateLeft,
rotateRight, reverse, etc.
Elementos matemáticos
El paquete java.math también ha sufrido modificaciones, como la adición en la
clase BigDecimal de soporte para cálculo en coma flotante de precisión fija.

Clases como Math o StrictMath además incluyen soporte para senos y cosenos
hiperbólicos, raíces cúbicas o logaritmos en base 10. Por último, también se da
soporte al uso de números hexadecimales con coma flotante.
Serialización
Además de corregir errores previos en la serialización, se da soporte para
serializar el nuevo tipo enum, aunque la forma de serializarlo difiere ligeramente
de los tipos tradicionales.
Hilos
Se han añadido los paquetes java.util.concurrent, java.util.concurrent.atomic y
java.util.concurrent.locks, que permiten crear diversas infraestructuras de hilos,
como pooling de hilos o colas de bloqueos, liberando al programador de tener que
controlar todas estas estructuras "a mano". En definitiva, se da soporte para
automatizar la programación concurrente.
Además, a la clase Thread se le han añadido los métodos getStackTrace y
getAllStackTraces para obtener la traza de los hilos en un momento dado.
Monitorización y gestión
Se tienen mejoras en el control o la monitorización tanto de las aplicaciones Java
como de la máquina virtual (JVM), a través de la API de JMX.
5. Novedades en librerías adicionales
RMI
Se tienen dos mejoras fundamentales en RMI:
• Generación dinámica de Stubs: se generan en tiempo de ejecución, sin
necesidad de utilizar rmic previamente. Sólo tendremos que utilizarlo para
generar Stubs para clientes que funcionen con versiones anteriores de
Java.
• Lanzamiento de rmid o un servidor RMI Java desde inetd/xinetd.
JDBC
En Java 1.4 se introdujo la interfaz RowSet, que permitía pasar datos entre
componentes. En Java 1.5 se han desarrollado 5 implementaciones de dicha
interfaz, para cubrir 5 posibles casos de uso:
• JdbcRowSet: para encapsular un ResultSet o un driver que utilice
tecnología JDBC

• CachedRowSet: desconecta de la fuente de datos y trabaja
independientemente, salvo cuando esté obteniendo datos de dicha fuente o
volcando datos en ella.
• FilteredRowSet: hereda de la anterior, y se utiliza para obtener un
subconjunto de datos
• JoinRowSet: hereda de CachedRowSet y se emplea para unir múltiples
objetos RowSet.
• WebRowSet: hereda de CachedRowSet para procesar datos XML.
JNDI
• Mejoras en la clase javax.naming.NameClassPair para poder acceder al
nombre completo del servicio de directorio.
• Soporte para controles estándar de LDAP
• Soporte para manipular nombres de LDAP
6. Novedades en la interfaz de usuario
Internacionalización
Para permitir renderizar texto