Classes aninhadas em Java

Classes aninhadas em Java

1. Introdução

Este tutorial é uma introdução rápida e direta às classes aninhadas na linguagem Java.

Simplificando, Java nos permite definir classes dentro de outras classes. Nested classes enable us to logically group classes that are only used in one place, write more readable and maintainable code and increase encapsulation.

Antes de começar, vamos dar uma olhada nos vários tipos de classes aninhadas disponíveis na linguagem:

  • Classes aninhadas estáticas

  • Classes aninhadas não estáticas

  • Classes locais

  • Classes anônimas

Nas próximas seções, discutiremos cada um deles em detalhes.

2. Classes aninhadas estáticas

Aqui estão alguns pontos a serem lembrados sobre as classes aninhadas estáticas:

  • Assim como os membros estáticos, eles pertencem à classe envolvente e não a uma instância da classe

  • Eles podem ter todos os tipos de modificadores de acesso em suas declarações

  • Eles só têm acesso a membros estáticos na classe envolvente

  • Eles podem definir membros estáticos e não estáticos

Vamos ver como podemos declarar uma classe aninhada estática:

public class Enclosing {

    private static int x = 1;

    public static class StaticNested {

        private void run() {
            // method implementation
        }
    }

    @Test
    public void test() {
        Enclosing.StaticNested nested = new Enclosing.StaticNested();
        nested.run();
    }
}

3. Classes aninhadas não estáticas

A seguir, apresentamos alguns pontos rápidos a serem lembrados sobre classes aninhadas não estáticas:

  • Eles também são chamados de classes internas

  • Eles podem ter todos os tipos de modificadores de acesso em suas declarações

  • Assim como variáveis ​​e métodos de instância, classes internas são associadas a uma instância da classe envolvente

  • Eles têm acesso a todos os membros da classe envolvente, independentemente de serem estáticos ou não estáticos

  • Eles só podem definir membros não estáticos

Veja como podemos declarar uma classe interna:

public class Outer {

    public class Inner {
        // ...
    }
}

Se declararmos uma classe aninhada com um modificadorstatic, então é um membro estático. Caso contrário, é uma classe interna. Mesmo que sintaticamente a diferença seja apenas uma única palavra-chave (ou seja,static), semanticamente há uma grande diferença entre esses tipos de classes aninhadas. As instâncias da classe interna são vinculadas às da classe envolvente e, portanto, elas têm acesso aos seus membros. Devemos estar cientes desse problema ao escolher se uma classe aninhada deve ser interna.

Para instanciar uma classe interna, devemos primeiro instanciar sua classe envolvente.

Vamos ver como podemos fazer isso:

Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();

Nas próximas subseções, vamos mostrar alguns tipos especiais de classes internas.

3.1. Aulas locais

Classes locais são um tipo especial de classes internas - nas quaisthe class is defined inside a method ou bloco de escopo.

Vejamos alguns pontos a serem lembrados sobre esse tipo de aula:

  • Eles não podem ter modificadores de acesso em suas declarações

  • Eles têm acesso a membros estáticos e não estáticos no contexto anexo

  • Eles só podem definir membros da instância

Aqui está um exemplo rápido:

public class NewEnclosing {

    void run() {
        class Local {

            void run() {
                // method implementation
            }
        }
        Local local = new Local();
        local.run();
    }

    @Test
    public void test() {
        NewEnclosing newEnclosing = new NewEnclosing();
        newEnclosing.run();
    }
}

3.2. Classes anônimas

Classes anônimas podem ser usadas para definir uma implementação de uma interface ou uma classe abstrata sem precisar criar uma implementação reutilizável.

Vamos listar alguns pontos a serem lembrados sobre as classes anônimas:

  • Eles não podem ter modificadores de acesso em suas declarações

  • Eles têm acesso a membros estáticos e não estáticos no contexto anexo

  • Eles só podem definir membros da instância

  • Eles são o único tipo de classes aninhadas que não podem definir construtores ou estender / implementar outras classes ou interfaces

Para definir uma classe anônima, vamos primeiro definir uma classe abstrata simples:

abstract class SimpleAbstractClass {
    abstract void run();
}

Agora vamos ver como podemos definir uma classe anônima:

public class AnonymousInnerTest {

    @Test
    public void whenRunAnonymousClass_thenCorrect() {
        SimpleAbstractClass simpleAbstractClass = new SimpleAbstractClass() {
            void run() {
                // method implementation
            }
        };
        simpleAbstractClass.run();
    }
}

Para mais detalhes, podemos achar útil nosso tutorial emAnonymous Classes in Java.

4. Sombreamento

The declaration of the members of an inner class shadow those of the enclosing class se eles tiverem o mesmo nome.

Nesse caso, a palavra-chavethis se refere às instâncias da classe aninhada e os membros da classe externa podem ser referenciados usando o nome da classe externa.

Vamos ver um exemplo rápido:

public class NewOuter {

    int a = 1;
    static int b = 2;

    public class InnerClass {
        int a = 3;
        static final int b = 4;

        public void run() {
            System.out.println("a = " + a);
            System.out.println("b = " + b);
            System.out.println("NewOuterTest.this.a = " + NewOuter.this.a);
            System.out.println("NewOuterTest.b = " + NewOuter.b);
            System.out.println("NewOuterTest.this.b = " + NewOuter.this.b);
        }
    }

    @Test
    public void test() {
        NewOuter outer = new NewOuter();
        NewOuter.InnerClass inner = outer.new InnerClass();
        inner.run();

    }
}

5. Serialização

Para evitarjava.io.NotSerializableException ao tentar serializar uma classe aninhada, devemos:

  • Declare a classe aninhada comostatic

  • Faça com que a classe aninhada e a classe envolvente implementemSerializable

6. Conclusão

Neste artigo, vimos o que são classes aninhadas e seus diferentes tipos. Também examinamos como a visibilidade do campo e os modificadores de acesso diferem entre esses tipos.

Como sempre, a implementação completa deste tutorial pode ser encontradaover on GitHub.