Вы находитесь на странице: 1из 28

Java

Clases e Interfaces Anidadas


H. Tejeda V
htejeda@fismat.umich.mx

Universidad Michoacana
Facultad de Ciencias Fı́sico-Matemáticas

Java– p. 1
Introducción
• Se pueden declarar clases e interfaces dentro de otras clases e
interfaces, como miembros o en bloques de código.
• Se definen tipos anidados por lo siguiente:
◦ Las clases e interfaces permiten estructurar los tipos y su alcance en
grupos relacionados lógicamente.
◦ Las clases anidadas se pueden usar para conectar objetos
relacionados lógicamente de forma simple y efectiva, como en
frameworks de eventos (AWT y en la arquitectura de componentes
JavaBeans).
• Un tipo anidado se considera parte del tipo que lo contiene, y comparten
una relación de confianza, donde cada uno puede acceder a los
miembros del otro.
• Las diferencias entre los tipos anidados dependen de que sea una clase
o interfaz.
• Los tipos anidados pueden declararse estáticos o no. Con el primero se
permite una estructuración simple de los tipos, y el segundo define una
relación especial entre un objeto anidado y un objeto de la clase que lo
contiene.
Java– p. 2
Tipos Anidados Estáticos
• Cuando una clase o interfaz anidada se declara como un miembro
static de la clase o interfaz que lo contiene, actúa como cualquier
clase o interfaz no anidada, o de nivel superior, excepto que el nombre y
accesibilidad se definen por el tipo que la incluye.
• El nombre de un tipo anidado se expresa como
NombreDelQueIncluye.NombreDelAnidado siendo accesible cuando el
tipo que lo incluye es accesible.
• Sirven como mecanismo de estructuración de gestión del alcance para
tipos relacionados lógicamente.
• Los tipos anidados estáticos son miembros del tipo que los contiene, por
lo cual pueden acceder a todos los miembros del tipo que los contiene.
• Como los tipos anidados estáticos son miembros del tipo que los
contiene, son aplicables para ellos las mismas reglas de accesibilidad
que las de los otros miembros.

Java– p. 3
Clases Anidadas Estáticas
• Es la forma más simple de clase anidada y se declara precediendo al
nombre de la clase con el modificador static.
• Si una declaración de clase se anida en una interfaz, la clase es siempre
estática.
• Una clase anidada se comporta como cualquier clase de nivel superior,
pudiendo ser extendida por otra clase y/o implementar cualquier interfaz.
• Se puede declarar final o abstract la clase anidada estática.

public class CuentaBancaria {


private long numero;
private long balance;

public static class Permisos {


public boolean puedeDepositar, // Campos no estáticos
puedeRetirar,
puedeCerrar;
}
public Permisos permisosDe ( String nomb ) { .... }
// ...
}
Java– p. 4
Comentarios
• La clase Permisos se define en la clase CuentaBancaria siendo un
miembro de la clase.
• El método permisosDe devuelve un objeto Permisos el cual puede ser
llamado sin calificador.
• El nombre completo de la clase es CuentaBancaria.Permisos.
• El código exterior a la clase CuentaBancaria debe usar el nombre
completo. Por ejemplo:

CuentaBancaria.Permisos perm = cuenta.permisosDe(propietario);


• La clase anidada se ve como parte de la implementación de la clase que
la incluye, y por tanto, es de total confianza.
• Las clases anidadas estáticas se pueden declarar accesibles de la forma
que se desee.
• No hay restricciones para extender una clase anidada, pudiendo ser
extendida por cualquier clase para la que sea accesible. La clase
extendida no heredará el acceso privilegiado que la clase anidada tiene
en la clase que lo incluyen.

Java– p. 5
Interfaces Anidadas
• Las interfaces anidadas son siempre estáticas.
• Sirven como un mecanismo de estructuración de tipos relacionados.

Java– p. 6
Clases Internas
• Las clases anidadas no estáticas se denominan clases internas.
• Una clase interna se asocia con una instancia de la clase, es decir, un
objeto de una clase interna se asocia siempre con un objeto de la clase
que la incluye.
• Se muestra en el siguiente código un método para la clase
CuentaBancaria que permite ver la última acción realizada en la
cuenta.
• La clase Accion almacena una sola acción sobre la cuenta.
• La relación entre un objeto Acción y su objeto CuentaBancaria se
establece cuando se crea el objeto Accion en los métodos deposito y
reintegro, asociándose con un objeto de la clase que la incluye.
• Por lo general, los objetos de las clases internas se crean dentro de
métodos de instancia de la clase, donde el objeto en curso this se
asocia por defecto con el objeto interno.

Java– p. 7
Ejemplo

public class CuentaBancaria {


private long numero;
private long balance;
private Accion ultimaAcc;

public class Accion {


private String operacion;
private long cantidad;
Accion(String operacion, long cantidad) {
this.operacion = operacion;
this.cantidad = cantidad;
}
public String toString()
{ return numero + ": " + operacion + " " + cantidad; }
}

public void deposito(long cantidad) {


balance += cantidad;
ultimaAcc = new Accion("deposito", cantidad);
}
⇓ Java– p. 8
Ejemplo cont.

public void retiro(long cantidad) {


balance -= cantidad;
ultimaAcc = new Accion("retiro", cantidad);
}
// ...
}

Java– p. 9
Acceso a los Objetos que Incluyen
• Una clase anidada puede acceder a todos los miembros de la clase que
la contiene (incluyendo los campos y métodos privados), sin necesidad
de calificación, por ser parte de la implementación de la clase que la
incluye, basta con nombrar los miembros, por los que los nombres de la
clase están dentro del alcance, por ejemplo cuando se usa el campo
numero del objeto CuentaBancaria en el método toString() de la
clase anidada.
• La clase que incluye puede acceder a los miembros privados de la clase
interna, usando una referencia explícita a un objeto de dicha clase
interna, como UltimaAcc.

Java– p. 10
TAREA

1. Poner un método accesor en la clase CuentaBancaria para poner el


número de cuenta. Crear una referencia del tipo CuentaBancaria para
realizar un depósito por 100 y un retiro por 25 para la cuenta 54321.

Java– p. 11
Extensión de Clases Internas
• Una clase interna se puede extender como cualquier otra clase anidada
estática o clase de nivel superior, siempre y cuando los objetos de la
clase extendida se asocien con objetos de la clase original que incluye, o
con una subclase.

class Externa {
class Interna { }
}

class ExternaExtendida extends Externa {


class InternaExtendida extends Interna { }
Interna ref = new InternaExtendida();
}

Java– p. 12
Extensión de Clases Internas
• El campo ref se inicializa al crear un objeto ExternaExtendida.
• La creación de la instancia de ExternaExtendida usa el constructor
por defecto sin argumentos de InternaExtendida, que a su vez
invoca implícitamente al constructor sin argumentos por defecto de
Interna usando super.
• El constructor de Interna requiere ligarse a un objeto de Externa, que
en este caso es implícitamente el objeto actual de ExternaExtendida.

Java– p. 13
Herencia, Alcance y Ocultación
• Dentro de una clase interna, todos los nombres declarados en la clase
que la incluyen están dentro del alcance.
• Los campos y métodos propios de la clase interna pueden ocultar a los
del objeto que la incluye, sucediendo de las siguientes 2 formas:
◦ Un campo o método se declara en la clase interna.
◦ Un campo o método es heredado por la clase interna.
• Para el primer caso, cualquier uso del nombre simple se refiere a la
declaración dentro de la clase interna.
• Para acceder al campo o método del objeto que la incluye, debe usarse
la nomenclatura con this.
• En el segundo caso el nombre debe ser calificado explícitamente usando
this o super, para referirse al nombre en la clase interna, o
NombreExterno.this para referirse a un miembro de la clase que la
incluya.

Java– p. 14
Ejemplo

class Host {
int x;
class Ayudante extends Desconocida {
void incrementar() { x++; }
}
}
class Desconocida { int x; }

• Parece que el método incrementar incrementa el campo x de la


instancia de Host que incluye a Ayudante.
• En Desconocida se declara un campo x, el cual es heredado por
Ayudante.
• El campo x heredado oculta al campo x de Host.
• Los usuarios que lean el código tendrían una impresión equivocada
sobre lo que sucede, y más cuando no saben que campos tiene la clase
Desconocida, por lo que se recomienda calificar explícitamente la
referencia a x para saber a que x se refiere:
◦ this.x
◦ Host.this.x
Java– p. 15
TAREA

2. Crear un objeto del tipo Host para incrementar x usando el método


incrementar de la clase ayudante. Poner un método que muestre los
valores de x, tanto el campo x de la clase host como el de la clase que se
extiende. Poner otro método que incremente el campo x de la clase Host
dentro de la clase Ayudante.

Java– p. 16
Ejemplo
• Un método de una clase interna con el mismo nombre que un método de
la clase que la incluye, oculta todas las formas sobrecargadas del
método de la clase externa, incluso aunque la clase interna no declare
esas formas sobrecargadas.

class Externa {
void imprimir() { }
void imprimir(int val) { }

class Interna {
void imprimir() { }
void mostrar() {
imprimir();
Externa.this.imprimir();
imprimir(1); // Error: no Interna.imprimir(int)
}
}
}

Java– p. 17
Ejemplo cont.
• La declaración de Interna.imprimir oculta a todas las formas
sobrecargadas de la declaración de Externa.imprimir.
• Cuando Interna.mostrar invoca a imprimir(1), el compilador
informa de que Interna no tiene ningún método imprimir que tome
un parámetro entero.
• mostrar debe calificar explícitamente la invocación con
Externa.this

Java– p. 18
Clases Internas Locales
• Se definen en el cuerpo de un método, en un constructor o en un bloque
de inicialización.
• No son miembros de la clase de la cual es parte el bloque de código,
sino que son locales al bloque, al igual que las variables locales.
• Son totalmente inaccesibles desde el exterior del bloque de código donde
se define, pero las instancias de esas clases son objetos normales que
pueden ser pasados como parámetros, ser valores de retorno de
métodos, y que existen hasta que ya nadie más se refiere a ellas.
• El único modificador que se les puede aplicar es final.
• Puede acceder a todas las variables que estén dentro de alcance allí
donde dicha clase define, por ejemplo: variables locales, parámetros de
métodos, variables de instancia y variables estáticas.
• Pueden acceder a una variable o parámetro local de un método si están
declarados como final. Si es necesario, se puede copiar una variable
no final en una final, que será accedida después por la clase interna
local.

Java– p. 19
Ejemplo - Clase Interna Local

public static Iterator recorridoPor(final Object[] objs) {


class Iter implements Iterator {
private int pos = 0;
public boolean hasNext() {
return (pos < objs.length); }
public Object next() throws NoSuchElementException {
if (pos >= objs.length)
throw new NoSuchElementException();
return objs[pos++];
}
public void remove() {
throw new UnsupportedOperationException(); }
}
}

Java– p. 20
Clase Interna Local – Comentarios
• Método que devuelve un Iterator para recorrer un arreglo de objetos.
• La clase Iter es local en el método recorridoPor.
• Como Iter es local al método, tiene acceso a todas las variable finales
del método, por ejemplo objs
• Los miembros de las clases locales internas pueden ocultar las variables
y parámetros locales del bloque de código donde se declaran, o bien,
pueden ocultar campos y métodos de instancia.

Java– p. 21
Clases Internas Anónimas
• Pueden usarse cuando una clase interna local parece demasiado para
los requerimientos del programa.
• Las clases se definen en la propia expresión de new, como parte de una
sentencia.
• El tipo especificado en new es el supertipo de la clase anónima.
• Como Iterator es una interfaz, la clase anónima en recorridoPor
extiende implícitamente a Object e implementa a Iterator.

Java– p. 22
Clases Internas Anónimas – Ejemplo

public static Iterator recorridoPor(final Object[] objs) {


return new Iterator() {
private int pos = 0;

public boolean hasNext() {


return (pos < objs.length);
}

public Object next() throws NoSuchElementException {


if (pos >= objs.length)
throw new NoSuchElementException();
return objs[pos++];
}

public void remove() {


throw new UnsupportedOperationException();
}
};
}

Java– p. 23
Herencia de Tipos Anidados
• Los tipos anidados, sean clases o interfaces estáticas, o clases internas,
se heredan de la misma forma que se heredan los campos.
• Una declaración de un tipo anidado con el mismo nombre que el de un
tipo anidado heredado oculta la definición del tipo heredado.
• El tipo real referido se determina por el tipo de referencia usada.
• Dentro de una clase dada, el tipo anidado real referido es el definido en
la clase actual o el heredado en la clase actual.

Java– p. 24
Anidamiento de Interfaces
• Las clases e interfaces anidadas permiten asociar tipos que están
fuertemente relacionados con una interfaz dentro de esa interfaz.

interface Cambiable {

class Grabar {
public Object cambiador;
public String descCambiador;
}

Grabar getUltimoCambio ();

// ...
}

Java– p. 25
Anidamiento de Interfaces cont.
• El método getUltimoCambio devuelve un objeto Cambiable.Grabar
que contiene el objeto que realizó el cambio y una cadena que describe
el cambio.
• La clase tiene sólo significado para la interfaz Cambiable. por lo que no
se justifica que sea una clase de nivel superior.
• Otro uso de las clases anidadas dentro de una interfaz es definir una
implementación por defecto (parcial o completa) de dicha interfaz, donde
una clase que implemente la interfaz puede elegir extender la clase o
redirigir llamadas de métodos a una instancia de clase.
• Cualquier clase o interfaz anidada dentro de otra interfaz es pública y
estática, al igual que los miembros de las interfaces.

Java– p. 26
Variables Modificables en Interfaces
• Cuando se necesitan datos compartidos que sean modificables en una
interfaz, el uso de una clase interna es la forma más simple de
conseguirlo.
• En la clase interna se declaran los campos que almacenan los datos
compartidos y cuyos métodos proporcionen acceso a esos datos, y se
mantiene una referencia a una instancia de esa clase.

interface DatosCompartidos {

class Datos {
private int x = 0;
public int getX() { return x; }
public void setX(int nuevoX) { x = nuevoX; }
}

Datos datos = new Datos();


}

Java– p. 27
Implementación de Tipos Anidados
• Los tipos anidados se añadieron como una extensión al lenguaje que
tuvo que mantener compatibilidad con anteriores máquinas virtuales de
Java, con lo que los tipos anidados se implementaron en términos de
transformaciones del código fuente que aplica el compilador.

Java– p. 28

Вам также может понравиться