Eu estava olhando para o código Java LinkedList
e notei que ele fazia uso de uma classe aninhada estática Entry
.
public class LinkedList<E> ... {
...
private static class Entry<E> { ... }
}
Qual é o motivo do uso de uma classe aninhada estática, em vez de uma classe interna normal?
A única razão pela qual pude pensar foi que o Entry não tem acesso a variáveis de instância, portanto, do ponto de vista do OOP, ele possui um melhor encapsulamento.
Mas pensei que poderia haver outras razões, talvez desempenho. O que poderia ser?
Nota. Espero que meus termos estejam corretos, eu chamaria de classe interna estática, mas acho que isso está errado: http://java.sun.com/docs/books/tutorial/java/javaOO/nested.html
Respostas:
A página da Sun à qual você vincula possui algumas diferenças importantes entre as duas:
Não é necessário
LinkedList.Entry
haver uma classe de nível superior, pois ela é usada apenasLinkedList
(existem outras interfaces que também têm classes aninhadas estáticas nomeadasEntry
, comoMap.Entry
- mesmo conceito). E como não precisa acessar os membros do LinkedList, faz sentido que seja estático - é uma abordagem muito mais limpa.Como Jon Skeet aponta , acho que é uma idéia melhor se você estiver usando uma classe aninhada começar com a estática e decidir se realmente precisa ser não estática com base no seu uso.
fonte
#comment113712_253507
A static nested class interacts with the instance members of its outer class (and other classes) just like any other top-level class
como isso é possível se apenas um parágrafo antes da documentação diz o seguinte:Static nested classes do not have access to other members of the enclosing class
Talvez eles gostariam de dizer:A nested (non-static) class interacts with the instance members of its outer class (and other classes) just like any other top-level class
An inner class interacts with the instance members through an implicit reference to its enclosing class
e isso aponta outra propriedade interessante denon-static inner classes
as wellanonymous inner classes
or orlocal classes defined inside a block
: todos eles não podem ter umno-arg
construtor, pois o compilador implicitamente precederá a sequência arg de cada construtor para passar uma referência de uma instância do anexo classe. Bem simples.Na minha opinião, a pergunta deve ser inversa sempre que você vê uma classe interna - ela realmente precisa ser uma classe interna, com a complexidade extra e a referência implícita (em vez de IMO explícita e clara) a uma instância? da classe que contém?
Lembre-se, sou tendencioso como um fã de C # - C # não tem o equivalente a classes internas, embora tenha tipos aninhados. Não posso dizer que perdi as classes internas ainda :)
fonte
Há problemas não óbvios de retenção de memória a serem considerados aqui. Como uma classe interna não estática mantém uma referência implícita à classe 'externa', se uma instância da classe interna for fortemente referenciada, a instância externa também será fortemente referenciada. Isso pode levar a um arranhão na cabeça quando a classe externa não é coletada como lixo, mesmo que pareça que nada faça referência a ela.
fonte
Bem, por um lado, as classes internas não estáticas têm um campo extra e oculto que aponta para a instância da classe externa. Portanto, se a classe Entry não fosse estática, além de ter acesso desnecessário, levaria quatro ponteiros em vez de três.
Como regra, eu diria que, se você definir uma classe que está basicamente lá para atuar como uma coleção de membros de dados, como uma "estrutura" em C, considere torná-la estática.
fonte
A classe interna estática é usada no padrão do construtor. A classe interna estática pode instanciar sua classe externa, que possui apenas construtor privado. Portanto, você pode usar a classe interna estática para instanciar a classe externa que possui apenas construtor privado. Você não pode fazer o mesmo com a classe interna, pois é necessário que o objeto da classe externa seja criado antes de acessar a classe interna.
Isso produzirá x: 1
fonte
A classe aninhada estática é como qualquer outra classe externa, pois não tem acesso aos membros da classe externa.
Apenas por conveniência de empacotamento, podemos agrupar classes aninhadas estáticas em uma classe externa para fins de legibilidade. Fora isso, não há outro caso de uso da classe aninhada estática.
Exemplo para esse tipo de uso, você pode encontrar no arquivo Android R.java (recursos). A pasta Res do android contém layouts (contendo designs de tela), pasta drawable (contendo imagens usadas para o projeto), pasta values (que contém constantes de string), etc.
Como todas as pastas fazem parte da pasta Res, a ferramenta Android gera um arquivo R.java (recursos) que contém internamente muitas classes aninhadas estáticas para cada uma de suas pastas internas.
Aqui está a aparência do arquivo R.java gerado no Android: Aqui eles estão usando apenas para conveniência de empacotamento.
fonte
Em http://docs.oracle.com/javase/tutorial/java/javaOO/whentouse.html :
fonte
Exemplo simples:
Se não estática, a classe não pode ser instanciada, exceto em uma instância da classe superior (portanto, não no exemplo em que main é uma função estática)
fonte
Uma das razões para estática versus normal tem a ver com carregamento de classe. Você não pode instanciar uma classe interna no construtor de seu pai.
PS: Eu sempre entendi 'aninhado' e 'interno' como intercambiáveis. Pode haver nuances sutis nos termos, mas a maioria dos desenvolvedores de Java também entenderia.
fonte
Classes internas não estáticas podem resultar em vazamentos de memória enquanto a classe interna estática irá protegê-las. Se a classe externa contiver dados consideráveis, poderá diminuir o desempenho do aplicativo.
fonte
Eu não sei sobre diferença de desempenho, mas como você diz, a classe aninhada estática não faz parte de uma instância da classe envolvente. Parece mais simples criar uma classe aninhada estática, a menos que você realmente precise que ela seja uma classe interna.
É um pouco como por que eu sempre faço minhas variáveis finais em Java - se elas não são finais, eu sei que há algo engraçado acontecendo com elas. Se você usar uma classe interna em vez de uma classe aninhada estática, deve haver um bom motivo.
fonte
Usar uma classe aninhada estática em vez de não estática pode economizar espaço em alguns casos. Por exemplo: implementando um
Comparator
dentro de uma classe, diga Aluno.Então os
static
garante que a classe estudante tem apenas um comparador, em vez de instanciar um novo a cada vez que uma nova instância do estudante é criado.fonte
Vantagem da classe interna
Sem existir classe externa, a classe interna não existirá.
Existem quatro tipos de classe interna.
ponto ---
para invocar a classe interna normal na área estática da classe externa.
Outer 0=new Outer(); Outer.Inner i= O.new Inner();
para invocar a classe interna normal na área de instância da classe externa.
Inner i=new Inner();
para invocar a classe interna normal fora da classe externa.
Outer 0=new Outer(); Outer.Inner i= O.new Inner();
inside Inner class Esse ponteiro para a classe interna.
this.member-current inner class outerclassname.this--outer class
para a classe interna, o modificador aplicável é - público, padrão,
final,abstract,strictfp,+private,protected,static
outer $ inner é o nome do nome da classe interna.
classe interna dentro do método de instância, podemos acessar o campo estático e de instância da classe externa.
Classe 10.inner dentro do método estático, então podemos acessar apenas o campo estático de
classe externa.
fonte