Pergunta

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?

Foi útil?

Solução

De Tutorial Java:

As classes aninhadas são divididas em duas categorias:estática e não estática.Classes aninhadas declaradas estáticas são simplesmente chamadas 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 de InnerClass pode existir apenas dentro de uma instância de OuterClass e tem acesso direto aos métodos e campos de sua instância envolvente.

Para instanciar uma classe interna, primeiro você deve instanciar a classe externa.Em seguida, crie o objeto interno dentro do objeto externo com esta sintaxe:

OuterClass.InnerClass innerObject = outerObject.new InnerClass();

ver: Tutorial Java - Classes aninhadas

Para completar, observe que também existe algo como um classe interna sem uma instância envolvente:

class A {
  int t() { return 1; }
  static A a =  new A() { int t() { return 2; } };
}

Aqui, new A() { ... } é um classe interna definida em um contexto estático e não possui uma instância envolvente.

Outras dicas

O Tutorial Java diz:

Terminologia:As classes aninhadas são divididas em duas categorias:estático e não estático.Classes aninhadas declaradas estáticas são simplesmente chamadas 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 ​​indistintamente pela maioria dos programadores, mas usarei o termo correto “classe aninhada”, que abrange tanto interno quanto estático.

As aulas podem ser aninhadas ao infinito, 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 classes é raro, pois geralmente é um design ruim.

Existem três motivos pelos quais você pode criar uma classe aninhada:

  • organização:às vezes parece mais sensato classificar uma classe no namespace de outra classe, especialmente quando ela não será usada em nenhum outro contexto
  • acesso:classes aninhadas têm acesso especial às variáveis/campos de suas classes que as contêm (precisamente quais variáveis/campos dependem do tipo de classe aninhada, seja interna ou estática).
  • conveniência:ter que criar um novo arquivo para cada novo tipo é incômodo, novamente, especialmente quando o tipo será usado apenas em um contexto

quatro tipos de classe aninhada em Java.Resumidamente, são eles:

  • classe estática:declarado como membro estático de outra classe
  • classe interna:declarado como membro de instância de outra classe
  • classe interna local:declarado dentro de um método de instância de outra classe
  • classe interna anônima:como uma classe interna local, mas escrita como uma expressão que retorna um objeto único

Deixe-me explicar com mais detalhes.


Classes estáticas

As classes estáticas são as mais fáceis de entender porque não têm nada a ver com instâncias da classe que as contém.

Uma classe estática é uma classe declarada como membro estático de outra classe.Assim como outros membros estáticos, essa classe é na verdade apenas um suporte que usa a classe que a contém como seu namespace, por exemplo. a classe Cabra declarado como um membro estático da classe Rinoceronte Na embalagem pizza é conhecido pelo nome pizza.Rinoceronte.Cabra.

package pizza;

public class Rhino {

    ...

    public static class Goat {
        ...
    }
}

Francamente, classes estáticas são um recurso bastante 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 tal classe tenha acesso aos membros estáticos privados da classe que a contém, mas acho que essa é uma justificativa bastante esfarrapada para a existência do recurso de classe estática.


Classes Internas

Uma classe interna é uma classe declarada como membro não estático de outra classe:

package pizza;

public class Rhino {

    public class Goat {
        ...
    }

    private void jerry() {
        Goat g = new Goat();
    }
}

Como acontece com uma classe estática, a classe interna é conhecida como qualificada pelo nome da classe que a contém, pizza.Rinoceronte.Cabra, mas dentro da classe que a contém, ela pode ser conhecida por seu nome simples.No entanto, cada instância de uma classe interna está vinculada a uma instância específica da classe que a contém:acima de Cabra criado em Jerry, está implicitamente ligado ao Rinoceronte instância esse em Jerry.Caso contrário, fazemos o associado Rinoceronte instância explícita quando instanciamos Cabra:

Rhino rhino = new Rhino();
Rhino.Goat goat = rhino.new Goat();

(Observe que você se refere ao tipo interno apenas como Cabra no estranho novo sintaxe:Java infere o tipo que contém a partir do rinoceronte papel.E sim novo rinoceronte.Cabra() teria feito mais sentido para mim também.)

Então, o que isso nos ganha?Bem, a instância da classe interna tem acesso aos membros da instância da classe que a contém.Esses membros de instância envolventes são referidos dentro da classe interna através da apenas seus nomes simples, não através da esse (esse na classe interna refere-se à instância da classe interna, não à instância da classe que contém associada):

public class Rhino {

    private String barry;

    public class Goat {
        public void colin() {
            System.out.println(barry);
        }
    }
}

Na classe interna, você pode consultar esse da classe que contém como Rinoceronte.isto, e você pode usar esse para se referir aos seus membros, por exemplo.Rinoceronte.este.barry.


Aulas internas locais

Uma classe interna local é uma classe declarada no corpo de um método.Tal classe só é conhecida dentro do método que a contém, portanto, ela só pode ser instanciada e ter seus membros acessados ​​dentro do método que a contém.O ganho é que uma instância de classe interna local está vinculada e pode acessar as variáveis ​​locais finais de seu método que a contém.Quando a instância usa um local final de seu método que a contém, a variável retém o valor que mantinha no momento da criação da instância, mesmo que a variável tenha saído do escopo (esta é efetivamente a versão limitada e grosseira dos fechamentos do Java).

Como uma classe interna local não é membro de uma classe ou pacote, ela não é declarada com um nível de acesso.(Fique claro, no entanto, que seus próprios membros têm níveis de acesso como em uma aula normal.)

Se uma classe interna local for declarada em um método de instância, uma instanciação da classe interna será vinculada à instância mantida pelo método que a contém. esse no momento da criação da instância e, portanto, os membros da instância da classe que a contém são acessíveis como em uma classe interna da instância.Uma classe interna local é instanciada simplesmente através da seu nome, por exemplo. classe interna local Gato é instanciado como novo gato(), não é novo this.Cat() como você poderia esperar.


Classes internas anônimas

Uma classe interna anônima é uma maneira sintaticamente conveniente de escrever uma classe interna local.Mais comumente, uma classe interna local é instanciada no máximo apenas uma vez cada vez que seu método que a contém é 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 pensar em um nome para a classe (quanto menos inútil nomes que seu código contém, melhor).Uma classe interna anônima permite ambas as coisas:

new *ParentClassName*(*constructorArgs*) {*members*}

Esta é uma expressão que retorna uma nova instância de uma classe sem nome que estende ParentClassName.Você não pode fornecer seu próprio construtor;em vez disso, é fornecido implicitamente um que simplesmente chama o superconstrutor, portanto, os argumentos fornecidos devem caber no superconstrutor.(Se o pai contiver vários construtores, o “mais simples” será 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 - apenas preste atenção ao que o NetBeans ou o Eclipse lhe dizem.)

Alternativamente, você pode especificar uma interface para implementar:

new *InterfaceName*() {*members*}

Tal declaração cria uma nova instância de uma classe sem nome que estende Object e implementa NomedaInterface.Novamente, você não pode fornecer seu próprio construtor;neste caso, Java fornece implicitamente um construtor sem argumentos e sem fazer nada (portanto, nunca haverá argumentos de construtor neste caso).

Mesmo que você não possa fornecer um construtor a uma classe interna anônima, você ainda pode fazer qualquer configuração que desejar usando um bloco inicializador (um bloco {} colocado fora de qualquer método).

Deixe 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 implemente múltiplas interfaces ou que implemente interfaces enquanto estende alguma classe diferente Objeto ou que especifica seu próprio construtor, você não conseguirá criar uma classe interna local nomeada regular.

Não creio que a verdadeira diferença tenha ficado clara nas respostas acima.

Primeiro para acertar os termos:

  • Uma classe aninhada é uma classe contida em outra classe no nível do código-fonte.
  • É estático se você o declarar com o estático modificador.
  • Uma classe aninhada não estática é chamada de classe interna.(Eu fico com a classe aninhada não estática.)

A resposta de Martin está certa até agora.No entanto, a questão real é:Qual é o propósito de declarar uma classe aninhada como estática ou não?

Você usa classes aninhadas estáticas se você deseja apenas manter suas classes juntas, se elas 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 uma fera diferente.Semelhante às classes internas anônimas, essas classes aninhadas são, na verdade, encerramentos.Isso significa que eles capturam o escopo circundante e a instância envolvente e os tornam acessíveis.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);
    }
}

Neste 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 muito trabalho.Você pode acessar a instância envolvente do Container com a sintaxe Container.this.

Explicações mais radicais a seguir:

Se você observar os bytecodes Java que o compilador gera para uma classe aninhada (não estática), isso 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 envolvente.Você não pode ver esse parâmetro na fonte, mas o compilador o gera implicitamente para uma classe aninhada.

O exemplo de Martinho

OuterClass.InnerClass innerObject = outerObject.new InnerClass();

seria então compilado para uma chamada de algo como (em bytecodes)

new InnerClass(outerObject)

Para completar:

Uma aula anônima é um exemplo perfeito de uma classe aninhada não estática que simplesmente não tem nome associado e não pode ser referenciada posteriormente.

Acho que nenhuma das respostas acima explica a diferença real entre uma classe aninhada e uma classe aninhada estática em termos de design de aplicativo:

Visão geral

Uma classe aninhada pode ser não estático ou estático e em cada caso é uma classe definida dentro de outra classe. Uma classe aninhada deve existir apenas para servir a classe envolvente, se uma classe aninhada for útil por outras classes (não apenas pelas envolventes), deverá ser declarada como uma classe de nível superior.

Diferença

Classe aninhada não estática :está implicitamente associado à instância envolvente da classe que a contém, isso significa que é possível invocar métodos e acessar variáveis ​​​​da instância envolvente.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 envolvente e invocar métodos nela, portanto deve ser usado quando a classe aninhada não requer acesso a uma instância da classe envolvente.Um uso comum da classe aninhada estática é implementar componentes do objeto externo.

Conclusão

Portanto, a principal diferença entre os dois do ponto de vista do design é: classe aninhada não estática pode acessar a instância da classe contêiner, enquanto estática não pode.

Em termos simples, precisamos de classes aninhadas principalmente porque Java não fornece encerramentos.

Classes aninhadas são classes definidas dentro do corpo de outra classe envolvente.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 aulas de alto nível, que só podem ser declaradas public ou pacote privado.

As classes internas, também conhecidas como classes não-stack, 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 é a nossa classe interna que não é estática.A principal diferença entre eles é que você não pode criar um Inner2 instância sem um Outer onde você pode criar um Inner1 objeto de forma independente.

Quando você usaria a classe Inner?

Pense em uma situação em que Class A e Class B são relacionados, Class B precisa acessar Class A membros, e Class B está relacionado apenas com Class A.As 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 Inner estática?

Você definiria uma classe interna estática quando soubesse que ela não tem nenhum relacionamento com a instância da classe/classe superior envolvente.Se sua classe interna não usa métodos ou campos da classe externa, é apenas uma perda de espaço, então torne-a estática.

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 que a contém/classe superior para funcionar.Isso pode ajudá-lo a reduzir o número de objetos que seu aplicativo cria em tempo de execução.

Eu acho que a convenção geralmente seguida é esta:

  • classe estática dentro de uma classe de nível superior é um classe aninhada
  • classe não estática dentro de uma classe de nível superior é um classe interna, que ainda tem mais duas formas:
    • aula local - classes nomeadas declaradas dentro de um bloco como um método ou corpo construtor
    • classe anônima - classes sem nome cujas instâncias são criadas em expressões e instruções

No entanto, poucos outros aponta para lembrar são:

  • Classes de nível superior e classes aninhadas estáticas são semanticamente iguais, exceto que no caso de classe aninhada estática ela pode fazer referência estática a campos/métodos estáticos privados de sua classe externa [pai] e vice-versa.

  • As classes internas têm acesso às variáveis ​​de instância da instância envolvente da classe externa [pai].No entanto, nem todas as classes internas têm instâncias envolventes, por exemplo, classes internas em contextos estáticos, como uma classe anônima usada em um bloco inicializador estático, não têm.

  • A classe anônima, por padrão, estende a classe pai ou implementa a interface pai e não há nenhuma cláusula adicional para estender qualquer outra classe ou implementar mais interfaces.Então,

    • new YourClass(){}; significa class [Anonymous] extends YourClass {}
    • new YourInterface(){}; significa class [Anonymous] implements YourInterface {}

Sinto que a grande questão que permanece em aberto é qual usar e quando?Bem, isso depende principalmente do cenário com o qual você está lidando, mas ler a resposta dada por @jrudolph pode ajudá-lo a tomar alguma decisão.

Aqui estão as principais diferenças e semelhanças entre a classe interna Java e a classe aninhada estática.

Espero que ajude!

Classe interna

  • Pode acessar para a classe externa instância e estática métodos e campos
  • Associado à instância da classe envolvente então, para instanciá-lo, primeiro é necessária uma instância da classe externa (observe novo lugar da palavra-chave):

    Outerclass.InnerClass innerObject = outerObject.new Innerclass();
    
  • Não pode definir qualquer membros estáticos em si

  • Não pode ter Aula ou Interface declaração

Classe aninhada estática

  • Não pode acessar classe externa instância métodos ou campos

  • Não associado a nenhuma instância da classe envolvente Então, para instanciá-lo:

    OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();
    

Semelhanças

  • Ambos Aulas internas pode acessar mesmo campos e métodos privados de classe externa
  • Também o Classe externa Ter acesso à campos e métodos privados de classes internas
  • Ambas as classes podem ter modificador de acesso privado, protegido ou público

Por que usar classes aninhadas?

De acordo com a documentação da Oracle, há vários motivos (documentação completa):

  • É uma forma de agrupar logicamente classes que são utilizadas apenas em um local: Se uma classe for útil apenas para outra classe, então é lógico incorporá-la nessa classe e manter as duas juntas.Aninhar essas "classes auxiliares" torna seu pacote mais simplificado.

  • Aumenta o encapsulamento: Considere duas classes de nível superior, A e B, onde B precisa de acesso a membros de A que de outra forma seriam declarados privados.Ao ocultar a classe B dentro da classe A, os membros de A podem ser declarados privados e B pode acessá-los.Além disso, o próprio B pode ser escondido do mundo exterior.

  • Isso pode levar a um código mais legível e de fácil manutenção: Aninhar pequenas classes em classes de nível superior coloca o código mais próximo de onde ele é usado.

Classe aninhada:aula dentro da aula

Tipos:

  1. Classe aninhada estática
  2. Classe aninhada não estática [classe interna]

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 de classe interna, devemos primeiro criar um objeto de classe externa.

outerclass outerobject=new outerobject();
outerclass.innerclass innerobjcet=outerobject.new innerclass(); 

Classe aninhada estática

Na classe aninhada estática, o objeto da classe interna não precisa do objeto da classe externa, pois a palavra "estático" indica que não há necessidade de criar 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, as instâncias da classe interna também deixam de existir.

A classe aninhada estática não possui uma instância concreta.Ele só é carregado 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 ocupam memória heap/pilha, pois não é necessário criar instância dessa classe.Portanto, a regra geral é tentar definir uma classe aninhada estática, com escopo tão limitado quanto possível (private >= class >= protected >= public), e então convertê-la em classe interna (removendo o identificador "estático") e afrouxar o escopo, se for realmente necessário.

Há uma sutileza no uso de classes estáticas aninhadas que pode ser útil em determinadas situações.

Enquanto os atributos estáticos são instantados antes que a classe seja instanciada por meio de seu construtor, atributos estáticos dentro das aulas estáticas aninhadas não parecem ser instantadas até que o construtor da classe seja invocado, ou pelo menos não até que os atributos sejam referenciados pela primeira vez, mesmo se mesmo 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 'nested' e 'innerItem' sejam declarados como 'static final'.O cenário de aninhado.Inneritem não ocorre até depois que a aula é instanciada (ou pelo menos não até que o item estático aninhado seja referenciado pela primeira vez), como você pode ver por si mesmo comentando e descommentando as linhas que me refiro, acima.O mesmo não se aplica a 'Exteritem'.

Pelo menos é isso que estou vendo no Java 6.0.

No caso de criação de instância, a instância da classe interna não estática é criada com a referência do objeto da classe externa em que é definido.Isso significa que ele tem uma instância de inclinação.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 incluiu uma instância.

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 classes aninhadas estáticas e classes internas.No entanto, considere o seguinte problema ao usar classes aninhadas versus classes internas.Como mencionado em algumas respostas, as classes internas não podem ser instanciadas sem a instância de sua classe envolvente, o que significa que elas SEGURAR a ponteiro para a instância de sua classe anexa, o que pode levar ao estouro de memória ou à exceção de estouro de pilha devido ao fato de o GC não ser capaz de coletar o lixo das 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 vai colocar "Estou destruído!", mas mantendo isso comentado não vai.
A razão é que a instância interna branca ainda é referenciada, o GC não pode coletá-la e porque faz referência (tem um ponteiro para) a instância externa, ela também não é coletada.Ter um número suficiente desses objetos em seu projeto pode ficar sem memória.
Em comparação com classes internas estáticas que não possuem um ponto para a instância da classe interna porque não são relacionadas à instância, mas sim à classe.O programa acima pode imprimir "Estou destruído!"se você tornar a classe Inner estática e instanciada com Outer.Inner i = new Outer.Inner();

Os termos são usados ​​indistintamente.Se você quiser ser realmente pedante sobre isso, então você poderia defina "classe aninhada" para se referir a uma classe interna estática, que não possui instância envolvente.No código, você pode ter algo assim:

public class Outer {
    public class Inner {}

    public static class Nested {}
}

Essa não é realmente uma definição amplamente aceita.

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 boa sobre Classes aninhadas, internas, membros e de nível superior.

Hum...uma classe interna É uma classe aninhada ...você quer dizer classe anônima e classe interna?

Editar:Se você realmente quis dizer interno versus anônimo...uma classe interna é apenas uma classe definida dentro de uma classe como:

public class A {
    public class B {
    }
}

Considerando que uma classe anônima é uma extensão de uma classe definida anonimamente, nenhuma "classe" real é definida, como em:

public class A {
}

A anon = new A() { /* you could change behavior of A here */ };

Edição adicional:

Wikipédia afirma que há uma diferença em Java, mas trabalho com Java há 8 anos, e é a primeira vez que ouço tal distinção...sem mencionar que não há referências para respaldar a afirmação...Resumindo, uma classe interna é uma classe definida dentro de uma classe (estática ou não), e aninhado é apenas outro termo que significa a mesma coisa.

Há uma diferença sutil entre classes aninhadas estáticas e não estáticas...basicamente classes internas não estáticas têm acesso implícito a campos de instância e métodos da classe envolvente (portanto, elas não podem ser construídas em um contexto estático, será um erro do compilador).As 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.

Almejando alunos novatos 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 conhecido como Aulas internas) =>Por favor, lembre-se disso


1. Aulas internas
Exemplo:

class OuterClass  {
/*  some code here...*/
     class InnerClass  {  }
/*  some code here...*/
}


Classes internas são subconjuntos de classes aninhadas:

  • classe interna é um tipo específico de classe aninhada
  • classes internas são subconjuntos de classes aninhadas
  • Você pode dizer que um a classe interna também é uma classe aninhada, mas você pode NÃO digamos que uma classe aninhada também é uma classe interna.

Especialidade da classe interna:

  • instância de uma classe interna tem acesso a todos dos membros da classe externa, mesmo aqueles que estão marcados como “privados”


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 de classes estáticas:

  • A classe interna estática só teria acesso aos membros estáticos da classe externa e não teria acesso aos membros não estáticos.

Conclusão:
Pergunta: Qual é a principal diferença entre uma classe interna e uma classe aninhada estática em Java?
Responder: basta analisar os detalhes de cada classe mencionada acima.

Classe interna e classe estática aninhada em Java, ambas 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 será chamada de classe estática aninhada em Java, enquanto as classes aninhadas não estáticas serão simplesmente chamadas 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, dentre essas classes aninhadas, as classes declaradas não estáticas são conhecidas como classe interna em Java.existem três tipos de classe Inner 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 possui nome para referenciar e inicializada no mesmo local onde foi criada.
3) Membro da classe interna - é declarado 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 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 é anexada a nenhuma instância envolvente da classe externa. 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) Ele pode acessar membros de dados estáticos de classe externa, incluindo privada.
2) Classe aninhada estática não pode acessar membro de dados não estático (instância) ou método.

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");
        }
    }
}

Referência: Classe interna e classe estática aninhada em Java com exemplo

Acho que as pessoas aqui deveriam notar no 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 !!!

 }

Então, resumindo, a classe estática não depende de qual classe ela contém.Então, eles não podem na aula 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 conforme 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 membro não estática dentro de uma classe, ela é conhecida como classe interna.A classe interna pode ser demonstrada conforme 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 está 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);
     }

}

Teste OuterClass:

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()); 

    }

}

Acho que nenhuma das respostas acima fornece um exemplo real da diferença entre uma classe aninhada e uma classe aninhada estática em termos de design de aplicativo.E a principal diferença entre a classe aninhada estática e a classe interna é a capacidade de acessar o campo de instância da classe externa.

Vejamos os dois exemplos a seguir.

Classe de ninho estático:Um bom exemplo de uso de classes aninhadas estáticas é o padrão de construtor (https://dzone.com/articles/design-patterns-the-builder-pattern).

Para BankAccount usamos uma classe aninhada estática, principalmente porque

  1. A instância da classe de ninho estático pode ser criada antes da classe externa.

  2. No padrão construtor, o construtor é uma classe auxiliar usada para criar BankAccount.

  3. BankAccount.Builder está associado apenas a BankAccount.Nenhuma outra classe está relacionada ao BankAccount.Builder.então é melhor organizá-los juntos sem usar convenção de nomes.
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:

  1. A classe interna MyAdapter precisa acessar o membro da classe externa.

  2. No exemplo, MyAdapter está associado apenas a MyClass.Nenhuma outra classe está relacionada ao MyAdapter.então é melhor organizá-los juntos sem usar uma convenção de nomes

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
        }
    }
}

Em primeiro lugar, não existe tal classe chamada classe estática. O modificador estático usado com a classe interna (chamada de classe aninhada) diz que é um membro estático da classe externa, o que significa que podemos acessá-lo como acontece com outros membros estáticos e sem ter qualquer instância da classe externa.(Que é originalmente o benefício da estática.)

A diferença entre usar a classe Nested e a classe Inner regular é:

OuterClass.InnerClass inner = new OuterClass().new InnerClass();

Primeiro podemos instanciar o Outerclass e depois acessar o Inner.

Mas se a classe estiver aninhada, a sintaxe será:

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 de classe aninhada e é ilustrada aqui:

class OuterClass {
...
class NestedClass {
    ...
    }
}

As 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.Classes aninhadas estáticas só terão acesso a outros membros da classe envolvente se estes forem estáticos.Não pode acessar membros não estáticos da classe externa.Tal como acontece com os métodos e variáveis ​​de classe, uma classe aninhada estática está 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, primeiro você deve 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

  1. É uma forma de agrupar logicamente classes que são utilizadas apenas em um local.
  2. Aumenta o encapsulamento.
  3. Isso pode levar a um código mais legível e de fácil manutenção.

Fonte: Os tutoriais Java™ - 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ático, também conhecido como classe interna, o Java não permitirá que você o instancie, exceto por meio da classe anexa.O objeto criado a partir da classe interna está vinculado ao objeto criado a partir da classe externa, para que a classe interna possa fazer referência aos campos da classe externa.

Mas se for estático, então o link não existe, os campos externos não podem ser acessados ​​(exceto através de uma referência comum como qualquer outro objeto) e você pode, portanto, instanciar a classe aninhada por si só.

Ilustrei vários cenários possíveis de correção e erro 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);
                        }*/
                    //}
                }
    }
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top