Qual é a principal diferença entre uma classe interna e uma classe aninhada estática em Java? O design / implementação desempenha um papel na escolha de um deles?
Qual é a principal diferença entre uma classe interna e uma classe aninhada estática em Java? O design / implementação desempenha um papel na escolha de um deles?
Respostas:
No Tutorial Java :
Classes aninhadas são divididas em duas categorias: estática e não estática. Classes aninhadas declaradas estáticas são chamadas simplesmente de classes aninhadas estáticas. Classes aninhadas não estáticas são chamadas de classes internas.
Classes aninhadas estáticas são acessadas usando o nome da classe anexa:
OuterClass.StaticNestedClass
Por exemplo, para criar um objeto para a classe aninhada estática, use esta sintaxe:
OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();
Objetos que são instâncias de uma classe interna existem dentro de uma instância da classe externa. Considere as seguintes classes:
class OuterClass {
...
class InnerClass {
...
}
}
Uma instância do InnerClass pode existir apenas dentro de uma instância do OuterClass e tem acesso direto aos métodos e campos de sua instância anexa.
Para instanciar uma classe interna, você deve primeiro instanciar a classe externa. Em seguida, crie o objeto interno dentro do objeto externo com esta sintaxe:
OuterClass outerObject = new OuterClass()
OuterClass.InnerClass innerObject = outerObject.new InnerClass();
consulte: Tutorial Java - Classes aninhadas
Para completar, observe que também existe uma classe interna sem uma instância anexa :
class A {
int t() { return 1; }
static A a = new A() { int t() { return 2; } };
}
Aqui, new A() { ... }
é uma classe interna definida em um contexto estático e não possui uma instância anexa.
import OuterClass.StaticNestedClass;
seguida, fazer referência a classe apenas como OuterClass.
OuterClass.InnerClass innerObject = outerObject.new InnerClass();
?
Terminologia: as classes aninhadas são divididas em duas categorias: estática e não estática. Classes aninhadas declaradas estáticas são chamadas simplesmente de classes aninhadas estáticas. Classes aninhadas não estáticas são chamadas de classes internas.
Na linguagem comum, os termos "aninhado" e "interno" são usados de forma intercambiável pela maioria dos programadores, mas usarei o termo correto "classe aninhada", que abrange interno e estático.
As classes podem ser aninhadas ad infinitum , por exemplo, a classe A pode conter a classe B, que contém a classe C, que contém a classe D, etc. No entanto, mais de um nível de aninhamento de classe é raro, pois geralmente é um design ruim.
Há três razões para você criar uma classe aninhada:
Existem quatro tipos de classe aninhada em Java . Em resumo, são eles:
Deixe-me elaborar em mais detalhes.
Classes estáticas são o tipo mais fácil de entender porque não têm nada a ver com instâncias da classe que os contém.
Uma classe estática é uma classe declarada como um membro estático de outra classe. Assim como outros membros estáticos, essa classe é realmente apenas um cabide que usa a classe que contém como espaço para nome, por exemplo , a classe Goat declarada como membro estático da classe Rhino no pacote pizza é conhecida pelo nome pizza.Rhino.Goat .
package pizza;
public class Rhino {
...
public static class Goat {
...
}
}
Francamente, classes estáticas são um recurso inútil, porque as classes já estão divididas em namespaces por pacotes. A única razão real concebível para criar uma classe estática é que essa classe tem acesso aos membros estáticos privados da classe que a contém, mas acho que essa é uma justificativa bastante fraca para o recurso de classe estática.
Uma classe interna é uma classe declarada como um membro não estático de outra classe:
package pizza;
public class Rhino {
public class Goat {
...
}
private void jerry() {
Goat g = new Goat();
}
}
Como em uma classe estática, a classe interna é conhecida como qualificada pelo nome da classe que contém, pizza.Rhino.Goat , mas dentro da classe que contém, ela pode ser conhecida pelo nome simples. No entanto, toda instância de uma classe interna está vinculada a uma instância específica de sua classe que contém: acima, o Goat criado em jerry , está implicitamente vinculado à instância do Rhino que está em jerry . Caso contrário, tornamos explícita a instância associada do Rhino quando instanciamos o Goat :
Rhino rhino = new Rhino();
Rhino.Goat goat = rhino.new Goat();
(Observe que você se refere ao tipo interno como apenas Goat na nova e estranha sintaxe: Java infere o tipo que contém a parte rhino . E sim, o novo rhino.Goat () também faria mais sentido para mim.)
Então, o que isso nos ganha? Bem, a instância da classe interna tem acesso aos membros da instância da classe que o contém. Estes membros de instância envolvente são referidos dentro da classe interna através de apenas os seus nomes simples, não via este ( esta na classe interna refere-se à ocorrência de classe interior, não contendo a instância de classe associado):
public class Rhino {
private String barry;
public class Goat {
public void colin() {
System.out.println(barry);
}
}
}
Na classe interna, você pode se referir a isso da classe que contém como Rhino.this e pode usar isso para se referir a seus membros, por exemplo , Rhino.this.barry .
Uma classe interna local é uma classe declarada no corpo de um método. Essa classe é conhecida apenas em seu método de contenção; portanto, ela só pode ser instanciada e ter seus membros acessados em seu método de contenção. O ganho é que uma instância local da classe interna está vinculada e pode acessar as variáveis locais finais do seu método que o contém. Quando a instância usa um local final do método que a contém, a variável retém o valor que ela mantinha no momento da criação da instância, mesmo que a variável tenha saído do escopo (essa é efetivamente a versão bruta e limitada de fechamentos de Java).
Como uma classe interna local não é membro de uma classe ou pacote, ela não é declarada com um nível de acesso. (Seja claro, no entanto, que seus próprios membros têm níveis de acesso como em uma classe normal.)
Se uma classe interna local é declarada em um método de instância, uma instanciação da classe interna é vinculada à instância mantida pelos métodos contendo isso no momento da criação da instância e, portanto, os membros da instância da classe que estão contidos são acessíveis como em uma instância classe interna. Uma classe interna local é instanciada simplesmente por seu nome, por exemplo , a classe interna local Cat é instanciada como nova Cat () , não nova this.Cat () como você poderia esperar.
Uma classe interna anônima é uma maneira sintaticamente conveniente de escrever uma classe interna local. Geralmente, uma classe interna local é instanciada no máximo apenas uma vez cada vez que seu método de contenção é executado. Seria bom, então, se pudéssemos combinar a definição de classe interna local e sua instanciação única em uma forma de sintaxe conveniente, e também seria bom se não tivéssemos que criar um nome para a classe (quanto menos inútil nomes que seu código contém, melhor). Uma classe interna anônima permite essas duas coisas:
new *ParentClassName*(*constructorArgs*) {*members*}
Esta é uma expressão retornando uma nova instância de uma classe sem nome que estende ParentClassName . Você não pode fornecer seu próprio construtor; ao contrário, é fornecido um implicitamente que simplesmente chama o super construtor, de modo que os argumentos fornecidos devem se encaixar no super construtor. (Se o pai contém vários construtores, o “mais simples” é chamado de “mais simples”, conforme determinado por um conjunto bastante complexo de regras que não vale a pena se preocupar em aprender em detalhes - basta prestar atenção ao que o NetBeans ou o Eclipse lhe dizem.)
Como alternativa, você pode especificar uma interface para implementar:
new *InterfaceName*() {*members*}
Essa declaração cria uma nova instância de uma classe sem nome que estende Object e implementa InterfaceName . Novamente, você não pode fornecer seu próprio construtor; nesse caso, o Java fornece implicitamente um construtor sem argumento, não faça nada (portanto, nunca haverá argumentos construtores nesse caso).
Mesmo que você não possa atribuir a uma classe interna anônima um construtor, você ainda pode fazer qualquer configuração desejada usando um bloco inicializador (um bloco {} colocado fora de qualquer método).
Seja claro que uma classe interna anônima é simplesmente uma maneira menos flexível de criar uma classe interna local com uma instância. Se você deseja uma classe interna local que implementa várias interfaces ou que implementa interfaces enquanto estende alguma classe que não seja Object ou especifica seu próprio construtor, você está impedido de criar uma classe interna local nomeada regular.
Eu não acho que a diferença real ficou clara nas respostas acima.
Primeiro, para acertar os termos:
A resposta de Martin está certa até agora. No entanto, a pergunta real é: Qual é o objetivo de declarar uma classe aninhada estática ou não?
Você usa classes aninhadas estáticas se desejar apenas manter suas classes unidas se pertencerem topicamente juntas ou se a classe aninhada for usada exclusivamente na classe envolvente. Não há diferença semântica entre uma classe aninhada estática e todas as outras classes.
Classes aninhadas não estáticas são um animal diferente. Semelhante às classes internas anônimas, essas classes aninhadas são na verdade encerramentos. Isso significa que eles capturam seu escopo circundante e sua instância anexa e o tornam acessível. Talvez um exemplo esclareça isso. Veja este esboço de um contêiner:
public class Container {
public class Item{
Object data;
public Container getContainer(){
return Container.this;
}
public Item(Object data) {
super();
this.data = data;
}
}
public static Item create(Object data){
// does not compile since no instance of Container is available
return new Item(data);
}
public Item createSubItem(Object data){
// compiles, since 'this' Container is available
return new Item(data);
}
}
Nesse caso, você deseja ter uma referência de um item filho para o contêiner pai. Usando uma classe aninhada não estática, isso funciona sem algum trabalho. Você pode acessar a instância anexa do Container com a sintaxe Container.this
.
Explicações mais explícitas a seguir:
Se você observar os bytecodes Java que o compilador gera para uma classe aninhada (não estática), pode ficar ainda mais claro:
// class version 49.0 (49)
// access flags 33
public class Container$Item {
// compiled from: Container.java
// access flags 1
public INNERCLASS Container$Item Container Item
// access flags 0
Object data
// access flags 4112
final Container this$0
// access flags 1
public getContainer() : Container
L0
LINENUMBER 7 L0
ALOAD 0: this
GETFIELD Container$Item.this$0 : Container
ARETURN
L1
LOCALVARIABLE this Container$Item L0 L1 0
MAXSTACK = 1
MAXLOCALS = 1
// access flags 1
public <init>(Container,Object) : void
L0
LINENUMBER 12 L0
ALOAD 0: this
ALOAD 1
PUTFIELD Container$Item.this$0 : Container
L1
LINENUMBER 10 L1
ALOAD 0: this
INVOKESPECIAL Object.<init>() : void
L2
LINENUMBER 11 L2
ALOAD 0: this
ALOAD 2: data
PUTFIELD Container$Item.data : Object
RETURN
L3
LOCALVARIABLE this Container$Item L0 L3 0
LOCALVARIABLE data Object L0 L3 2
MAXSTACK = 2
MAXLOCALS = 3
}
Como você pode ver, o compilador cria um campo oculto Container this$0
. Isso é definido no construtor que possui um parâmetro adicional do tipo Container para especificar a instância anexa. Você não pode ver esse parâmetro na fonte, mas o compilador o gera implicitamente para uma classe aninhada.
O exemplo de Martin
OuterClass.InnerClass innerObject = outerObject.new InnerClass();
seria assim compilado para uma chamada de algo como (em bytecodes)
new InnerClass(outerObject)
Por uma questão de completude:
Uma classe anônima é um exemplo perfeito de uma classe aninhada não estática que simplesmente não tem nome associado a ela e não pode ser referenciada posteriormente.
Penso que nenhuma das respostas acima explica a diferença real entre uma classe aninhada e uma classe aninhada estática no termo do design do aplicativo:
Uma classe aninhada pode ser não estática ou estática e, em cada caso, é uma classe definida em outra classe . Uma classe aninhada deve existir apenas para servir é a classe envolvente , se uma classe aninhada for útil para outras classes (não apenas a envolvente), deve ser declarada como uma classe de nível superior.
Classe aninhada não estática : está implicitamente associada à instância anexa da classe que contém, isso significa que é possível chamar métodos e acessar variáveis da instância anexa. Um uso comum de uma classe aninhada não estática é definir uma classe Adapter.
Classe aninhada estática : não pode acessar a instância da classe anexa e invocar métodos nela; portanto, deve ser usado quando a classe aninhada não exigir acesso a uma instância da classe anexa. Um uso comum da classe aninhada estática é implementar componentes do objeto externo.
Portanto, a principal diferença entre os dois do ponto de vista do design é: a classe aninhada não estática pode acessar a instância da classe de contêiner, enquanto a estática não .
Em termos simples, precisamos de classes aninhadas principalmente porque o Java não fornece fechamentos.
Classes aninhadas são classes definidas dentro do corpo de outra classe anexa. Eles são de dois tipos - estáticos e não estáticos.
Eles são tratados como membros da classe envolvente, portanto, você pode especificar qualquer um dos quatro especificadores de acesso - private, package, protected, public
. Não temos esse luxo com classes de nível superior, que só podem ser declaradas public
ou privadas de pacotes.
Classes internas, também conhecidas como classes sem pilha, têm acesso a outros membros da classe superior, mesmo que sejam declaradas privadas enquanto as classes aninhadas estáticas não têm acesso a outros membros da classe superior.
public class OuterClass {
public static class Inner1 {
}
public class Inner2 {
}
}
Inner1
é nossa classe interna estática e Inner2
é nossa classe interna que não é estática. A principal diferença entre eles, você não pode criar uma Inner2
instância sem um Exterior, onde você pode criar um Inner1
objeto independentemente.
Quando você usaria a classe Inner?
Pense em uma situação em que Class A
e Class B
relacionados, Class B
precise acessar os Class A
membros e Class B
só esteja relacionado a Class A
. Classes internas entram em cena.
Para criar uma instância da classe interna, você precisa criar uma instância da sua classe externa.
OuterClass outer = new OuterClass();
OuterClass.Inner2 inner = outer.new Inner2();
ou
OuterClass.Inner2 inner = new OuterClass().new Inner2();
Quando você usaria a classe interna estática?
Você definiria uma classe interna estática quando souber que ela não tem nenhum relacionamento com a instância da classe / classe superior envolvente. Se a sua classe interna não usa métodos ou campos da classe externa, é apenas um desperdício de espaço; portanto, torne-o estático.
Por exemplo, para criar um objeto para a classe aninhada estática, use esta sintaxe:
OuterClass.Inner1 nestedObject = new OuterClass.Inner1();
A vantagem de uma classe aninhada estática é que ela não precisa de um objeto da classe / classe superior para funcionar. Isso pode ajudar a reduzir o número de objetos que seu aplicativo cria em tempo de execução.
OuterClass.Inner2 inner = outer.new Inner2();
?
static inner
é uma contradição em termos.
Aqui estão as principais diferenças e semelhanças entre a classe interna Java e a classe aninhada estática.
Espero que ajude!
Associado à instância da classe envolvente , para instanciar primeiro, é necessária uma instância da classe externa (observe o novo local da palavra-chave):
Outerclass.InnerClass innerObject = outerObject.new Innerclass();
Não pode definir quaisquer membros estáticos em si
Não é possível acessar métodos ou campos de instância de classe externa
Não está associado a nenhuma instância da classe envolvente. Portanto, para instanciar:
OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();
De acordo com a documentação da Oracle, existem vários motivos ( documentação completa ):
É uma maneira de agrupar logicamente classes que são usadas apenas em um local: se uma classe é útil para apenas uma outra classe, é lógico incorporá-la nessa classe e manter as duas juntas. Aninhar essas "classes auxiliares" torna seu pacote mais otimizado.
Aumenta o encapsulamento: considere duas classes de nível superior, A e B, em que B precisa acessar membros de A que, de outra forma, seriam declarados privados. Ao ocultar a classe B na classe A, os membros de A podem ser declarados privados e B pode acessá-los. Além disso, o próprio B pode ser oculto do mundo exterior.
Isso pode levar a um código mais legível e de manutenção: o aninhamento de pequenas classes nas classes de nível superior coloca o código mais perto de onde é usado.
Eu acho que a convenção geralmente seguida é a seguinte:
No entanto, alguns outros pontos a serem lembrados são:
As classes de nível superior e a classe aninhada estática são semanticamente iguais, exceto que, no caso da classe aninhada estática, ela pode fazer referência estática aos campos / métodos estáticos privados de sua classe [pai] externa e vice-versa.
As classes internas têm acesso a variáveis de instância da instância anexa da classe Outer [parent]. No entanto, nem todas as classes internas possuem instâncias encerradas, por exemplo, classes internas em contextos estáticos, como uma classe anônima usada em um bloco inicializador estático, não.
A classe anônima, por padrão, estende a classe pai ou implementa a interface pai e não há cláusula adicional para estender qualquer outra classe ou implementar mais interfaces. Assim,
new YourClass(){};
significa class [Anonymous] extends YourClass {}
new YourInterface(){};
significa class [Anonymous] implements YourInterface {}
Eu sinto que a questão maior que permanece em aberto é qual e quando usar? Bem, isso depende principalmente do cenário em que você está lidando, mas a leitura da resposta dada por @jrudolph pode ajudá-lo a tomar alguma decisão.
Classe aninhada: classe dentro da classe
Tipos:
Diferença:
Classe aninhada não estática [Classe interna]
Na classe aninhada não estática, o objeto da classe interna existe dentro do objeto da classe externa. Portanto, esse membro de dados da classe externa é acessível à classe interna. Portanto, para criar um objeto da classe interna, primeiro devemos criar um objeto da classe externa.
outerclass outerobject=new outerobject();
outerclass.innerclass innerobjcet=outerobject.new innerclass();
Classe aninhada estática
Na classe estática aninhada, o objeto da classe interna não precisa de um objeto da classe externa, porque a palavra "estática" indica que não há necessidade de criar um objeto.
class outerclass A {
static class nestedclass B {
static int x = 10;
}
}
Se você deseja acessar x, escreva o seguinte método interno
outerclass.nestedclass.x; i.e. System.out.prinltn( outerclass.nestedclass.x);
A instância da classe interna é criada quando a instância da classe externa é criada. Portanto, os membros e métodos da classe interna têm acesso aos membros e métodos da instância (objeto) da classe externa. Quando a instância da classe externa sai do escopo, também as instâncias da classe interna deixam de existir.
A classe aninhada estática não possui uma instância concreta. É carregado apenas quando usado pela primeira vez (assim como os métodos estáticos). É uma entidade completamente independente, cujos métodos e variáveis não têm acesso às instâncias da classe externa.
As classes aninhadas estáticas não são acopladas ao objeto externo, são mais rápidas e não levam memória de pilha / pilha, porque não é necessário criar uma instância dessa classe. Portanto, a regra geral é tentar definir a classe aninhada estática, com escopo tão limitado quanto possível (privado> = classe> = protegido> = público) e, em seguida, convertê-la em classe interna (removendo o identificador "estático") e soltar o escopo, se for realmente necessário.
Há uma sutileza sobre o uso de classes estáticas aninhadas que podem ser úteis em determinadas situações.
Enquanto os atributos estáticos são instanciados antes que a classe seja instanciada por meio de seu construtor, os atributos estáticos dentro das classes estáticas aninhadas não parecem instanciados até depois que o construtor da classe é chamado, ou pelo menos não depois que os atributos são referenciados pela primeira vez, mesmo se eles são marcados como 'final'.
Considere este exemplo:
public class C0 {
static C0 instance = null;
// Uncomment the following line and a null pointer exception will be
// generated before anything gets printed.
//public static final String outerItem = instance.makeString(98.6);
public C0() {
instance = this;
}
public String makeString(int i) {
return ((new Integer(i)).toString());
}
public String makeString(double d) {
return ((new Double(d)).toString());
}
public static final class nested {
public static final String innerItem = instance.makeString(42);
}
static public void main(String[] argv) {
System.out.println("start");
// Comment out this line and a null pointer exception will be
// generated after "start" prints and before the following
// try/catch block even gets entered.
new C0();
try {
System.out.println("retrieve item: " + nested.innerItem);
}
catch (Exception e) {
System.out.println("failed to retrieve item: " + e.toString());
}
System.out.println("finish");
}
}
Mesmo que 'aninhado' e 'innerItem' sejam declarados como 'estático final'. a configuração de nested.innerItem não ocorre até depois que a classe é instanciada (ou pelo menos não depois que o item estático aninhado é referenciado pela primeira vez), como você pode ver ao comentar e descomentar as linhas às quais me refiro, acima. O mesmo não vale para 'outerItem'.
Pelo menos é o que estou vendo no Java 6.0.
Os termos são usados de forma intercambiável. Se você quiser ser realmente pedante sobre isso, poderá definir "classe aninhada" para se referir a uma classe interna estática, uma que não possui instância anexa. No código, você pode ter algo parecido com isto:
public class Outer {
public class Inner {}
public static class Nested {}
}
Essa não é realmente uma definição amplamente aceita.
No caso de criação de instância, a instância de classe interna não estática é criada com a referência do objeto da classe externa na qual está definida. Isso significa que ele tem uma instância abrangente. Mas a instância da classe interna estática é criada com a referência da classe Externa, não com a referência do objeto da classe externa. Isso significa que não há instância detalhada.
Por exemplo:
class A
{
class B
{
// static int x; not allowed here…..
}
static class C
{
static int x; // allowed here
}
}
class Test
{
public static void main(String… str)
{
A o=new A();
A.B obj1 =o.new B();//need of inclosing instance
A.C obj2 =new A.C();
// not need of reference of object of outer class….
}
}
Não acho que haja muito a acrescentar aqui, a maioria das respostas explica perfeitamente as diferenças entre a classe aninhada estática e as classes Inner. No entanto, considere o seguinte problema ao usar classes aninhadas x classes internas. Como mencionado em algumas respostas, as classes internas não podem ser instanciadas sem uma instância de sua classe envolvente, o que significa que eles mantêm um ponteiro para a instância de sua classe envolvente, o que pode levar ao estouro de memória ou à exceção de excesso de pilha devido ao fato de o GC não poderá coletar lixo as classes anexas, mesmo que elas não sejam mais usadas. Para deixar isso claro, verifique o seguinte código:
public class Outer {
public class Inner {
}
public Inner inner(){
return new Inner();
}
@Override
protected void finalize() throws Throwable {
// as you know finalize is called by the garbage collector due to destroying an object instance
System.out.println("I am destroyed !");
}
}
public static void main(String arg[]) {
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
// out instance is no more used and should be garbage collected !!!
// However this will not happen as inner instance is still alive i.e used, not null !
// and outer will be kept in memory until inner is destroyed
outer = null;
//
// inner = null;
//kick out garbage collector
System.gc();
}
Se você remover o comentário em // inner = null;
O programa exibirá " Estou destruído! ", Mas, mantendo esse comentário, não será.
O motivo é que a instância interna branca ainda é referenciada pelo GC não pode coletá-la e, por referenciar (tem um ponteiro para) a instância externa, ela também não é coletada. Ter o suficiente desses objetos em seu projeto e pode ficar sem memória.
Comparado às classes internas estáticas, que não mantêm um ponto para a instância da classe interna porque ela não é relacionada à instância, mas relacionada à classe. O programa acima pode imprimir " Estou destruído! " Se você tornar a classe Inner estática e instanciada comOuter.Inner i = new Outer.Inner();
Classe aninhada é um termo muito geral: toda classe que não é de nível superior é uma classe aninhada. Uma classe interna é uma classe aninhada não estática. Joseph Darcy escreveu uma explicação muito agradável sobre as classes Nested, Inner, Member e de nível superior .
Ummm ... uma classe interna É uma classe aninhada ... você quer dizer classe anônima e classe interna?
Edit: Se você realmente quis dizer inner vs anonymous ... uma classe interna é apenas uma classe definida dentro de uma classe como:
public class A {
public class B {
}
}
Enquanto uma classe anônima é uma extensão de uma classe definida anonimamente, portanto, nenhuma classe "real é definida, como em:
public class A {
}
A anon = new A() { /* you could change behavior of A here */ };
Edição adicional:
A Wikipedia afirma que há uma diferença em Java, mas eu trabalho com Java há 8 anos, e é a primeira vez que ouvi essa distinção ... sem mencionar que não há referências para fazer backup da declaração ... bottom linha, uma classe interna é uma classe definida dentro de uma classe (estática ou não) e aninhado é apenas outro termo para significar a mesma coisa.
Há uma diferença sutil entre classe aninhada estática e não estática ... basicamente, classes internas não estáticas têm acesso implícito a campos de instância e métodos da classe envolvente (portanto, não podem ser construídos em um contexto estático, será um compilador erro). Classes aninhadas estáticas, por outro lado, não têm acesso implícito aos campos e métodos da instância e podem ser construídas em um contexto estático.
Alvo de aluno que é iniciante em Java e / ou classes aninhadas
As classes aninhadas podem ser:
1. Classes aninhadas estáticas.
2. Classes aninhadas não estáticas. (também conhecidas como classes internas ) => Lembre-se disso
1. Classes internas
Exemplo:
class OuterClass {
/* some code here...*/
class InnerClass { }
/* some code here...*/
}
Classes internas são subconjuntos de classes aninhadas:
Especialidade da classe interna:
2. Classes aninhadas estáticas:
Exemplo:
class EnclosingClass {
static class Nested {
void someMethod() { System.out.println("hello SO"); }
}
}
Caso 1: Instanciando uma classe aninhada estática de uma classe não envolvente
class NonEnclosingClass {
public static void main(String[] args) {
/*instantiate the Nested class that is a static
member of the EnclosingClass class:
*/
EnclosingClass.Nested n = new EnclosingClass.Nested();
n.someMethod(); //prints out "hello"
}
}
Caso 2: Instanciando uma classe aninhada estática de uma classe envolvente
class EnclosingClass {
static class Nested {
void anotherMethod() { System.out.println("hi again"); }
}
public static void main(String[] args) {
//access enclosed class:
Nested n = new Nested();
n.anotherMethod(); //prints out "hi again"
}
}
Especialidade das classes estáticas:
Conclusão:
Pergunta: Qual é a principal diferença entre uma classe interna e uma classe aninhada estática em Java?
Resposta: basta passar por detalhes de cada classe mencionada acima.
Classe interna e classe estática aninhada em Java são classes declaradas dentro de outra classe, conhecida como classe de nível superior em Java. Na terminologia Java, se você declarar uma classe aninhada estática, ela chamará classe estática aninhada em Java, enquanto a classe aninhada não estática é simplesmente chamada de Classe Interna.
O que é classe interna em Java?
Qualquer classe que não seja de nível superior ou declarada dentro de outra classe é conhecida como classe aninhada e fora dessas classes aninhadas, a classe declarada não estática é conhecida como classe Inner em Java. existem três tipos de classe interna em Java:
1) Classe interna local - é declarada dentro de um bloco ou método de código.
2) Classe interna anônima - é uma classe que não tem nome para referência e inicializada no mesmo local em que é criada.
3) Classe interna do membro - é declarada como membro não estático da classe externa.
public class InnerClassTest {
public static void main(String args[]) {
//creating local inner class inside method i.e. main()
class Local {
public void name() {
System.out.println("Example of Local class in Java");
}
}
//creating instance of local inner class
Local local = new Local();
local.name(); //calling method from local inner class
//Creating anonymous inner class in Java for implementing thread
Thread anonymous = new Thread(){
@Override
public void run(){
System.out.println("Anonymous class example in java");
}
};
anonymous.start();
//example of creating instance of inner class
InnerClassTest test = new InnerClassTest();
InnerClassTest.Inner inner = test.new Inner();
inner.name(); //calling method of inner class
}
//Creating Inner class in Java
private class Inner{
public void name(){
System.out.println("Inner class example in java");
}
}
}
O que é classe estática aninhada em Java?
Classe estática aninhada é outra classe que é declarada dentro de uma classe como membro e tornada estática. A classe estática aninhada também é declarada como membro da classe externa e pode ser tornada privada, pública ou protegida como qualquer outro membro. Um dos principais benefícios da classe estática aninhada sobre a classe interna é que a instância da classe estática aninhada não está anexada a nenhuma instância anexa da classe Exterior. Você também não precisa de nenhuma instância da classe Outer para criar uma instância da classe estática aninhada em Java .
1) Pode acessar membros de dados estáticos da classe externa, incluindo privado.
2) A classe aninhada estática não pode acessar o membro ou método não estático (instância) de dados .
public class NestedStaticExample {
public static void main(String args[]){
StaticNested nested = new StaticNested();
nested.name();
}
//static nested class in java
private static class StaticNested{
public void name(){
System.out.println("static nested class example in java");
}
}
}
Ref: Classe interna e classe estática aninhada em Java com exemplo
Eu acho que as pessoas aqui devem notar para o Poster que: Static Nest Class é apenas a primeira classe interna. Por exemplo:
public static class A {} //ERROR
public class A {
public class B {
public static class C {} //ERROR
}
}
public class A {
public static class B {} //COMPILE !!!
}
Resumindo, a classe estática não depende de qual classe ela contém. Então, eles não podem na classe normal. (porque a classe normal precisa de uma instância).
Quando declaramos uma classe de membro estático dentro de uma classe, ela é conhecida como classe aninhada de nível superior ou classe aninhada estática. Pode ser demonstrado como abaixo:
class Test{
private static int x = 1;
static class A{
private static int y = 2;
public static int getZ(){
return B.z+x;
}
}
static class B{
private static int z = 3;
public static int getY(){
return A.y;
}
}
}
class TestDemo{
public static void main(String[] args){
Test t = new Test();
System.out.println(Test.A.getZ());
System.out.println(Test.B.getY());
}
}
Quando declaramos uma classe de membro não estático dentro de uma classe, ela é conhecida como classe interna. A classe interna pode ser demonstrada como abaixo:
class Test{
private int i = 10;
class A{
private int i =20;
void display(){
int i = 30;
System.out.println(i);
System.out.println(this.i);
System.out.println(Test.this.i);
}
}
}
A seguir, é apresentado um exemplo de static nested class
e inner class
:
OuterClass.java
public class OuterClass {
private String someVariable = "Non Static";
private static String anotherStaticVariable = "Static";
OuterClass(){
}
//Nested classes are static
static class StaticNestedClass{
private static String privateStaticNestedClassVariable = "Private Static Nested Class Variable";
//can access private variables declared in the outer class
public static void getPrivateVariableofOuterClass(){
System.out.println(anotherStaticVariable);
}
}
//non static
class InnerClass{
//can access private variables of outer class
public String getPrivateNonStaticVariableOfOuterClass(){
return someVariable;
}
}
public static void accessStaticClass(){
//can access any variable declared inside the Static Nested Class
//even if it private
String var = OuterClass.StaticNestedClass.privateStaticNestedClassVariable;
System.out.println(var);
}
}
OuterClassTest:
public class OuterClassTest {
public static void main(String[] args) {
//access the Static Nested Class
OuterClass.StaticNestedClass.getPrivateVariableofOuterClass();
//test the private variable declared inside the static nested class
OuterClass.accessStaticClass();
/*
* Inner Class Test
* */
//Declaration
//first instantiate the outer class
OuterClass outerClass = new OuterClass();
//then instantiate the inner class
OuterClass.InnerClass innerClassExample = outerClass. new InnerClass();
//test the non static private variable
System.out.println(innerClassExample.getPrivateNonStaticVariableOfOuterClass());
}
}
Eu acho que nenhuma das respostas acima fornece o exemplo real para você a diferença entre uma classe aninhada e uma classe aninhada estática no termo do design do aplicativo. E a principal diferença entre classe aninhada estática e classe interna é a capacidade de acessar o campo de instância da classe externa.
Vamos dar uma olhada nos dois exemplos a seguir.
Classe de ninho estático: Um bom exemplo do uso de classes aninhadas estáticas é o padrão do construtor ( https://dzone.com/articles/design-patterns-the-builder-pattern ).
Para BankAccount, usamos uma classe aninhada estática, principalmente porque
A instância da classe estática do ninho pode ser criada antes da classe externa.
No padrão do construtor, o construtor é uma classe auxiliar usada para criar a BankAccount.
public class BankAccount {
private long accountNumber;
private String owner;
...
public static class Builder {
private long accountNumber;
private String owner;
...
static public Builder(long accountNumber) {
this.accountNumber = accountNumber;
}
public Builder withOwner(String owner){
this.owner = owner;
return this;
}
...
public BankAccount build(){
BankAccount account = new BankAccount();
account.accountNumber = this.accountNumber;
account.owner = this.owner;
...
return account;
}
}
}
Classe interna: um uso comum de classes internas é definir um manipulador de eventos. https://docs.oracle.com/javase/tutorial/uiswing/events/generalrules.html
Para MyClass, usamos a classe interna, principalmente porque:
Classe interna MyAdapter precisa acessar o membro da classe externa.
No exemplo, o MyAdapter está associado apenas ao MyClass. Nenhuma outra classe está relacionada ao MyAdapter. portanto, é melhor organizá-los juntos sem usar uma convenção de nome
public class MyClass extends Applet {
...
someObject.addMouseListener(new MyAdapter());
...
class MyAdapter extends MouseAdapter {
public void mouseClicked(MouseEvent e) {
...// Event listener implementation goes here...
...// change some outer class instance property depend on the event
}
}
}
Antes de tudo, não existe uma classe chamada classe estática. O uso do modificador estático com a classe interna (chamada de classe aninhada) diz que ele é um membro estático da classe externa, o que significa que podemos acessá-lo como com outros membros estáticos e sem ter nenhum instância da classe externa. (Qual é o benefício da estática originalmente.)
A diferença entre o uso da classe Nested e da classe Inner regular é:
OuterClass.InnerClass inner = new OuterClass().new InnerClass();
Primeiro, podemos instanciar Outerclass e depois podemos acessar Inner.
Mas se a classe é aninhada, a sintaxe é:
OuterClass.InnerClass inner = new OuterClass.InnerClass();
Que usa a sintaxe estática como implementação normal da palavra-chave estática.
A linguagem de programação Java permite definir uma classe dentro de outra classe. Essa classe é chamada classe aninhada e é ilustrada aqui:
class OuterClass {
...
class NestedClass {
...
}
}
Classes aninhadas são divididas em duas categorias: estática e não estática. Classes aninhadas declaradas estáticas são chamadas de classes aninhadas estáticas. Classes aninhadas não estáticas são chamadas de classes internas. Uma coisa que devemos ter em mente é que as classes aninhadas não estáticas (classes internas) têm acesso a outros membros da classe envolvente, mesmo que sejam declaradas privadas. As classes aninhadas estáticas só têm acesso a outros membros da classe envolvente se essas forem estáticas. Ele não pode acessar membros não estáticos da classe externa. Assim como os métodos e variáveis de classe, uma classe aninhada estática é associada à sua classe externa. Por exemplo, para criar um objeto para a classe aninhada estática, use esta sintaxe:
OuterClass.StaticNestedClass nestedObject =
new OuterClass.StaticNestedClass();
Para instanciar uma classe interna, você deve primeiro instanciar a classe externa. Em seguida, crie o objeto interno dentro do objeto externo com esta sintaxe:
OuterClass.InnerClass innerObject = new OuterClass().new InnerClass();
Por que usamos classes aninhadas
A diferença é que uma declaração de classe aninhada que também é estática pode ser instanciada fora da classe envolvente.
Quando você tem uma declaração de classe aninhada que não é estática, também conhecida como classe interna , o Java não permite instancia-la, exceto por meio da classe envolvente. O objeto criado a partir da classe interna é vinculado ao objeto criado a partir da classe externa, para que a classe interna possa fazer referência aos campos da externa.
Mas se for estático, o link não existe, os campos externos não podem ser acessados (exceto por uma referência comum como qualquer outro objeto) e, portanto, você pode instanciar a classe aninhada sozinha.
É bem simples, comparando classes locais estáticas e classes internas não estáticas
Diferenças:
Classe local estática:
pode acessar apenas membros estáticos da classe externa.
Não pode ter inicializadores estáticos
Não pode ser acessado diretamente de fora da função onde está declarado
Eu ilustrei vários possíveis cenários corretos e de erros que podem ocorrer no código java.
class Outter1 {
String OutStr;
Outter1(String str) {
OutStr = str;
}
public void NonStaticMethod(String st) {
String temp1 = "ashish";
final String tempFinal1 = "ashish";
// below static attribute not permitted
// static String tempStatic1 = "static";
// below static with final attribute not permitted
// static final String tempStatic1 = "ashish";
// synchronized keyword is not permitted below
class localInnerNonStatic1 {
synchronized public void innerMethod(String str11) {
str11 = temp1 +" sharma";
System.out.println("innerMethod ===> "+str11);
}
/*
// static method with final not permitted
public static void innerStaticMethod(String str11) {
str11 = temp1 +" india";
System.out.println("innerMethod ===> "+str11);
}*/
}
// static class not permitted below
// static class localInnerStatic1 { }
}
public static void StaticMethod(String st) {
String temp1 = "ashish";
final String tempFinal1 = "ashish";
// static attribute not permitted below
//static String tempStatic1 = "static";
// static with final attribute not permitted below
// static final String tempStatic1 = "ashish";
class localInnerNonStatic1 {
public void innerMethod(String str11) {
str11 = temp1 +" sharma";
System.out.println("innerMethod ===> "+str11);
}
/*
// static method with final not permitted
public static void innerStaticMethod(String str11) {
str11 = temp1 +" india";
System.out.println("innerMethod ===> "+str11);
}*/
}
// static class not permitted below
// static class localInnerStatic1 { }
}
// synchronized keyword is not permitted
static class inner1 {
static String temp1 = "ashish";
String tempNonStatic = "ashish";
// class localInner1 {
public void innerMethod(String str11) {
str11 = temp1 +" sharma";
str11 = str11+ tempNonStatic +" sharma";
System.out.println("innerMethod ===> "+str11);
}
public static void innerStaticMethod(String str11) {
// error in below step
str11 = temp1 +" india";
//str11 = str11+ tempNonStatic +" sharma";
System.out.println("innerMethod ===> "+str11);
}
//}
}
//synchronized keyword is not permitted below
class innerNonStatic1 {
//This is important we have to keep final with static modifier in non
// static innerclass below
static final String temp1 = "ashish";
String tempNonStatic = "ashish";
// class localInner1 {
synchronized public void innerMethod(String str11) {
tempNonStatic = tempNonStatic +" ...";
str11 = temp1 +" sharma";
str11 = str11+ tempNonStatic +" sharma";
System.out.println("innerMethod ===> "+str11);
}
/*
// error in below step
public static void innerStaticMethod(String str11) {
// error in below step
// str11 = tempNonStatic +" india";
str11 = temp1 +" india";
System.out.println("innerMethod ===> "+str11);
}*/
//}
}
}
item 22 : Favor static member classes over non static