1.1 ¿Qué es JAVA?

Java es solo es otro lenguaje de programación con el que se pueden escribir programas que corran en Internet. Java es más parecido a lenguajes de programación como C, C++, Visual Basic o Pascal que a lenguajes de descripción como HTML o lenguajes para escribir guiones como JavaScript.

Java es un lenguaje de programación orientado a objetos desarrollado por Sun Microsystems. Fundamentado en C++, el lenguaje Java se diseño para ser pequeño, sencillo y portátil a través de las plataformas y sistemas operativos.

Java se menciona frecuentemente en el contexto del WWW, donde los Navegadores, reclaman ser “autorizados por Java” esto significa que el navegador puede en cuestión bajar y ejecutar programas en Java. Java se escribió como un lenguaje de programación de propósito general con el que se pueden abordar los mismos tipos de tarea o resolver el mismo tipo de problemas que con otros lenguajes de programación como C o C++.

1.2 La Simplicidad de Java

Java ha sido diseñado de modo de eliminar las complejidades de otros lenguajes como C y C++.

Si bien Java posee una sintaxis similar a C, con el objeto de facilitar la migración de C hacia a Java, Java es semánticamente muy distinto a C: · Java no posee aritmética de punteros: La aritmética de punteros es el origen de muchos errores de programación que no se manifiestan durante la depuración y que una vez que el usuario los detecta son difíciles de resolver.

  • No se necesita hacer delete: Determinar el momento en que se debe liberar el espacio ocupado por un objeto es un problema difícil de resolver correctamente. Esto también es el origen a errores difíciles de detectar y solucionar.
  • No hay herencia múltiple: En C++ esta característica da origen a muchas situaciones de borde en donde es difícil predecir cuál será el resultado. Por esta razón en Java se opta por herencia simple que es

 

1.3 Java posee bibliotecas de clases estándares

Toda implementación de Java debe tener las siguientes bibliotecas de clases:

  • Manejo de archivos
  • Comunicación de datos
  • Acceso a la red Internet
  • Acceso a bases de datos
  • Interfaces gráficas

La interfaz de programación de estas clases es estándar, es decir en todas ellas las operaciones se invocan con el mismo nombre y los mismos argumentos.

1.4 Java es multiplataforma

La independencia de plataforma es una de las ventas significativas que tiene Java sobre otros lenguajes de programación. Esto significa que un programa puede ejecutarse en cualquier sistema operativo. Los programas pueden ejecutarse en cualquier sistema que tenga instalado una maquina virtual.

Si esta escribiendo software para el WWW, la posibilidad de correr el mismo programa en sistemas diferentes es crucial para el éxito del programa.

Los programas en Java pueden ejecutarse en cualquiera de las siguientes plataformas, sin necesidad de hacer cambios:

  • Windows/95 y /NT
  • Power/Mac
  • Unix (Solaris, Silicon Graphics, …)

La compatibilidad es total:

  • A nivel de fuentes: El lenguaje es exactamente el mismo en todas las plataformas.
  • A nivel de bibliotecas: En todas las plataformas están presentes las mismas bibliotecas estándares.
  • A nivel del código compilado: el código intermedio que genera el compilador es el mismo para todas las plataformas. Lo que cambia es el intérprete del código intermedio.

1.5 El Look-and-Feel

Lo único que varia de acuerdo a la plataforma es el look-and-feel. Un programa en Windows/95 tendrá el aspecto característico de esta plataforma (en cuanto a la forma de los botones, barras de desplazamiento, menús, etc.). El mismo programa en Unix tendrá el aspecto característico de Motif. Y en Power/Mac se verá como un programa para Macintosh.

Sin embargo el código que escriben los programadores no tiene que tener presente las características de ninguna de estas plataformas. Es la implementación de la interfaz gráfica estándar de Java la que se encarga de desplegar las ventanas con el look-and-feel de la plataforma local.

1.6 C es poco robusto

Se dice que el lenguaje C es un lenguaje poco robusto porque a menudo un error de programación se traduce en un mensaje críptico del estilo segmentation fault. Este tipo de mensajes se origina en 4 errores clásicos:

  • Se accesa un elemento de un arreglo con un índice fuera de rango. Ejemplo: a[-3]=5;
  • Se usa un puntero como si referencia a una estructura de tipo A, cuando en realidad en esa área de memoria hay una estructura de tipo B, incompatible con A. En C esto ocurre debido al uso de casts. Ejemplo: *(int*)pdistance
  • Se usa un puntero a una estructura cuyo espacio ya se liberó. Luego volveremos a hablar de este punto. Ejemplo: free(p); *p= 1;
  • Al usar aritmética de punteros se comete un error. Ejemplo: *(p+i*sizeof(*p))

Todos estos errores conducen a que tarde o temprano se use un puntero que direcciona un área de memoria no asignada por el sistema operativo. Esto es lo que detiene la ejecución con el mensaje segmentation fault. Lo más desagradable de este tipo de errores es que es muy difícil determinar en qué línea del código está la verdadera fuente del error. Podría ser en cualquier parte del programa. Encontrar la línea puede llevar varios días y hasta semanas, incluso en el caso de programadores expertos.

1.7 Java sí es robusto

En Java no se pueden cometer los 4 errores mencionados:

  • Java siempre chequea los índices al accesar un arreglo.
  • Java realiza chequeo de tipos durante la compilación (al igual que C).En una asignación entre punteros el compilador verifica que los tipos sean compatibles. Además, Java realiza chequeo de tipos durante la ejecución (cosa que C y C++ no hacen). Cuando un programa usa un cast para accesar un objeto como si fuese de un tipo específico, se verifica durante la ejecución que el objeto en cuestión sea compatible con el cast que se le aplica. Si el objeto no es compatible, entonces se levanta una excepción que informa al programador la línea exacta en donde está la fuente del error.
  • Java posee un recolector de basuras que administra automáticamente la memoria. Es el recolector el que determina cuando se puede liberar el espacio ocupado por un objeto. El programador no puede liberar explícitamente el espacio ocupado por un objeto.
  • Java no posee aritmética de punteros, porque es una propiedad que no se necesita para programar aplicaciones. En C sólo se necesita la aritmética de punteros para programa malloc/free o para programar el núcleo del sistema operativo.

Por lo tanto Java no es un lenguaje para hacer sistemas operativos o administradores de memoria, pero sí es un excelente lenguaje para programar aplicaciones.

1.8 Java es flexible

Pascal también es un lenguaje robusto, pero logra su robustez prohibiendo tener punteros a objetos de tipo desconocido.

Lamentablemente esta prohibición es demasiado rígida. Aunque son pocos los casos en que se necesita tener punteros a objetos de tipo desconocido, las contorsiones que están obligados a realizar los programadores cuando necesitan estos punteros dan origen a programas ilegibles.

Lisp por su parte es un lenguaje flexible y robusto. Todas las variables son punteros a objetos de cualquier tipo (un arreglo, un elemento de lista, etc.). El tipo del objeto se encuentra almacenado en el mismo objeto. Durante la ejecución, en cada operación se chequea que el tipo del objeto manipulado sea del tipo apropiado. Esto da flexibilidad a los programadores sin sacrificar la robustez. Lamentablemente, esto hace que los programas en Lisp sean poco legibles debido a que al estudiar su código es difícil determinar cuál es el tipo del objeto que referencia una variable.

Java combina flexibilidad, robustez y legibilidad gracias a una mezcla de chequeo de tipos durante la compilación y durante la ejecución. En Java se pueden tener punteros a objetos de un tipo específico y también se pueden tener punteros a objetos de cualquier tipo. Estos punteros se pueden convertir a punteros de un tipo específico aplicando un cast, en cuyo caso se chequea en tiempo de ejecución de que el objeto sea de un tipo compatible.

El programador usa entonces punteros de tipo específico en la mayoría de los casos con el fin de ganar legibilidad y en unos pocos casos usa punteros a tipos desconocidos cuando necesita tener flexibilidad. Por lo tanto Java combina la robustez de Pascal con la flexibilidad de Lisp, sin que lo programas pierdan legibilidad en ningún caso.

1.9 Java administra automáticamente la memoria

En Java los programadores no necesitan preocuparse de liberar un trozo de memoria cuando ya no lo necesitan. Es el recolector de basuras el que determina cuando se puede liberar la memoria ocupada por un objeto.

Un recolector de basuras es un gran aporte a la productividad. Se ha estudiado en casos concretos que los programadores han dedicado un 40% del tiempo de desarrollo a determinar en qué momento se puede liberar un trozo de memoria. Además este porcentaje de tiempo aumenta a medida que aumenta la complejidad del software en desarrollo. Es relativamente sencillo liberar correctamente la memoria en un programa de 1000 líneas. Sin embargo, es difícil hacerlo en un programa de 10000 líneas. Y se puede postular que es imposible liberar correctamente la memoria en un programa de 100000 líneas.

Para entender mejor esta afirmación, supongamos que hicimos un programa de 1000 líneas hace un par de meses y ahora necesitamos hacer algunas modificaciones. Ahora hemos olvidado gran parte de los detalles de la lógica de este programa y ya no es sencillo determinar si un puntero referencia un objeto que todavía existe, o si ya fue liberado.

Peor aún, suponga que el programa fue hecho por otra persona y evalúe cuan probable es cometer errores de memoria al tratar de modificar ese programa.

Ahora volvamos al caso de un programa de 100000 líneas. Este tipo de programas los desarrolla un grupo de programadores que pueden tomar años en terminarlo. Cada programador desarrolla un módulo que eventualmente utiliza objetos de otros módulos desarrollados por otros programadores. ¿Quién libera la memoria de estos objetos? ¿Cómo se ponen de acuerdo los programadores sobre cuándo y quién libera un objeto compartido? ¿Como probar el programa completo ante las infinitas condiciones de borde que pueden existir en un programa de 100000 líneas?

Es inevitable que la fase de prueba dejará pasar errores en el manejo de memoria que sólo serán detectados más tarde por el usuario final.

Probablemente se incorporan otros errores en la fase de mantención.

Se puede concluir:

  • Todo programa de 100000 líneas que libera explícitamente la memoria tiene errores latentes.
  • Sin un recolector de basuras no hay verdadera modularidad.
  • Un recolector de basuras resuelve todos los problemas de manejo de memoria en forma trivial.

La pregunta es: ¿Cuál es el impacto de un recolector de basura en el desempeño de un programa? El sobrecosto de la recolección de basuras no es superior al 100%. Es decir si se tiene un programa que libera explícitamente la memoria y
que toma tiempo X, el mismo programa modificado de modo que utilice un recolector de basuras para liberar la memoria tomará un tiempo no superior a 2X.

Este sobrecosto no es importante si se considera el periódico incremento en la velocidad de los procesadores. El impacto que un recolector de basura en el tiempo de desarrollo y en la confiabilidad del software resultante es muchos más importante que la pérdida en eficiencia.

1.10 Programación Orientada a Objetos

La programación orientada a objetos (POO) se distingue por pensar en los problemas y sus soluciones a través de la implementación de objetos y sus comportamientos. Las características fundamentales de la Programación Orientada a objetos son: abstracción, encapsulamiento, herencia y polimorfismo.

-Abstracción.

Por medio de la abstracción se consigue no detenerse en los detalles concretos de implementación en cada momento, sino generalizar y centrarse en los aspectos que permiten tener una visión del problema.

-Encapsulamiento.

Permite ver un objeto como una caja negra en la que se ha introducido de alguna manera tosa la información relacionada con dicho objeto. Esto permite manipular los objetos como unidades básicas, permaneciendo ocultar su estructura interna.

-Herencia.

Permite el acceso automático a la información contenida en otras clases. De esta forma, la reutilización de código está garantizada. Con la herencia todas las clases están clasificadas en una jerarquía estricta.

-Polimorfismo.

Esta característica permite implementar a una variedad de métodos (todos con el mismo nombre), utilizando el mismo medio de acceso.

-Constructores y destructores.

Un constructor es un procedimiento especial de una clase que es llamada automáticamente siempre que crea un objeto de esa clase. Su función es iniciar esa clase.

Un destructor es un procedimiento especial de una clase que es llamado automáticamente siempre que se destruye una de esta clase. Su función es realizar cualquier tarea final en el momento de destruir cualquier objeto.

1.11 Mecanismos básicos de la POO

Los mecanismos (términos) )básicos son: objetos, mensajes, métodos y clases.

-Objetos

Un programa orientado a objetos se compone únicamente de objetos, es decir, un objeto es una entidad que tiene atributos particulares (propiedades), y una forma de operar sobre de ellos es como los métodos (el comportamiento).
Por ejemplo. Una ventana de Windows es un objeto. El color de fondo, la anchura, la altura, etc. son propiedades. Las rutinas que permiten maximizar, minimizar, etc. son los métodos.

-Métodos

Un método se implementa en una clase de objetos y determina como tiene que actuar el objeto cuando recibe el mensaje vinculado con ese método.

La estructura mas interna del objeto se oculta a los usuarios que lo vayan a utilizar, manteniendo como única conexión con el exterior, los mensajes.

-Clase

Una clase es una platilla genérica para un conjunto de objetos con características similares.

 

Fuente:

Diplomado Webmaster Avanzado
Instituto de Computación Activa de México S.C.