| Creación de un Televisor estándar |
| Paso 11: Operativa |
Los paquetes
La forma general de la sentencia package multinivel es la siguiente
package paq1[.paq2[.paq3]];
|
- como se puede ver, se puede crear una jerarquía de paquetes separando los niveles por puntos
- estos niveles están reflejados en el sistema de archivos como una jerarquía de directorios
- la sentencia package, tiene que ser la primera sentencia de un archivo fuente Java
- una Clase podría tener un paquete por defecto. Si este fuera el caso, entonces no tendríamos escrita la sentencia package en el código de la Clase
- los paquetes por defecto suelen utilizarse en ejemplos de tutoriales Java cuando todavía no se ha introducido el concepto de paquete
Para utilizar un paquete o librería Java se incluye la sentencia import. La forma general de la sentencia import es la siguiente
import paq1[.paq2[.paq3]].(nombreClase | *);
|
- import
- la sentencia import, tiene que ir inmediatamente después de la sentencia package, si existe, y antes de la definición de la Clase
- nombreClase
| *
- tanto podemos importar una Clase concreta de un paquete, como todas las Clases de un paquete
Los paquetes son un mecanismo que
- evitan conflictos de nombres de Clases
- la signatura completa de una Clase, es la unión del nombre del paquete con el nombre de la Clase
- de esta forma, tenemos total libertad para asignarle un nombre a una Clase sin tener que pensar que esta Clase pudiera tener el mismo nombre que otra Clase creada por desarrolladores de otra empresa
- Nota: Convención sobre los nombres de los paquetes Apéndice - Nombre de los paquetes
- restringen la visibilidad
- interactúa directamente con los controles de acceso o ámbito. (Lo iremos viendo en los pasos sucesivos)
En todos los pasos anteriores hemos simulado estar en una Empresa de televisores creando
- por un lado un televisor estándar que lo hemos llamado Televisor y que lo utilizamos como plantilla para la creación de otros televisores
- por otro lado un modelo de televisor homologado por la normativa tipo ISO y que por tanto es totalmente funcional y que lo hemos llamado TelevisorVirtual
- y finalmente un usuario o televidente que interactúa con el TelevisorVirtual llamado Aplicacion
Podemos asegurar que las Clases Televisor, TelevisorVirtual y Aplicacion siempre han pertenecido a la Empresa de televisores porque, todas ellas están incluidas en el paquete paqtvestandar. Esta es su representación en UML
El hecho de que una Clase pertenezca a un paquete u otro tiene una importancia vital sobre el control de acceso o ámbito.
Control de acceso friendly
Además de los controles de acceso o ámbito public y private, existe otro llamado friendly
- sólo se tiene acceso a un miembro friendly cuando pertenecemos a un mismo paquete
- en ocasiones nos puede interesar tener métodos encapsulados como los de ámbito private, pero a la vez también queremos tener una flexibilidad de uso dentro del mismo paquete
- de esta forma si distribuimos nuestras Clases a otros
departamentos
de nuestra organización o a otras empresas, éstas no tendrán conocimiento y mucho menos acceso a los métodos con ámbito friendly
Un error muy típico en la primera puesta en marcha de una aplicación Java en una empresa, es que los ámbitos public y friendly se han solapado. Es decir, los desarrolladores muy probablemente han estado trabajando bajo el paraguas de un mismo paquete y nunca han tenido problemas de visibilidad a los métodos friendly
- pero cuando estas Clases han tenido que interactuar con otras Clases de otros paquetes, el entorno de ejecución Java se queja (y con razón) porque no puede ver tal o cual método
Para ilustrar el mencionado error , podemos ver los siguientes Diagramas de Clases de diseño que muestra como una Clase Aplicacion perteneciente al paquete paqusuario interactúa con las Clases del paquete paqtvestandar


- Aplicacion
(from paqusuario)
- en este caso tenemos una Clase Aplicacion que pertenece al paquete paqusuario y que interactúa con nuestras Clases
- pueden haber tantos paquetes que esten interactuando con nuestras Clases como subsistemas de otras empresas que interactúan con nuestras Clases
- ~setSonido(sonido:boolean): void
- en UML se denota que un método es friendly poniéndole una tilde "~" delante del nombre del método
Y para ver el mencionado error en código Java, vamos a seguir los siguientes pasos
Modificamos la Clase TelevisorVirtual
package paqtvestandar;
public class TelevisorVirtual extends Televisor {
private boolean sonido = true;
void setSonido(boolean valorSonido){ // Quitamos el modificador public
sonido = valorSonido;
}
public boolean isSonido(){
return sonido;
}
public void subirVolumen() {
super.subirVolumen();
if (this.isSonido() == false){
setSonido(true);
}
}
public void bajarVolumen() {
super.bajarVolumen();
if (isSonido() == false){
setSonido(true);
}
}
public void usarMenu(){
System.out.println("TelevisorVirtual - usarMenu(): utilizo el menu");
}
} |
- void setSonido(boolean valorSonido){
// Quitamos el modificador public
- hemos cambiado en este método el ámbito public a friendly
- en Java se sabe que un método es friendly por la ausencia de modificadores
Compilamos la Clase TelevisorVirtual.
Ejecutamos la Clase Aplicacion del paquete paqtvestandar y como cabe esperear que la ejecución es correcta.
Ahora nos creamos un paquete llamado paqusuario. Este paquete simula ser la vivienda donde se aloja la Clase Aplicacion, es decir el usuario que quiere ver el televisor TelevisorVirtual que nos ha comprado a nuestra empresa llamada paqtvestandar
package paqusuario;
import paqtvestandar.TelevisorVirtual;
public class Aplicacion {
public static void main(String[] args) {
TelevisorVirtual tv = new TelevisorVirtual();
tv.setCanal(3);
System.out.println("El canal seleccionado es el: " + tv.getCanal());
tv.subirColor();
tv.setSonido(false);
System.out.println("El telvisor tiene el sonido: " + tv.isSonido());
tv.subirVolumen();
System.out.println("La posición del volumen es: " + tv.getVolumen());
System.out.println("El televisor tiene el sonido: " + tv.isSonido());
tv.usarMenu();
}
} |
- package paqusuario;
- esta nueva Clase pertenece al paquete paqusuario
- import paqtvestandar.TelevisorVirtual;
- para poder acceder al TelevisorVirtual que pertenece al paquete paqtvestandar, tenemos que indicárselo al entorno de ejecución Java a través de la sentencia import
Ejecutamos la nueva Clase Aplicacion y comprobamos que el compilador se queja indicándonos que el método setSonido() no es público
- setSonido(boolean) is not public in paqtvestandar.TelevisorVirtual;
cannot be accessed from outside package

Y finalmente
- le devolvemos el modificador public al método setSonido() de la Clase TelevisorVirtual
- compilamos la Clase TelevisorVirtual
- ejecutamos la Clase Aplicacion perteneciente al paquete paqusuario para ver que ahora sí, todo funciona correctamente