¡Acceso ilimitado 24/7 a todos nuestros libros y vídeos! Descubra la Biblioteca Online ENI. Pulse aquí
¡Acceso ilimitado 24/7 a todos nuestros libros y vídeos! Descubra la Biblioteca Online ENI. Pulse aquí
  1. Libros
  2. Aprender la Programación Orientada a Objetos con el lenguaje Java
  3. Creación de clases
Extrait - Aprender la Programación Orientada a Objetos con el lenguaje Java (con ejercicios prácticos y corregidos)
Extractos del libro
Aprender la Programación Orientada a Objetos con el lenguaje Java (con ejercicios prácticos y corregidos) Volver a la página de compra del libro

Creación de clases

Introducción

Recordemos que una clase es un modelo que el sistema utiliza para instanciar el objeto correspondiente en memoria. Son estos modelos los que el desarrollador declara en lo que comúnmente se llama archivos fuentes (archivos con extensión .java) de su proyecto. Esto es lo que acabamos de hacer en el ejercicio LabTypesJava con la clase Main.

Paquetes

Las clases Java se agrupan por finalidades en conjuntos llamados paquetes, que a su vez se organizan de forma jerárquica. Cuando escribe el código fuente y desea utilizar una clase de un paquete dado, debe indicar su «ruta completa» en cada llamada o, de manera más concisa, declarar su importación en el encabezado del archivo fuente. Las clases «estándares» del paquete java.lang, no siguen esta regla; son directamente accesibles.

Las clases que va a desarrollar deberán pertenecer obligatoriamente a paquetes que, por lo tanto, tendrá que crear. La organización de estos conjuntos de clases y de sus jerarquías le permite controlar el «ámbito» de los paquetes, las clases y los métodos.

Hay convenciones de nomenclatura para los paquetes (como también existen para las clases, los métodos, etc.). Estas pueden variar de una empresa a otra. Generalmente, el paquete empieza por el nombre de un tipo de dominio (com, edu, gov, mil, net, org), seguido por un punto (.), seguido por el nombre de la empresa, seguido por un punto (.). A continuación, puede tener un nombre de proyecto o de un módulo utilizable en varios proyectos, etc.

Ejemplo de nombre de paquete

com.eni.facturacion.exportConta

Elija nombres de paquetes que resuman la función de la familia de clases que agrupan.

Generalmente, el análisis UML llevado a cabo anteriormente le ayudará a la hora de seleccionar los nombres. Este nombre debe...

Declaración de una clase

Una vez que el paquete se ha declarado, la clase se puede definir después de eventuales líneas de importación.

No es posible declarar más de una clase en el mismo archivo fuente, salvo si se «anidan» o si las clases son «privadas» del archivo fuente que las contiene.

Si intenta declarar dos clases de tipo public en un mismo archivo fuente, IntelliJ IDEA reacciona como sigue:

images/10RI05V2.png

Una clase se declara con la palabra clave class, seguida por el nombre que ha elegido. Como para el paquete, este nombre debe empezar por una letra o por un guión bajo (_). A continuación puede contener letras, cifras y guiones bajos. Evite utilizar caracteres acentuados y opte por el formato CamelCase. Según las convenciones de nomenclatura más extendidas, es una buena práctica empezar el nombre de la clase por una letra mayúscula. Por ejemplo, si escribe una clase que emula un reproductor digital, el nombre en formato «CamelCase» será ReproductorDigital. Las primeras letras de las palabras relacionadas están en mayúsculas.

La declaración de una herencia eventual interviene a continuación. Se explicará en detalle más adelante. En efecto, si la clase «extiende» una clase existente, entonces la palabra clave extends precede al nombre de la superclase.

Si la clase «implementa» una o varias interfaces, entonces la palabra clave implements precede a la lista de las interfaces soportadas por la clase.

Los miembros de la clase (los atributos y los métodos) se definen a continuación entre paréntesis.

Sintaxis de declaración

visibilidad class NombreClase  [[extends ClaseMadre]  
[implements Lista interfaces de base]]  
{  
   // cuerpo de la clase  
} 

Ejemplo

package com.miempresa;  
  
public class ClaseQueHereda extends SuClaseMadre implements  
Interface1, Interface2 {  
   // Cuerpo de la clase  
} 

El atributo de visibilidad de una clase definida en un paquete puede ser de tipo:

  • public: la clase será utilizable por todos.

  • <ninguna definición>: la clase será accesible por las clases del paquete en el que se encuentra.

El resto de los atributos (private, protected) solo tienen sentido para...

Las interfaces

1. Introducción

Explicar las interfaces y su interés siempre es mejor con un ejemplo concreto en el que basarse. Imaginemos por lo tanto un programa que permita controlar un sistema domótico desde un teléfono móvil (con nuestros smartphones siempre conectados, la locura para este tipo de aplicación es rebosante). Este programa gráfico permitirá manejar persianas eléctricas, leer temperaturas, encender el horno, etc. En resumen, leer y escribir los estados lógicos (verdadero o falso) y leer y escribir los valores analógicos (de 00 a ff, por ejemplo).

En este tipo de aplicaciones, es necesario no atarse a un hardware concreto. Un cambio de la tarjeta de entradas/salidas -es decir, la tarjeta que va a leer los sensores y controlar los relés bajo demanda- debe impactar lo menos posible en el código existente.

Y aquí es donde las interfaces de programación nos van a ayudar.

2. El contrato

Para tener éxito en nuestra independencia con respecto al hardware, hay que limitar sus relaciones a su más sencilla expresión y «contractualizarlos».

Por analogía podemos decir que es debido a la «estandarización del Conector Jack 3.5mm estéreo» que cualquier auricular se pueda conectar a cualquier reproductor digital. Esta famosa toma juega el rol de interfaz entre dos piezas de hardware, que no son obligatoriamente del mismo constructor.

Limitar los enlaces a su más sencilla expresión implica listar las funcionalidades mínimas esperadas para la tarjeta de entrada/salida. Esta lista es una especie de contrato que deberá respetar obligatoriamente el hardware. Para retomar la analogía anterior, los fabricantes de auriculares ofrecen productos con conectores de diámetros normalizados. Gracias a esta «interfaz», es posible la interconexión.

Por lo tanto, para este proyecto domótico, ¿cuáles son nuestras necesidades?

Es necesario poder:

  • leer los estados binarios sobre las entradas referenciadas: interruptores, pulsadores, sensores de presencias,

  • leer los valores analógicos sobre las entradas referenciadas: sensores de temperatura, de luz o de sonido,

  • controlar las salidas binarias referenciadas: persianas, horno, motor de la puerta, bomba, etc.,

  • controlar las salidas analógicas referenciadas: reguladores...

Asociaciones, composiciones y agregaciones

En todo programa, el desarrollador se anima a diseñar clases que utilicen o contengan otras clases, que a su vez pueden utilizar o contener otras clases, etc. Por ejemplo, un formulario (cuadro de diálogo con el usuario) muestra diferentes controles como botones de radio, casillas de selección, campos de introducción de texto u otras listas desplegables. El formulario y cada uno de sus controles se «encapsulan» en las clases que el desarrollador va a asociar para alcanzar la visualización final.

Las asociaciones son más o menos fuertes. En nuestro ejemplo, la asociación es fuerte porque es el formulario que instancia estos controles y estos mismos controles se destruirán durante su cierre. Se habla entonces de agregación «compuesta» o más sencillamente de «composición».

Durante esta asociación el objeto Contenedor accede libremente a los miembros de tipo public de cada uno de los objetos Contenido. De esta manera, durante su carga, nuestro formulario podrá inicializar los contenidos por defecto de las cajas de texto, las selecciones de los botones de radio y, durante la validación, recuperar las opciones del usuario, preguntando a cada uno de los controles.

¿Cómo permite el lenguaje Java administrar estas diferentes formas de colaboración?

Sea cual sea el grado de asociación, la clase Contenedor necesitará almacenar las referencias sobre las clases «contenidas».

Puede haber varios objetos de los mismos tipos referenciados en la clase Contenedor. Esta pluralidad también se expresa en UML, a través de un índice al final del enlace, indicando bien una cantidad finita o una franja posible.

images/22.png

En este ejemplo, un autor puede escribir uno o un número indefinido de libros (1..*) y un libro solo se asigna a un único autor (1).

Por lo tanto, el lenguaje Java va a tener varias formas de codificación para estos diferentes tipos de asociación.

  • La clase Contenedor contiene una sencilla referencia a un objeto de tipo Contenido.

class Contenedor{  
   Contenido contenido  = null;  
} 

Traducción UML de esta asociación:

images/23.png
  • La clase Contenedor contiene una lista de tamaño fijo de referencias a los tipos Contenido. En este caso, es preferible un objeto...

Las clases anidadas

Es posible declarar una clase dentro de otra clase. Esta funcionalidad ofrece al desarrollador otra manera más de organizar su código. Las clases principales se guardan en los paquetes y, por lo tanto, es posible realizar agrupaciones dentro de ellas.

La mayor parte de las veces, la clase anidada -llamada nested class o inner class- no significa nada fuera de su clase host y su operador de visibilidad es de tipo private. A pesar de todo, es posible modificar este tipo de acceso como public, protected o package private.

Sintaxis de una nested class

public class ClassHost {  
     
   class ClaseAnidada {  
  
   }  
   //.  
} 

La clase anidada tiene acceso a todos los miembros de la clase host. La clase host tiene acceso al resto de los miembros de la clase anidada.

El hecho de declarar una clase dentro de otra no implica una instanciación automática de la clase anidada durante la instanciación de la clase host. Esto sigue siendo una declaración.

La clase anidada puede ser de tipo static y, en este caso, se llama comúnmente static nested class.

Si la clase anidada no es de tipo static, se llama inner class.

Ejemplo de codificación de una clase anidada y de su clase host

Package demonestedclass;  
  
// ClassHost contiene dos propiedades,  
// la definición de "ClaseAnidada"  
// y un método de prueba  
  
public class ClassHost {...

Algunas diferencias con C#

Los lenguajes Java y C# son muy parecidos. Los dos son lenguajes de referencias (literal y figuradamente) y pasar de uno a otro no presentará grandes problemas.

Si es desarrollador C#, las diferencias respecto a este capítulo son que Java no soporta:

  • Las estructuras: herencia de C, las estructuras son muy parecidas a las clases en C#. La principal diferencia afecta a la memoria en la que se almacenan. Las clases se escriben en el heap y las estructuras están en la pila (stack); por lo tanto, son de muy rápido acceso porque se declaran por el compilador. No necesitan ninguna asignación del sistema operativo.

  • Las clases parciales (definidas en varios archivos fuentes): es un bien, digamos, determinado.

  • Los métodos parciales que tienen firmas definidas en un archivo fuente e implementaciones (opcionales) definidas en otro: misma observación.

  • La sobrecarga de operadores y principalmente los [], que representan indexadores, incluso el ==, que permite probar la igualdad entre dos objetos. Es verdad que, aunque la sobrecarga de operadores sea opcional, el usuario de las clases C# debe comprobar si realmente son operativos, mientras que en Java la cuestión no se plantea y se debe utilizar los métodos de prueba y de acceso correspondientes.