Qual é o uso de classes anônimas em Java? Podemos dizer que o uso de classe anônima é uma das vantagens do Java?
Qual é o uso de classes anônimas em Java? Podemos dizer que o uso de classe anônima é uma das vantagens do Java?
Respostas:
Por uma "classe anônima", entendo que você quer dizer classe interna anônima .
Uma classe interna anônima pode ser útil ao criar uma instância de um objeto com certos "extras", como métodos de substituição, sem ter que realmente subclassificar uma classe.
Eu costumo usá-lo como um atalho para anexar um ouvinte de evento:
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// do something
}
});
O uso desse método torna a codificação um pouco mais rápida, pois não preciso criar uma classe extra que implemente ActionListener
- posso instanciar uma classe interna anônima sem criar uma classe separada.
Eu só uso essa técnica para tarefas "rápidas e sujas", onde fazer uma aula inteira parecer desnecessária. Ter várias classes internas anônimas que fazem exatamente a mesma coisa deve ser refatorada para uma classe real, seja uma classe interna ou uma classe separada.
overloading methods
e não overriding methods
?
Classes internas anônimas são efetivamente encerramentos, portanto podem ser usadas para emular expressões lambda ou "delegados". Por exemplo, considere esta interface:
public interface F<A, B> {
B f(A a);
}
Você pode usar isso anonimamente para criar uma função de primeira classe em Java. Digamos que você tenha o seguinte método que retorna o primeiro número maior que i na lista fornecida, ou i se nenhum número for maior:
public static int larger(final List<Integer> ns, final int i) {
for (Integer n : ns)
if (n > i)
return n;
return i;
}
E então você tem outro método que retorna o primeiro número menor que i na lista fornecida, ou i se nenhum número for menor:
public static int smaller(final List<Integer> ns, final int i) {
for (Integer n : ns)
if (n < i)
return n;
return i;
}
Esses métodos são quase idênticos. Usando a função de primeira classe tipo F, podemos reescrevê-los em um método da seguinte maneira:
public static <T> T firstMatch(final List<T> ts, final F<T, Boolean> f, T z) {
for (T t : ts)
if (f.f(t))
return t;
return z;
}
Você pode usar uma classe anônima para usar o método firstMatch:
F<Integer, Boolean> greaterThanTen = new F<Integer, Boolean> {
Boolean f(final Integer n) {
return n > 10;
}
};
int moreThanMyFingersCanCount = firstMatch(xs, greaterThanTen, x);
Este é um exemplo realmente elaborado, mas é fácil ver que poder transmitir funções como se fossem valores é um recurso bastante útil. Veja "Sua linguagem de programação pode fazer isso", do próprio Joel.
Uma boa biblioteca para programar Java neste estilo: Java funcional.
Classe interna anônima é usada no seguinte cenário:
1.) Para Substituir (Subclassificação), Quando a definição de classe não é utilizável, exceto no caso atual:
class A{
public void methodA() {
System.out.println("methodA");
}
}
class B{
A a = new A() {
public void methodA() {
System.out.println("anonymous methodA");
}
};
}
2.) Para implementar uma interface, quando a implementação da interface é necessária apenas para o caso atual:
interface interfaceA{
public void methodA();
}
class B{
interfaceA a = new interfaceA() {
public void methodA() {
System.out.println("anonymous methodA implementer");
}
};
}
3.) Classe interna anônima definida por argumento:
interface Foo {
void methodFoo();
}
class B{
void do(Foo f) { }
}
class A{
void methodA() {
B b = new B();
b.do(new Foo() {
public void methodFoo() {
System.out.println("methodFoo");
}
});
}
}
Às vezes, eu os uso como um hack da sintaxe para a instanciação do mapa:
Map map = new HashMap() {{
put("key", "value");
}};
vs
Map map = new HashMap();
map.put("key", "value");
Isso economiza redundância ao fazer várias declarações put. No entanto, também encontrei problemas ao fazer isso quando a classe externa precisa ser serializada via comunicação remota.
Eles são comumente usados como uma forma detalhada de retorno de chamada.
Suponho que você possa dizer que são uma vantagem em comparação a não tê-las e ter que criar uma classe nomeada todas as vezes, mas conceitos semelhantes são implementados muito melhor em outros idiomas (como fechamentos ou blocos)
Aqui está um exemplo de swing
myButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
// do stuff here...
}
});
Embora ainda seja confuso, é muito melhor do que forçar você a definir uma classe nomeada para cada ouvinte que joga fora isso (embora, dependendo da situação e reutilização, essa ainda seja a melhor abordagem)
myButton.addActionListener(e -> { /* do stuff here */})
ou myButton.addActionListener(stuff)
seria terser.
Você o usa em situações em que precisa criar uma classe para uma finalidade específica dentro de outra função, por exemplo, como ouvinte, como executável (para gerar um encadeamento), etc.
A idéia é que você os chame de dentro do código de uma função para nunca consultá-los em outro lugar, para não precisar nomeá-los. O compilador apenas os enumera.
Eles são essencialmente açúcar sintático e geralmente devem ser movidos para outro lugar à medida que crescem.
Não tenho certeza se essa é uma das vantagens do Java, mas se você as usar (e todas as usamos com frequência, infelizmente), poderá argumentar que elas são uma.
GuideLines para classe anônima.
A classe anônima é declarada e inicializada simultaneamente.
A classe anônima deve estender ou implementar para uma e apenas uma classe ou interface resp.
Como a classe anonymouse não tem nome, ela pode ser usada apenas uma vez.
por exemplo:
button.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
}
});
ref.getClass().newInstance()
.
Sim, classes internas anônimas são definitivamente uma das vantagens do Java.
Com uma classe interna anônima, você tem acesso às variáveis finais e membros da classe circundante, o que é útil para os ouvintes, etc.
Mas uma grande vantagem é que o código da classe interna, que é (pelo menos deve ser) fortemente acoplado à classe / método / bloco circundante, tem um contexto específico (a classe, o método e o bloco circundantes).
new Thread() {
public void run() {
try {
Thread.sleep(300);
} catch (InterruptedException e) {
System.out.println("Exception message: " + e.getMessage());
System.out.println("Exception cause: " + e.getCause());
}
}
}.start();
Este também é um exemplo de tipo interno anônimo usando thread
eu uso objetos anônimos para chamar novos threads.
new Thread(new Runnable() {
public void run() {
// you code
}
}).start();
Uma classe interna está associada a uma instância da classe externa e existem dois tipos especiais: Classe local e classe Anônima . Uma classe anônima nos permite declarar e instanciar uma classe ao mesmo tempo, tornando o código conciso. Nós os usamos quando precisamos de uma classe local apenas uma vez, pois eles não têm nome.
Considere o exemplo do doc em que temos uma Person
classe:
public class Person {
public enum Sex {
MALE, FEMALE
}
String name;
LocalDate birthday;
Sex gender;
String emailAddress;
public int getAge() {
// ...
}
public void printPerson() {
// ...
}
}
e temos um método para imprimir membros que correspondem aos critérios de pesquisa como:
public static void printPersons(
List<Person> roster, CheckPerson tester) {
for (Person p : roster) {
if (tester.test(p)) {
p.printPerson();
}
}
}
Onde CheckPerson
está uma interface como:
interface CheckPerson {
boolean test(Person p);
}
Agora podemos usar a classe anônima que implementa essa interface para especificar critérios de pesquisa como:
printPersons(
roster,
new CheckPerson() {
public boolean test(Person p) {
return p.getGender() == Person.Sex.MALE
&& p.getAge() >= 18
&& p.getAge() <= 25;
}
}
);
Aqui a interface é muito simples e a sintaxe da classe anônima parece pesada e pouco clara.
O Java 8 introduziu um termo Interface Funcional, que é uma interface com apenas um método abstrato; portanto, podemos dizer que CheckPerson
é uma interface funcional. Podemos fazer uso da expressão Lambda, que nos permite passar a função como argumento do método como:
printPersons(
roster,
(Person p) -> p.getGender() == Person.Sex.MALE
&& p.getAge() >= 18
&& p.getAge() <= 25
);
Podemos usar uma interface funcional padrão Predicate
no lugar da interface CheckPerson
, o que reduzirá ainda mais a quantidade de código necessária.
A classe interna anônima pode ser benéfica ao fornecer implementações diferentes para objetos diferentes. Mas deve ser usado com moderação, pois cria problemas para a legibilidade do programa.
Um dos principais usos de classes anônimas na finalização de classe, chamada de finalizador guardião . No mundo Java, os métodos finalize devem ser evitados até que você realmente precise deles. Lembre-se de que, quando você substitui o método finalize para subclasses, sempre deve invocá-lo super.finalize()
, porque o método finalize da superclasse não invocará automaticamente e você pode ter problemas com vazamentos de memória.
portanto, considerando o fato mencionado acima, você pode simplesmente usar as classes anônimas como:
public class HeavyClass{
private final Object finalizerGuardian = new Object() {
@Override
protected void finalize() throws Throwable{
//Finalize outer HeavyClass object
}
};
}
Ao usar essa técnica, você e seus outros desenvolvedores se livraram de chamar super.finalize()
cada subclasse do HeavyClass
método que precisa finalizar.
Parece que ninguém foi mencionado aqui, mas você também pode usar a classe anônima para armazenar argumentos de tipo genérico (que normalmente são perdidos devido ao apagamento do tipo) :
public abstract class TypeHolder<T> {
private final Type type;
public TypeReference() {
// you may do do additional sanity checks here
final Type superClass = getClass().getGenericSuperclass();
this.type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
}
public final Type getType() {
return this.type;
}
}
Se você instanciar essa classe de maneira anônima
TypeHolder<List<String>, Map<Ineger, Long>> holder =
new TypeHolder<List<String>, Map<Ineger, Long>>() {};
essa holder
instância conterá uma definição não apagada do tipo passado.
Isso é muito útil para criar validadores / desserializadores. Além disso, você pode instanciar o tipo genérico com reflexão (por isso, se você quiser fazer new T()
no tipo parametrizado - seja bem-vindo!) .
A melhor maneira de otimizar o código. Além disso, podemos usar o método de substituição de uma classe ou interface.
import java.util.Scanner;
abstract class AnonymousInner {
abstract void sum();
}
class AnonymousInnerMain {
public static void main(String []k){
Scanner sn = new Scanner(System.in);
System.out.println("Enter two vlaues");
int a= Integer.parseInt(sn.nextLine());
int b= Integer.parseInt(sn.nextLine());
AnonymousInner ac = new AnonymousInner(){
void sum(){
int c= a+b;
System.out.println("Sum of two number is: "+c);
}
};
ac.sum();
}
}
Uma classe interna anônima é usada para criar um objeto que nunca será referenciado novamente. Ele não tem nome e é declarado e criado na mesma instrução. Isso é usado onde você normalmente usaria a variável de um objeto. Você substitui a variável pela new
palavra - chave, uma chamada para um construtor e a definição de classe dentro {
e }
.
Ao escrever um programa encadeado em Java, normalmente seria assim
ThreadClass task = new ThreadClass();
Thread runner = new Thread(task);
runner.start();
O ThreadClass
usado aqui seria definido pelo usuário. Esta classe implementará a Runnable
interface necessária para criar threads. No ThreadClass
o run()
método (único método Runnable
) precisa ser implementado também. É claro que se livrar ThreadClass
seria mais eficiente e é exatamente por isso que existem Classes Internas Anônimas.
Veja o seguinte código
Thread runner = new Thread(new Runnable() {
public void run() {
//Thread does it's work here
}
});
runner.start();
Este código substitui a referência feita task
no exemplo mais importante. Em vez de ter uma classe separada, a Classe Interna Anônima dentro do Thread()
construtor retorna um objeto sem nome que implementa a Runnable
interface e substitui o run()
método. O método run()
incluiria instruções internas que fazem o trabalho exigido pelo encadeamento.
Respondendo à pergunta sobre se Anonymous Inner Classes é uma das vantagens do Java, devo dizer que não tenho muita certeza, pois não estou familiarizado com muitas linguagens de programação no momento. Mas o que posso dizer é que é definitivamente um método mais rápido e fácil de codificar.
Referências: Sams ensina-se Java em 21 dias sétima edição