Publicaciones de Estudiantes


Autor: Francisco Javier Pabón Molina
Titulo: Principios de Programación II
Area: Information Systems
Pais:
Perfil:
Programa:
Disponible para descarga: Yes
Ver Más Publicaciones Estudiantiles Clic aquí

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.

Para conocer más de la iniciativa de Acceso Abierto de AIU haga Clic aquí.

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:
https://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 multilingüe utilizando fuentes lógicas, se tienen en
cuenta tanto las fuentes del cliente como las del locale que tengamos instalado.
Además, AWT utiliza APIs Unicode en Windows 2000 y XP, con lo que se puede
manejar texto sin estar limitado a la configuración de locale de Windows.
Java Sound
Para el tratamiento del sonido desde Java, se tienen también los siguientes
cambios, principalmente:
• Se permite el acceso a puertos en todas las plataformas
• También está disponible la entrada/salida MIDI
Java 2D
• Se cachean en memoria todas las imágenes construidas a partir de
BufferedImage
• Métodos para controlar la aceleración hardware en imágenes
• Añadido soporte para aceleración hardware con OpenGL en Solaris y Linux.
• Creación de fuentes a partir de archivos y flujos de entrada
• Se ha mejorado la renderización de texto.
Flujos de imágenes
Se permite, además de los formatos de imágenes ya soportados (PNG, JPG, etc.),
leer y escribir imágenes BMP y WBMP.

AWT
Las novedades más significativas son:
• La clase MouseInfo almacena información sobre la posición del ratón en el
escritorio
• Se tienen nuevos métodos en la clase Window para especificar la posición
para las nuevas ventanas que se creen. También se tienen métodos para
asegurar que una ventana permanezca siempre en primer lugar (aunque
esta característica no funciona bien en algunas versiones de Solaris o
Linux)
• Nuevos métodos para acceder y notificar sobre el contenido del
portapapeles.
• Se han corregido errores existentes en los layout managers: GridBagLayout
y FlowLayout.
• Cambios y correcciones en eventos de teclado (nuevos mapeos de teclas,
redefinición de métodos, etc.), y de acción (correcciones en cuanto al uso
de Enter como evento de acción).
Swing
Entre otras, se tienen las novedades:
• Se proporcionan nuevos look & feels (uno de ellos, Synth, es skinnable, es
decir, se puede personalizar el skin que muestra)
• Se añade soporte para imprimir JTables.
• Se permite definir menús contextuales (popup menus) en componentes,
para que muestren las opciones que queramos. Para ello se tiene la clase
JPopupMenu.
• Se han añadido mejoras en JTextArea para facilitar el scroll por su
contenido, y la actualización cuando se modifique su texto.
• Podremos utilizar el método JFrame.add(...), en lugar de
JFrame.getContentPane().add(...)
// Antes
JFrame f = new JFrame();
f.getContentPane().add(new JButton("Hola"));
// Ahora
JFrame f = new JFrame();
f.add(new JButton("Hola"));

7. Novedades en despliegue de aplicaciones
Despliegue general
Se tienen, entre otras, las siguientes novedades en cuanto a despliegue de
aplicaciones:
• Se ha unido gran parte de la funcionalidad entre el Java Plug-in y Java Web
Start, de modo que ahora tienen un Java Control Panel común para ambos
• Las aplicaciones desplegadas se pueden configurar mediante un archivo de
configuración, que puede ser accedido a través de una URL, y establecer
ciertos parámetros de la aplicación.
• El formato de compresión Pack200 permite tener archivos JAR ultracomprimidos
(hasta 1/8 de su tamaño original), reduciendo los tiempos de
descarga, o de despliegue mediante Java Web Start.
• Inclusión de marcas de tiempo (timestamps) en los archivos JAR firmados,
de forma que se sabe cuándo se concedió el certificado para el archivo, y
se previene así el uso de JARs cuyo permiso ya caducó.
Java Web Start
Hay también cambios específicos de Java Web Start, como son:
• Supresión del Application Manager, cuya mayor funcionalidad se ha
encapsulado dentro del nuevo Java Control Panel, y el JNLP Cache Viewer,
una nueva herramienta que permite gestionar las aplicaciones
descargadas.
• Supersión del Developer Bundle, ya que Java Web Start está
completamente integrado con JRE y SDK, y los elementos que contenía
dicho bundle ahora están integrados en Java.
• Se tiene una caché de sistema, de forma que el administrador del sistema
puede cargar al inicio programas en la caché de sistema, de forma que
sean compartidas y accesibles por múltiples usuarios.
• Hay también una facilidad de importación, de forma que se facilita la
instalación desde CDs, donde el código se carga primero desde un lugar y
luego se actualiza desde otro. También permite preinstalar aplicaciones y
librerías en caché, sin ejecutarlas.
8. Novedades en herramientas
JPDA
JPDA es un conjunto de interfaces utilizadas para depurar en entornos y sistemas
de desarrollo. En la versión 1.5 se tienen nuevas mejoras y funcionalidades de
esta herramienta. Muchas de estas nuevas funcionalidades se han añadido para

adaptar las nuevas características de la versión 1.5 de Java, como los argumentos
variables, imports estáticos, etc.
JVMTI
JVMTI (Java Virtual Machine Tool Interface) es una nueva interfaz de
programación nativa para utilizar en herramientas de desarrollo y monitorización.
Forma parte de las interfaces contenidas en JPDA para depuración. Permite
chequear el estado y controlar la ejecución de una aplicación.
Compilador (javac)
Se han añadido algunas características a la hora de utilizar el compilador, como
son los parámetros:
• - source 1.5: habilita las nuevas características de la versión 1.5 de Java,
para ser tenidas en cuenta por el compilador. Lleva implícito también un
parámetro -target 1.5
• -target 1.5: permite al compilador utilizar características específicas de Java
1.5 en las librerías y la máquina virtual.
• -Xlint: permite producir warnings sobre código que, aunque es correcto,
puede ser problemático debido a su construcción.
Herramienta javadoc
Se tienen nuevas funcionalidades en la herramienta javadoc. Como en otros
elementos, muchos de los cambios dan soporte a características nuevas de Java
1.5 (generics, tipo enum, etc.). Se tienen también marcas nuevas, como
regression para indicar funcionalidades que se desaconsejaron en versiones
anteriores, pero que han sido corregidas en la nueva. También se da soporte a
anotaciones para generar metainformación que utilizar en otros programas.
8.5 El Entorno de Desarrollo de Java
La herramienta básica para empezar a desarrollar aplicaciones o applets en Java
es el JDK (Java Developer’s Kit) o Kit de Desarrollo Java, que consiste,
básicamente, en un compilador y un intérprete (JVM) para la línea de comandos.
No dispone de un entorno de desarrollo integrado (IDE), pero este puede ser
descargado de varias fuentes en Internet (Netbeans, Eclipse en mi caso, etc.)
suficiente para aprender el lenguaje y desarrollar pequeñas aplicaciones.
¿Dónde conseguirlo?
El Kit de desarrollo puede obtenerse en las direcciones siguientes:
· https://www.sun.com

· https://www.javasoft.com
El entorno para Windows9x/NT está formado por un archivo ejecutable que realiza
la instalación, creando toda la estructura de directorios. El kit contiene
básicamente:
· El compilador: javac.exe
· El depurador: jdb.exe
· El intérprete: java.exe y javaw.exe
· El visualizador de applets: appletviewer.exe
· El generador de documentación: javadoc.exe
· Un desensamblador de clases: javap.exe
· El generador de archivos fuentes y de cabecera (.c y .h) para clases
nativas en C: javah.exe
8.6 Herramientas para trabajar en Java
Existen distintas “ediciones” de Java para el desarrollo de aplicaciones en distintos
ámbitos:
• Aplicaciones de propósito general (J2SE)
• Aplicaciones de gestión en entornos empresariales (J2EE)
• Aplicaciones para teléfonos móviles, PDAs y otros dispositivos electrónicos que
permitan aplicaciones empotradas (J2ME)
La más utilizada es sin duda la edición estándar (J2SE).
J2SE incluye bibliotecas muy extensas y completas, que permiten la
implementación de casi cualquier tipo de aplicación:
• Seguridad
• EEDDs

• Componentes (JavaBeans)
• Internacionalización
• E/S
• XML
• Redes y acceso a Internet
• Programación distribuida (RMI, CORBA)
• Matemática de precisión arbitraria
• Sonido
• Interfaz de usuario (AWT, SWING)
• Gráficos 2D
• Manipulación, carga y descarga de imágenes
• Impresión
• Acceso a bases de datos (JDBC)
• Gestión de preferencias y configuraciones
Varias de estas características se verifican en la sección de novedades, apartado
8.4.
Entonces, en los entornos de desarrollo podemos encontrar:
NetBeans. Entorno integrado de desarrollo Java de Sun, realizado íntegramente
en Java (y por tanto multiplataforma). Consume bastantes recursos. Permite
diseñar ventanas, escribir código, compilar, ejecutar etc. Requiere un JDK
instalado. Puede obtenerse gratuitamente de www.netbeans.org
Borland JBuilder. Excelente entorno integrado de desarrollo Java de Borland. Al
igual que Netbeans, también está realizado íntegramente en Java. Existen
versiones limitadas que pueden bajarse de www.borland.com.

Microsoft Visual J++. Uno de los más populares, aunque las aplicaciones
obtenidas pueden presentar problemas de compatibilidad con el SDK oficial de
Java, por el uso de librerías especificas de Microsoft. Permite construir
aplicaciones Java dentro de la plataforma .NET.
Otros IDE son Eclipse, el cual se detallará en el apartado 15, IBM WebSphere,
Oracle JDeveloper, etc.
Java vrs otros lenguajes OO
9. Tipos de datos, variables y matrices
9.1 Tipos de datos
En Java existen dos tipos principales de datos:
1) Tipos de datos simples.
2) Referencias a objetos.
Los tipos de datos simples son aquellos que pueden utilizarse directamente en un
programa, sin necesidad del uso de clases (POO). Estos tipos son:

El segundo tipo está formado por todos los demás. Se les llama referencias
porque en realidad lo que se almacena en los mismos son punteros a zonas de
memoria donde se encuentran almacenadas las estructuras de datos que los
soportan. Dentro de este grupo se encuentran las clases (objetos) y también se
incluyen las interfaces, los vectores y los Strings.
Pueden realizarse conversiones entre los distintos tipos de datos (incluso entre
simples y referenciales), bien de forma implícita o de forma explícita.
9.2 Tipos de datos simples
Los tipos de datos simples soportados por Java son los siguientes:
No existen más datos simples en Java. Incluso éstos que se enumeran son
envueltos por clases equivalentes (java.lang.Integer, java.lang.Double,
java.lang.Byte, etc.), que pueden tratarlos como si fueran objetos en lugar de
datos simples.
A diferencia de otros lenguajes de programación como el C, en Java los tipos de
datos simples no dependen de la plataforma ni del sistema operativo. Un entero de
tipo int siempre tendrá 4 bytes, por lo que no tendremos sorpresas al migrar un
programa de un sistema operativo a otro. Es más, ni siquiera hay que volverlo a
compilar.
Eso sí, Java no realiza una comprobación de los rangos. Por ejemplo: si a una
variable de tipo short con el valor 32.767 se le suma 1, el resultado será

-32.768 y no se producirá ningún error de ejecución.
Nota: A diferencia de otros lenguajes de programación, los Strings en Java no son
un tipo simple de datos sino un objeto. Los valores de tipo String van entre
comillas dobles (“Hola”), mientras que los de tipo char van entre comillas simples
(‘K’).
Los valores que pueden asignarse a variables y que pueden ser utilizados en
expresiones directamente reciben el nombre de literales.
9.3 Tipos de datos referenciales
El resto de tipos de datos que no son simples, son considerados referenciales.
Estos tipos son básicamente las clases, en las que se basa la programación
orientada a objetos.
Al declarar un objeto perteneciente a una determinada clase, se está reservando
una zona de memoria19 donde se almacenarán los atributos y otros datos
pertenecientes a dicho objeto. Lo que se almacena en el objeto en sí, es un
puntero (referencia) a dicha zona de memoria.
Dentro de estos tipos pueden considerarse las interfaces, los Strings y los
vectores, que son unas clases un tanto especiales, y que se verán en detalle
posteriormente.
Existe un tipo referencial especial nominado por la palabra reservada null que
puede ser asignado a cualquier variable de cualquier clase y que indica que el
puntero no tiene referencia a ninguna zona de memoria (el objeto no está
inicializado).
Además, todos los tipos de datos simples vistos en el punto anterior pueden ser
declarados como referenciales (objetos), ya que existen clases que los engloban.
Estas clases son:
19 En realidad, el momento en el que se realiza la reserva física del espacio de memoria es cuando se instancia el objeto
realizando la llamada a su constructor, y no en el momento de la declaración.

Clases que Engloban datos simples
9.4 Identificadores y variables
Los identificadores son los nombres que se les da a las variables, clases,
interfaces, atributos y métodos de un programa.
Reglas para la creación de identificadores:
1. Java hace distinción entre mayúsculas y minúsculas, por lo tanto, nombres o
identificadores como var1, Var1 y VAR1 son distintos.
2. Pueden estar formados por cualquiera de los caracteres del código Unicode, por
lo tanto, se pueden declarar variables con el nombre: añoDeCreación, raïm, etc.
(se acabó la época de los nombres de variable como ano_de_creacion), aunque
eso sí, el primer carácter no puede ser un dígito numérico y no pueden utilizarse
espacios en blanco ni símbolos coincidentes con operadores.
3. La longitud máxima de los identificadores es prácticamente ilimitada.
4. No puede ser una palabra reservada del lenguaje ni los valores lógicos true o
false.
5. No pueden ser iguales a otro identificador declarado en el mismo ámbito.
6. Por convenio, los nombres de las variables y los métodos deberían empezar por
una letra minúscula y los de las clases por mayúscula.
Además, si el identificador está formado por varias palabras la primera se escribe
en minúsculas (excepto para las clases) y el resto de palabras se hace empezar

por mayúscula (por ejemplo: añoDeCreación). Estas reglas no son obligatorias,
pero son convenientes ya que ayudan al proceso de codificación de un programa,
así como a su legibilidad. Es más sencillo distinguir entre clases y métodos o
variables.
Ya que el lenguaje permite identificadores todo lo largos que se desee, es
aconsejable crearlos de forma que tengan sentido y faciliten su interpretación. El
nombre ideal para un identificador es aquel que no se excede en longitud (lo más
corto posible) siempre que califique claramente el concepto que intenta
representar. Siempre dentro de unos límites; por ejemplo, no sería muy adecuado
utilizar un identificador de un índice de un Ciclo como indiceDeTalCiclo en lugar
de simplemente i.
Hay que evitar identificadores como a1, a2, a3, a4, va1, xc32, xc21, xsda, … y en
general todos aquellos identificadores que no “signifiquen” nada.
Declaración de variables
La declaración de una variable se realiza de la misma forma que en C. Siempre
contiene el nombre (identificador de la variable) y el tipo de dato al que pertenece.
El ámbito de la variable depende de la localización en el programa donde es
declarada.
Ejemplo:
int x;
Las variables pueden ser inicializadas en el momento de su declaración, siempre
que el valor que se les asigne coincida con el tipo de dato de la variable.
Ejemplo:
int x = 0;

Ámbito de una variable
El ámbito de una variable es la porción de programa donde dicha variable es
visible para el código del programa y, por tanto, referenciable.
El ámbito de una variable depende del lugar del programa donde es declarada,
pudiendo pertenecer a cuatro categorías distintas.
· Variable local.
· Atributo.
· Parámetro de un método.
· Parámetro de un tratador de excepciones.
Como puede observarse, NO existen las variables globales. Esto no es un
“defecto” del lenguaje sino todo lo contrario. La utilización de variables globales
resulta peligrosa, ya que puede ser modificada en cualquier parte del programa y
por cualquier procedimiento.
Además, a la hora de utilizarlas hay que buscar dónde están declaradas para
conocerlas y dónde son modificadas para evitar sorpresas en los valores que
pueden contener.
Los ámbitos de las variables u objetos en Java siguen los criterios “clásicos”, al
igual que en la mayoría de los lenguajes de programación como Pascal, C++, etc.
No existen sorpresas.
Si una variable no ha sido inicializada, tiene un valor asignado por defecto. Este
valor es, para las variables de tipo referencial (objetos), el valor null. Para las
variables de tipo numérico, el valor por defecto es cero (0), las variables de tipo
char, el valor ‘\u0000’ y las variables de tipo boolean, el valor false.
Variables locales
Una variable local se declara dentro del cuerpo de un método de una clase y es
visible únicamente dentro de dicho método.
Se puede declarar en cualquier lugar del cuerpo, incluso después de instrucciones
ejecutables, aunque es una buena costumbre declararlas justo al principio.
También pueden declararse variables dentro de un bloque patentizado por llaves
{…}. En ese caso, sólo serán “visibles” dentro de dicho bloque.
class Caracter {
char ch;
public Caracter(char c) {
ch=c;
}
public void repetir(int num) {
int i;
for (i=0;i<num;i++)
System.out.println(ch);
}

}
class Ej1 {
public static void main(String argumentos[]) {
Caracter caracter;
caracter = new Caracter('H');
caracter.repetir(20);
}
}
En este ejemplo existe una variable local: int i; definida en el método repetirde la clase Caracter, por lo tanto, únicamente es visible dentro del método
repetir.
También existe una variable local en el método main. En este caso, la variable local
es un objeto:
Caracter caracter; .. que sólo será visible dentro del método en el que está
declarada (main).
Es importante hacer notar que una declaración como la anterior le indica al
compilador el tipo de la variable caracter pero no crea un objeto. El operador que
crea el objeto es new, que necesita como único parámetro el nombre del
constructor (que será el procedimiento que asigna valor a ese objeto recién
instanciado).
Cuando se pretende declarar múltiples variables del mismo tipo pueden
declararse, en forma de lista, separadas por comas:
Ejemplo:
int x,y,z;
· Declara tres variables x, y, z de tipo entero.
· Podrían haberse inicializado en su declaración de la forma:
int x=0,y=0,z=3;
No es necesario que se declaren al principio del método. Puede hacerse en
cualquier lugar del mismo, incluso de la siguiente forma:
public void repetir(int num) {
for (int i=0;i<num;i++)
System.out.println(ch);
}
En el caso de las variables locales, éstas no se inicializan con un valor por
defecto, como se ha comentado en el punto anterior, sino que es necesario
asignarles algún valor antes de poder utilizarlas en cualquier instrucción, de lo
contrario el compilador genera un error, de tal forma que es imposible hacer uso
de una variable local no inicializada sin que se percate de ello el compilador.
Las variables locales pueden ser antecedidas por la palabra reservada final. En
ese caso, sólo permiten que se les asigne un valor una única vez.

Ejemplo:
final int x=0;
No permitirá que a x se le asigne ningún otro valor. Siempre contendrá 0.
No es necesario que el valor se le asigne en el momento de la declaración, podría
haberse inicializado en cualquier otro lugar, pero una sola vez:
Ejemplo:
final int x;

x=y+2;
Después de la asignación x=y+2, no se permitirá asignar ningún otro valor a x.
Atributos
Los atributos de una clase son las características que se van a tener en cuenta
sobre un objeto y por lo tanto su ámbito está circunscrito, en principio, dentro de la
clase a la cual caracterizan. Se declaran de la misma forma que las variables
locales pero, además, pueden tener algunos modificadores que afectan al ámbito
de los mismos.
En el ejemplo anterior, ch es un atributo de la clase Caracter y por lo tanto es
“manipulable” en cualquier método de dicha clase, como de hecho ocurre en los
método repetir () y Carácter ().
Para acceder a un atributo de un objeto desde algún método perteneciente a otra
clase u objeto se antepone el nombre del objeto y un punto al nombre de dicho
atributo. Por ejemplo:
caracter.ch
Con los nombres de los métodos se hace lo mismo.
Ejemplo:
caracter.repetir(20);
Parámetros de un método
Los parámetros se declaran en la cabecera del método de la siguiente forma:
[Modificadores_de_método] Tipo_devuelto Nombre_de_método (lista_de_parámetros)
{

}
La lista_de_parámetros consiste en una serie de variables, separadas por comas y
declarando el tipo al que pertenecen.
Ejemplo:
public static void miMétodo(int v1, int v2, float v3, Stringv4, ClaseObjeto v5);

Nótese que aunque existan varios parámetros pertenecientes al mismo tipo o
clase, no pueden declararse abreviadamente, como ocurre con las variables
locales y los atributos, indicando el tipo y a continuación la lista de parámetros
separados por comas. Así, es ilegal la siguiente declaración del método anterior:
public static void miMétodo(int v1, v2, float v3, String v4,
ClaseObjeto v5); .. (ILEGAL)
La declaración de un parámetro puede ir antecedida, como ocurre con las
variables locales, por la palabra reservada final. En ese caso, el valor de dicho
parámetro no podrá ser modificado en el cuerpo del método.
Los parámetros de un método pueden ser de dos tipos:
• Variables de tipo simple de datos: En este caso, el paso de parámetros se
realiza siempre por valor. Es decir, el valor del parámetro de llamada no puede
ser modificado en el cuerpo del método (El método trabaja con una copia del
valor utilizado en la llamada).
• Variables de tipo objeto (referencias): En este caso, lo que realmente se
pasa al método es un puntero al objeto y, por lo tanto, el valor del parámetro de
llamada sí que puede ser modificado dentro del método (El método trabaja
directamente con el valor utilizado en la llamada), a no ser que se anteponga la
palabra reservada final.

La salida del programa sería la siguiente:
Valor del objeto = 1
Valor de la variable = 2
-Después de llamar a modifica ( )-
Valor del objeto = 2
Valor de la variable = 2
Como puede verse, después de la llamada, el valor del objeto obj sí ha sido
modificado (se ha realizado un pase de parámetro por referencia), mientras que el
valor de la variable var1 no ha sido modificado (se ha realizado un paso de
parámetro por valor).
9.5 Conversión de Tipos
La palabra conversión se utiliza con el sentido de "convertir a un molde". Java
convertirá automáticamente un tipo de datos en otro cuando sea adecuado. Por
ejemplo, si se asigna un valor entero a una variable de coma flotante, el
compilador convertirá automáticamente el int en float. La conversión permite llevar
a cabo estas conversiones de tipos de forma explícita, o forzarlas cuando no se
diesen por defecto.

Para llevar a cabo una conversión, se pone el tipo de datos deseado (incluidos
todos los modificadores) entre paréntesis a la izquierda de cualquier valor. He aquí
un ejemplo:
void conversiones ( ) {
int i = 200;
long 1 = (long) i;
long 12 = (lon9)2OO;
}
Como puede verse, es posible llevar a cabo una conversión, tanto con un valor
numérico, como con una variable. En las dos conversiones mostradas, la
conversión es innecesaria, dado que el compilador convertirá un valor int en long
cuando sea necesario. No obstante, se permite usar conversiones innecesarias
para hacer el código más limpio. En otras situaciones, puede ser esencial una
conversión para lograr que el código compile.
En C y C++, las conversiones pueden conllevar quebraderos de cabeza. En Java,
la conversión de tipos es segura, con la excepción de que al llevar a cabo una de
las denominadas conversiones reductoras(es decir, cuando se va de un tipo de
datos que puede mantener más información a otro que no puede contener tanta)
se corre el riesgo de perder información. En estos casos, el compilador fuerza a
hacer una conversión explícita, diciendo, de hecho, "esto puede ser algo peligroso
de hacer -si se quiere que lo haga de todas formas, tiene que hacer la conversión
de forma explícita". Con una conversión extensora no es necesaria una
conversión explícita porque el nuevo tipo es capaz de albergar la información del
viejo tipo sin que se pierda nunca ningún bit.
Java permite convertir cualquier tipo primitivo en cualquier otro tipo, excepto
boolean, que no permite ninguna conversión. Los tipos clase no permiten ninguna
conversión. Para convertir una a otra debe utilizar métodos especiales (String es
un caso especial y se verá más adelante en este libro que los objetos pueden
convertirse en una familia de tipos; un Roble puede convertirse en Árbol y
viceversa, pero esto no puede hacerse con un tipo foráneo como Roca.)
Toda expresión en Java tiene un tipo de dato asociado, ya sea simple o
referencial, y puede ser deducido de la estructura de la expresión y los literales
que pudiera contener.
Las conversiones de tipos pueden ser apropiadas para cambiar el tipo de una
determinada expresión que no se corresponda con el tipo necesario.
Tipos de conversiones de tipos:
Conversión por ampliación: Consiste en cambiar el tipo de dato por otro
cuyo rango es mayor y por lo tanto, contiene al primero. En este tipo de

conversión no se pierde información (aunque puede perderse precisión en
la conversión de datos enteros a reales).
Conversión por reducción: En este tipo de conversión sí que puede
perderse información debido a que se pretende almacenar más información
de la que “cabe” en el tipo de destino. Al ser una conversión
“semidestructiva”, es necesario indicar que se pretende realizar la misma
explícitamente para evitar pérdidas de información por conversiones por
reducción inadvertidas.
Conversión por ampliación de tipos de datos simples
En estos casos no se pierde información sobre la magnitud de los valores
numéricos.
Tipo a Tipo resultante
convertir
byte short
int
long
float
double
short int
long
float
double
char int
long
float
double
int long
float
double
long float
double
float double
Para los casos de asignación no es necesario realizar ninguna conversión explícita
de tipos. Por ejemplo, se puede asignar un valor de tipo byte a una variable de tipo
short, int, long, float o double.
También se puede asignar un carácter (char) a una variable de tipo int, long, float
o double.
int i = ’A’;

Los únicos casos en los que no se preserva necesariamente la exactitud entre los
valores del tipo a convertir y el tipo resultante, ya que puede perderse precisión
son:
Tipo a Tipo resultante
convertir
int float
long float
double
En estos casos de pérdida de precisión, se redondea al valor más cercano.
Ejemplo de pérdida de precisión:
Produce la siguiente salida:
f=1.23456794E9
-46
Esto es debido a que el tipo float sólo es preciso hasta 8 dígitos significativos.
Conversión por reducción de tipos de datos simples
En estos casos puede perderse información ya que los rangos de representación
son distintos, no estando el del tipo de dato a convertir incluido en el rango del tipo
de destino.
La forma de convertir de un tipo a otro es trasladando los n bits menos
significativos a la zona de memoria de destino con capacidad para esos n bits. De
esta forma puede perderse incluso el signo de valores numéricos (representados
en complemento a dos).

Tipo a
convertir
Tipo
resultante
Tipo a
convertir
Tipo
resultante
byte char
short byte
char
char byte
short
int byte
short
char
long byte
short
char
int
float byte
short
char
int
long
double byte
short
char
Int
Long
float
Reducción de datos simples
En estos casos, en que puede perderse información en el proceso de conversión
de tipos, es necesario indicarlo explícitamente para evitar que esta pérdida se
produzca de forma accidental, o por lo menos de forma inadvertida por el
programador.
La forma de realizar la conversión de tipo por reducción es mediante la
anteposición a la expresión a convertir, el tipo de destino encerrado entre
paréntesis.

Salida por pantalla:
f1=1.234567 i1=1
f2=7.654321 i2=7
i=1234567 s=-10617
Conversión por ampliación de tipos de datos referenciales
Al igual que ocurre con los tipos de datos simples, también para los objetos
pueden realizarse conversiones tanto por ampliación como por reducción.
Las conversiones por ampliación permitidas son:
Tipo a convertir Tipo resultante
La clase null - Cualquier clase, interfase o vector
Cualquier clase C - Cualquier clase R siempre que C sea
subclase de R
- Cualquier interfase I si C implementa I
- La clase Object
Cualquier interfase I - Cualquier interfase K siempre que I sea
subinterfaz de K
- La clase Object
Cualquier vector A - La clase Object
- La clase Cloneable
- Cualquier vector R siempre que el tipo de los
elementos de A y R sean datos referenciales y
exista una conversión por ampliación entre ellos.
En estos casos no es necesaria ninguna conversión explícita.
Produce la siguiente salda por pantalla:

Clase c2
En el ejemplo, se ha declarado un objeto c1 de la clase C1, que es subclase de
C2. A c1 se le asigna un objeto de la clase C2 (al realizar la llamada al constructor
de C2). Esto puede hacerse sin ninguna conversión explícita ya que C2 es
subclase de C1. Casi gráficamente puede entenderse mediante un ejemplo de la
siguiente forma: imaginemos una clase Ave y una subclase Pato; si se dispone de
una variable de la clase Ave, a dicha variable se le puede asignar un “Pato”, ya
que un pato es, efectivamente, un ave. Por lo tanto, a una variable de la clase Ave,
se le puede asignar un objeto “Pato” sin ninguna conversión explícita ya que es un
proceso “natural”. El caso contrario no siempre es cierto. Si se dispone de una
variable de la clase Pato, no se le puede asignar un objeto de la clase “Ave”, ya
que cualquier ave no es un pato.
Si se dispone de una variable de la clase Pato y se le desea asignar un objeto de
la clase Ave, habrá que realizar una conversión explícita (ver punto siguiente) para
“asegurar” que el ave que asignamos es “realmente” un pato.
Conversión por reducción de tipos de datos referenciales
Las conversiones por reducción permitidas son:
Tipo a convertir Tipo resultante
La clase Object - Cualquier vector
- Cualquier interfase
- Cualquier clase
Cualquier clase C - Cualquier clase R siempre que C sea
superclase de R
- Cualquier interfase I si C no es final y
no implementa I
Cualquier interfase I - Cualquier clase C que no sea final
- Cualquier clase C que sea final
siempre que C implemente I
- Cualquier interfase K siempre que I no
sea subinterface de K y no tengan
métodos con el mismo nombre pero
distinto tipo de dato de retorno.
Cualquier vector A - Cualquier vector R siempre que el tipo
de los elementos de A y R sean datos
referenciales y exista una conversión
por reducción entre ellos.
En estos casos es necesario indicarlo explícitamente.

La forma de realizar la conversión de tipo por reducción es mediante la
anteposición a la expresión a convertir, el tipo de destino encerrado entre
paréntesis.
El siguiente ejemplo muestra una conversión no permitida y genera un mensaje de
error por el compilador:
class C1 {
public String clase;
public C1() {
clase = "clase c1";
}
}
class C2 extends C1{
public C2() {
clase = "clase c2";
}
}
class Conversion4 {
public static void main(String arg[]) {
C1 c1 = new C1();
C2 c2 = c1;
System.out.println(c2.clase);
}
}
Conversion4.java:16: Incompatible type for declaration. Explicit
cast needed to convert C1 to C2.
C2 c2 = c1;
^
1 error
La conversión de un objeto de la clase C1 a la clase C2 necesita del programador
la indicación de que se sabe que se está asignando un valor de la clase C1 a una
variable de la clase C2, pero que en realidad c1 no contiene un objeto de la clase
C1 sino un objeto de la clase C2.
Para realizar la conversión en el ejemplo anterior se antepone la clase a convertir
encerrada entre paréntesis de la siguiente manera:
class Conversion4 {
public static void main(String arg[]) {
C1 c1 = new C1();
// Conversión por reducción de tipo de
// dato referencial
C2 c2 = (C2) c1;
System.out.println(c2.clase);
}
}

Con esta conversión explícita se indica que el objeto almacenado en c1 es, en
realidad, de la clase C2 (lo cuál no es cierto). Ahora el compilador no genera
ningún error, pero al ejecutar el programa se genera una excepción:
java.lang.ClassCastException:
at Conversion5.main(Conversion5.java:17)
No se habría generado ninguna excepción si en c1 hubiera un objeto de la clase
C2 de la siguiente forma:
class Conversion4 {
public static void main(String arg[]) {
C1 c1 = new C2(); // Conversión por ampliación
// Conversión por reducción de tipo de dato
// referencial
C2 c2 = (C2) c1;
System.out.println(c2.clase);
}
}
La salida por pantalla sería:
Clase c2
Conversiones de tipos no permitidas
Tipo a convertir Tipo resultante
Tipo referencial Tipo simple
Tipo simple Tipo referencial (Excepto al tipo String)
Null Tipo simple
Cualquier tipo Tipo boolean
Tipo boolean Cualquier otro tipo (Excepto al tipo
String)
Cualquier clase C - Cualquier clase R siempre que C no
sea
subclase de R y R no sea subclase de
C
(Excepto a la clase String)
- Cualquier interfase I si C es “final” y no
implementa I
- Cualquier vector (Excepto si C es de
la clase Object)
Cualquier interfase I - Cualquier clase C (Excepto si C es
String) si es “final” y no implementa I
- Cualquier interfase K si I y K declaran
métodos con la misma cabecera y
distinto tipo de dato de retorno.
Cualquier vector - Cualquier interfase excepto al
interfase

Cloneable.
-Cualquier otro vector si no hay
conversión entre los tipos de los
elementos (excepto la conversión a
String).
9.6 Vectores o Matrices
Para manejar colecciones de objetos del mismo tipo estructurados en una sola
variable se utilizan los vectores20. En Java, los vectores son en realidad objetos y
por lo tanto se puede llamar a sus métodos (como se verá en el capítulo
siguiente).
Existen dos formas equivalentes de declarar vectores en Java:
1) tipo nombreDelVector [ ];
2) tipo [ ] nombreDelVector;
Ejemplo:
int vector1[], vector2[], entero; //entero no es un vector
int[] otroVector;
También pueden utilizarse vectores de más de una dimensión:
Ejemplo:
int matriz [] [];
int [] [] otraMatriz;
Los vectores, al igual que las demás variables pueden ser inicializados en el
momento de su declaración. En este caso, no es necesario especificar el número
de elementos máximo reservado. Se reserva el espacio justo para almacenar los
elementos añadidos en la declaración.
Ejemplo:
String Días []= {”Lunes”,”Martes”,”Miércoles”,”Jueves”,
”Viernes”,”Sábado”,”Domingo”};
Una simple declaración de un vector no reserva espacio en memoria, a excepción
del caso anterior, en el que sus elementos obtienen la memoria necesaria para ser
almacenados. Para reservar la memoria hay que llamar explícitamente a un
constructor new21 de la siguiente forma:
new tipoElemento[ numElementos] ;
20 También llamados arrays, matrices o tablas.
21 Véase la sección 12.4

Ejemplo:
int matriz[][];
matriz = new int[4][7];
También se puede indicar el número de elementos durante su declaración:
Ejemplo:
int vector[] = new int[5];
Para hacer referencia a los elementos particulares del vector, se utiliza el
identificador del vector junto con el índice del elemento entre corchetes. El índice
del primer elemento es el cero (0) y el del último, el número de elementos menos
uno.
Ejemplo:
j = vector[0]; vector[4] = matriz[2][3];
El intento de acceder a un elemento fuera del rango de la matriz, a diferencia de lo
que ocurre en C, provoca una excepción (error) que, de no ser manejado por el
programa, será el compilador quien aborte la operación.
Para obtener el número de elementos de un vector en tiempo de ejecución se
accede al atributo de la clase vector length. No olvidemos que los vectores en
Java son tratados como un objeto.
class Array1 {
public static void main (String argumentos[]) {
String colores[] = {"Rojo","Verde","Azul",
"Amarillo","Negro"};
int i;
for (i=0;i<colores.length;i++)
System.out.println(colores[i]);
}
}
El ejemplo anterior produce la siguiente salida por pantalla:
Rojo
Verde
Azul
Amarillo
Negro
Arrays multidimensionales
Java permite crear fácilmente arrays multidimensionales:
/ / : c04:ArrayMultidimensional.java/ / creando arrays multidimensionales.
import java.util.*;
public class ArrayMultidimensional {
static Random aleatorio = new Random();

static int pAleatorio (int modulo) {
return Math. abs (aleatorio. nextInt ( ) ) % modulo + 1;
}
static void visualizar (String S) {
System.out.println (S);
}
public static void main (String[] args) {
int[l [ ] al = {
{ 1, 2, 3}
{ 4, 5 , 6}
};
for(int i = O; i < al.length; i++)
for (int j = O; j < al [i] . length; j++)
visualizar ("al [ " + i + "1 [ " + j +
“j = “ + al[i] [j]);
/ / array 3-D de longitud fija:
int [] [] [] a2 = new int [2] [2] [4];
for (int i = O; i < a2.length; i+t)
for (int j = O; j < a2 [i] . length; jt+)
for(int k = O; k < a2[i] [j] .length;
k++)
visualizar ("a2 [ " + i + "1 [ " + j + "][" + k +
“J = “+ a2 [i][j][k]);
/ / array 3-D con vectores de longitud variable:
int [] [ ] [] a3 = new int [pAleatorio (7) ] [] [] ;
for (int i = O; i < a3.length; i++) {
a3 [i] = new int [pAleatorio (5) ] [] ;
for(int j = O; j < a3[i] .length; j++)
a3[il [jl = new int[pAleatorio(5)1;
}
for (int i = O; i < a3.length; i++)
for (int j = O; j < a3 [i] .length; j++)
for(int k = O; k < a3[i] [j] .length;
k++)
visualizar ("a3 [ " + i + "1 [ " + j + "][" + k +
“J = “ + a3 [il [jl [kl ) ;
/ / Array de objetos no primitivos:
Integer [] [] a4 = {
{ new Integer (1) , new Integer (2) } ,
{ new Integer (3) , new Integer ( 4 ) },
{ new Integer (S), new Integer (6) } ,
};
for(int i = O; i < a4.length; i++)
for (int j = O; j < a4 [i] . length; j++)
visualizar("a4[" + i + "1 [ " + j +
" J = " + a4 [i] [j]);
Integer [] [ ] a5;
a5 = new Integer [3] [] ;
for(int i = O; i < a5.length; i++) {
a5[i] = new Integer[3];

for (int j = O; j < a5 [i] .length; j++)
a5 [i] [ j ] = new Integer (i* j) ;
}
for(int i = O; i < a5.length; i++)
for(int j = O; j < a5[i] .length; j++)
visualizar ("a5 [ " + i + "1 [ " + j +
“ J = “J + a5[i] [j]);
}
} / / / : -
El código utilizado para imprimir utiliza el método length, de forma que no
depende de tamaños fijos de array.
El primer ejemplo muestra un array multidimensional de tipos primitivos. Se puede
delimitar cada vector del array por llaves:
Cada conjunto de corchetes nos introduce en el siguiente nivel del array.
El segundo ejemplo muestra un array de tres dimensiones asignado con new.
Aquí, se asigna de una sola vez todo el array:
int [] [] [] a2 = new int [2] [2] [4] ;
Pero el tercer ejemplo muestra que cada vector en los arrays que conforman la
matriz puede ser de cualquier longitud:
El primer new crea un array con un primer elemento de longitud aleatoria, y el
resto, indeterminados. El segundo new de dentro del Ciclo for rellena los
elementos pero deja el tercer índice indeterminado hasta que se acometa el tercer
new.
Se verá en la salida que los valores del array que se inicializan automáticamente a
cero si no se les da un valor de inicialización explícito.

Se puede tratar con arrays de objetos no primitivos de forma similar, lo que se
muestra en el cuarto ejemplo, que demuestra la habilidad de englobar muchas
expresiones new entre llaves:
El quinto ejemplo muestra cómo se puede construir pieza a pieza un array de
objetos no primitivos:
El i*j es simplemente para poner algún valor interesante en el Integer.
10 Operadores
Los operadores son partes indispensables en la construcción de expresiones.
Existen muchas definiciones técnicas para el término expresión. Puede decirse
que una expresión es una combinación de operandos ligados mediante
operadores.
Los operandos pueden ser variables, constantes, funciones, literales, etc. y los
operadores todos los enumerados en este punto.
10.1 Operadores aritméticos:
Operador Formato Descripción
+ op1 + op2 Suma aritmética de dos
operandos
-op1 - op2
-op1
Resta aritmética de dos
operandos
Cambio de signo
* op1 * op2 Multiplicación de dos
operandos
/ op1 / op2 División entera de dos
operandos
% op1 % op2 Resto de la división

)
++
--op1
op1 --
entera ( o módulo++op1
op1++
Incremento unitario
Decremento unitario
El operador - puede utilizarse en su versión unaria (- op1) y la operación que
realiza es la de invertir el signo del operando.
Como en C, los operadores unarios ++ y -- realizan un incremento y un
decremento respectivamente. Estos operadores admiten notación prefija y postfija.
• ++op1: En primer lugar realiza un incremento (en una unidad) de op1 y
después ejecuta la instrucción en la cual está inmerso.
• op1++: En primer lugar ejecuta la instrucción en la cual está inmerso y
después realiza un incremento (en una unidad) de op1.
• --op1: En primer lugar realiza un decremento (en una unidad) de op1 y
después ejecuta la instrucción en la cuál está inmerso.
• op1--: En primer lugar ejecuta la instrucción en la cual está inmerso y
después realiza un decremento (en una unidad) de op1.
La diferencia entre la notación prefija y la postfija no tiene importancia en
expresiones en las que únicamente existe dicha operación:
++contador; es equivalente a: contador++;
--contador; contador--;
Es importante no emplear estos operadores en expresiones que contengan más
de una referencia a la variable incrementada, puesto que esta práctica puede
generar resultados erróneos fácilmente.
La diferencia es apreciable en instrucciones en las cuáles están incluidas otras
operaciones.
Por ejemplo:
cont = 1; cont = 1;
do { do {
…} …}
while ( cont++ < 3 ); while ( ++cont < 3 );
En el primer caso, el Ciclo se ejecutará 3 veces, mientras que en el segundo se
ejecutará 2 veces.
Otro ejemplo:
a = 1; a = 1;
b = 2 + a++; b = 2 + ++a;

• En el primer caso, después de las operaciones, b tendrá el valor 3 y a el valor
2.
• En el segundo caso, después de las operaciones, b tendrá el valor 4 y a el
valor 2.
10.2 Operadores relacionales
Operador Formato Descripción
> op1 > op2 Devuelve true (cierto) si op1
es mayor que op2
< op1 < op2 Devuelve true (cierto) si op1
es menor que op2
>= op1 >= op2 Devuelve true (cierto) si op1
es mayor o igual que op2
<= op1<= op2 Devuelve true (cierto) si op1
es menor o igual que op2
== op1 == op2 Devuelve true (cierto) si op1
es igual a op2
!= op1 != op2 Devuelve true (cierto) si op1
es distinto de
op2
Los operadores relacionales actúan sobre valores enteros, reales y caracteres
(char); y devuelven un valor del tipo boolean (true o false).
Class Relacional {
public static void main(String arg[]) {
double op1,op2;
op1=1.34;
op2=1.35;
System.out.println("op1="+op1+" op2="+op2);
System.out.println("op1>op2 = "+(op1>op2));
System.out.println("op1<op2 = "+(op1<op2));
System.out.println("op1==op2 = "+(op1==op2));
System.out.println("op1!=op2 = "+(op1!=op2));
char op3,op4;
op3='a'; op4='b';
System.out.println("'a'>'b' = "+(op3>op4));
}
}
Salida por pantalla:
op1=1.34 op2=1.35
op1>op2 = false
op1<op2 = true
op1==op2 = false
op1!=op2 = true
'a'>'b' = false
Los operadores == y != actúan también sobre valores lógicos (boolean).

10.3 Operadores lógicos
Operador Formato Descripción
&& op1 && op2 Y lógico. Devuelve true
(cierto) si son ciertos op1 y
op2
½½ op1 ½½ op2 O lógico. Devuelve true
(cierto) si son ciertos op1 o
op2
! ! op1 Negación lógica. Devuelve
true (cierto) si es false op1.
Estos operadores actúan sobre operadores o expresiones lógicas, es decir,
aquellos que se evalúan a cierto o falso (true / false).
class Bool {
public static void main ( String argumentos[] ) {
boolean a=true;
boolean b=true;
boolean c=false;
boolean d=false;
System.out.println("true Y true = " + (a && b) );
System.out.println("true Y false = " + (a && c) );
System.out.println("false Y false = " + (c && d) );
System.out.println("true O true = " + (a || b) );
System.out.println("true O false = " + (a || c) );
System.out.println("false O false = " + (c || d) );
System.out.println("NO true = " + !a);
System.out.println("NO false = " + !c);
System.out.println("(3 > 4) Y true = " + ((3 >4) && a) );
}
}
Produciría la siguiente salida por pantalla:
true Y true = true
true Y false = false
false Y false = false
true O true = true
true O false = true
false O false = false
NO true = false
NO false = true
(3 > 4) Y true = false
10.4 Operadores de asignación
El operador de asignación es el símbolo igual (=).
op1 = Expresión
Asigna el resultado de evaluar la expresión de la derecha a op1.

.
 

Resto del documento disponible para descarga...

AIU Búsqueda Rápida

Contáctenos para empezar

Entendemos que los adultos que trabajan no tienen tiempo de regresar a la escuela. Ahora es posible obtener un título desde la comodidad de su hogar y todavía tener tiempo para usted y su familia. La oficina de admisiones está para ayudarlo, para obtener información adicional o para saber si es candidato para incorporarse a nuestros programas, por favor contáctenos. Si ya está listo para inscribirse, por favor mande su solicitud en línea y adjunte su currículum vitae y cualquier duda o comentario que tenga.

Pioneer Plaza
900 Fort Street Mall 905
Honolulu, HI 96813
800-993-0066 (Gratis en EUA)
808-924-9567 (Internacional)
8082150431 (Whatsapp)