Compile as Listagens 5 e 6 da seguinte forma:
javac *.java
Quando você compila uma classe cujo método contém uma classe local, o compilador cria um arquivo de classe para a classe local cujo nome consiste no nome da classe envolvente, um caractere de cifrão, um inteiro de base 1 e o nome da classe local. Nesse caso, a compilação resulta em EnclosingClass$1LClass.class
e EnclosingClass.class
.
Uma nota sobre o nome do arquivo de classe local
Ao gerar um nome para um arquivo de classe de uma classe local, o compilador adiciona um inteiro ao nome gerado. Esse inteiro é provavelmente gerado para distinguir um arquivo de classe de uma classe local de um arquivo de classe de uma classe membro não estática. Se duas classes locais tiverem o mesmo nome, o compilador incrementa o inteiro para evitar conflitos. Considere o seguinte exemplo:
public class EnclosingClass
{
public void m1()
{
class LClass
{
}
}
public void m2()
{
class LClass
{
}
}
public void m3()
{
class LClass2
{
}
}
}
EnclosingClass
declara três métodos de instância que declaram cada um uma classe local. Os dois primeiros métodos geram duas classes locais diferentes com o mesmo nome. O compilador gera os seguintes arquivos de classe:
EnclosingClass$1LClass.class
EnclosingClass$1LClass2.class
EnclosingClass$2LClass.class
EnclosingClass.class
Execute o aplicativo da seguinte maneira:
java LCDemo
Você deve observar a seguinte saída:
5
15
Exemplo: Usando classes locais em expressões regulares
A biblioteca de classes padrão inclui exemplos de uso de classes locais. Por exemplo, o Matcher
classe, em java.util.regex
fornece um results()
método que retorna um fluxo de resultados de correspondência. Este método declara um MatchResultIterator
classe para iterar sobre esses resultados:
public Stream results()
{
class MatchResultIterator implements Iterator
{
// members
}
return StreamSupport.
stream(Spliterators.spliteratorUnknownSize(new MatchResultIterator(),
Spliterator.ORDERED |
Spliterator.NONNULL),
false);
}
Observe a instanciação de MatchResultIterator()
seguindo a declaração de classe. Não se preocupe com partes do código que você não entende; em vez disso, pense na utilidade de poder declarar classes nos escopos apropriados (como um corpo de método) para organizar melhor seu código.
Tipo de classe interna 3: Classes anônimas
Classes de membros estáticos, classes de membros não estáticos e classes locais têm nomes. Em contraste, aulas anônimas são classes aninhadas sem nome. Você as introduz no contexto de expressões que envolvem o new
operador e o nome de uma classe base ou de uma interface que é implementada pela classe anônima:
// subclass the base class
abstract class Base
{
// members
}
class A
{
void m()
{
Base b = new Base()
{
// members
};
}
}
// implement the interface
interface I
{
// members
}
class B
{
void m()
{
I i = new I()
{
// members
};
}
}
O primeiro exemplo demonstra uma classe anônima estendendo uma classe base. Expressão new Base()
é seguido por um par de caracteres de chaves que significam a classe anônima. O segundo exemplo demonstra uma classe anônima implementando uma interface. Expressão new I()
é seguido por um par de chaves que significam a classe anônima.
Classes anônimas são úteis para expressar funcionalidades que são passadas para um método como seu argumento. Por exemplo, considere um método para classificar uma matriz de inteiros. Você quer classificar a matriz em ordem crescente ou decrescente, com base em comparações entre pares de elementos da matriz. Você pode duplicar o código de classificação, com uma versão usando o menor que () operator for one order, and the other version using the greater than (
>
) operador para a ordem oposta. Alternativamente, como mostrado abaixo, você pode projetar o código de classificação para invocar um método de comparação e, em seguida, passar um objeto contendo esse método como um argumento para o método de classificação.
Listagem 7. Usando uma classe anônima para passar funcionalidade como argumento de método (Comparer.java)
public abstract class Comparer
{
public abstract int compare(int x, int y);
}
O compare()
O método é invocado com dois elementos de matriz inteira e retorna um dos três valores: um valor negativo se x
é menor que y
0 se ambos os valores forem iguais e um valor positivo se x
é maior que y
. A Listagem 8 apresenta uma aplicação cuja sort()
método invoca compare()
para realizar as comparações.
Listagem 8. Classificando um array de inteiros com o algoritmo Bubble Sort (ACDemo.java)
public class ACDemo
{
public static void main(String() args)
{
int() a = { 10, 30, 5, 0, -2, 100, -9 };
dump(a);
sort(a, new Comparer()
{
public int compare(int x, int y)
{
return x - y;
}
});
dump(a);
int() b = { 10, 30, 5, 0, -2, 100, -9 };
sort(b, new Comparer()
{
public int compare(int x, int y)
{
return y - x;
}
});
dump(b);
}
static void dump(int() x)
{
for (int i = 0; i pass; i--)
if (c.compare(x(i), x(pass))
O main()
método revela duas chamadas para seu companheiro sort()
método, que classifica uma matriz de inteiros por meio do algoritmo Bubble Sort. Cada chamada recebe uma matriz de inteiros como seu primeiro argumento e uma referência a um objeto criado a partir de um anônimo Comparer
subclasse como seu segundo argumento. A primeira chamada obtém uma classificação de ordem crescente subtraindo y
de x
; a segunda chamada obtém uma classificação em ordem decrescente subtraindo x
de y
.
Compile as Listagens 7 e 8 da seguinte forma:
javac *.java
Quando você compila uma classe cujo método contém uma classe anônima, o compilador cria um arquivo de classe para a classe anônima cujo nome consiste no nome da classe envolvente, um caractere de cifrão e um inteiro que identifica exclusivamente a classe anônima. Nesse caso, a compilação resulta em ACDemo$1.class
e ACDemo$2.class
além de ACDemo.class
.
Execute o aplicativo da seguinte maneira:
java ACDemo
Você deve observar a seguinte saída:
10 30 5 0 -2 100 -9
-9 -2 0 5 10 30 100
100 30 10 5 0 -2 -9
Exemplo: Usando classes anônimas com um manipulador de eventos AWT
Classes anônimas podem ser usadas com muitos pacotes na biblioteca de classes padrão. Para este exemplo, usaremos uma classe anônima como um manipulador de eventos no Abstract Windowing Toolkit ou Swing Windowing Toolkit. O seguinte fragmento de código registra um manipulador de eventos com o Swing’s JButton
classe, que está localizada na javax.swing
pacote. JButton
descreve um botão que executa uma ação (neste caso, imprimir uma mensagem) quando clicado.
JButton btnClose = new JButton("close");
btnClose.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
System.out.println("close button clicked");
}
});
A primeira linha instancia JButton
passando close
como o rótulo do botão para JButton
construtor de ‘s. A segunda linha registra um ouvinte de ação com o botão. O ouvinte de ação actionPerformed()
método é invocado sempre que o botão é clicado. O objeto passado para addActionListener()
é instanciado de uma classe anônima que implementa o java.awt.event.ActionListener
interface.
Conclusão
Os recursos de aninhamento do Java ajudam você a organizar tipos de referência não de nível superior. Para tipos de referência de nível superior, o Java fornece pacotes. O próximo Java 101 O tutorial apresenta pacotes e importações estáticas em Java.