JavaRush /Blogue Java /Random-PT /Classes, tipos de classes aninhadas com exemplos
Ярослав
Nível 40
Днепр

Classes, tipos de classes aninhadas com exemplos

Publicado no grupo Random-PT
Olá a todos. Neste tópico, quero falar detalhadamente sobre as classes Java e seus tipos para ajudar os iniciantes a entender esse tópico e, talvez, os não novatos a aprender algo novo. Sempre que possível, tudo será mostrado usando exemplos da vida real acompanhados de exemplos de código. Vamos começar. Classes, tipos de classes aninhadas com exemplos - 1E gostaria de observar que o principal é entender os dois primeiros tipos de classes, e local e anônimo são simplesmente subtipos da classe interna.

O que é uma aula?

Uma classe é uma descrição lógica de algo, um modelo com o qual você pode criar instâncias reais daquilo mesmo. Em outras palavras, é simplesmente uma descrição de como deveriam ser as entidades criadas: quais propriedades e métodos elas deveriam ter. Propriedades são características de uma entidade, métodos são ações que ela pode realizar. Um bom exemplo de aula da vida real, que dá uma compreensão do que é uma aula, pode ser considerado desenhos: desenhos são usados ​​​​para descrever estruturas (catapulta, chave de fenda), mas desenho não é um projeto. Assim como os engenheiros usam projetos para criar projetos, a programação usa classes para criar objetos que descrevem propriedades e métodos.
public class Student {
    private String name, group, specialty;

    public Student(String name, String group, String specialty) {
       this.name = name;
       this.group = group;
       this.specialty = specialty;
   }

   // getters/setters
}
Neste exemplo, criamos uma classe Java que descreve a entidade “aluno”: cada aluno possui nome, turma e especialidade. Agora, em outros locais do programa, podemos criar exemplos reais desta classe. Em outras palavras: se a aula Studenté um retrato do que um aluno deveria ser, então a instância criada é o próprio aluno. Um exemplo de criação de um novo aluno: new Student("Ivan", "KI-17-2", "Computer Engineering");O operador newprocura a classe Studente a seguir chama um método especial (construtor) desta classe. O construtor retorna um objeto de classe pronto Student- nosso querido aluno faminto sem bolsa :))

Tipos de classes em Java

Em Java existem 4 tipos de classes dentro de outra classe:
  1. Classes internas aninhadas são classes não estáticas dentro de uma classe externa.

  2. Classes estáticas aninhadas são classes estáticas dentro de uma classe externa.

  3. Classes locais Java são classes dentro de métodos.

  4. Classes Java anônimas são classes criadas dinamicamente.

Falaremos sobre cada um deles separadamente.

Classes não estáticas dentro de uma classe externa

Primeiramente quero que você entenda o que é isso com um exemplo real, pois fica muito mais fácil de entender. Então agora vamos dividir algo realmente grande em componentes menores e desmontar um avião! Contudo, a título de exemplo, bastará mostrar um pouco; não iremos decompô-lo completamente. Para visualizar esse processo, usaremos um diagrama de avião. Classes, tipos de classes aninhadas com exemplos - 2 Primeiro precisamos criar uma classe Airplaneonde possamos adicionar uma pequena descrição: nome da aeronave, código de identificação, voo.
public class Airplane {
    private String name, id, flight;

    public Airplane(String name, String id, String flight) {
        this.name = name;
        this.id = id;
        this.flight = flight;
    }

    // getters/setters
}
Agora queremos adicionar asas. Criar uma turma separada? Talvez seja esta a lógica se tivermos um programa complexo para projetar aviões, e onde precisamos criar um grande número de classes derivadas (classes que possuem a mesma lógica da classe pai, ou seja, a classe da qual herdam, mas então eles estendem a classe pai adicionando lógica ou características mais detalhadas), mas e se tivermos apenas um jogo onde temos um plano? Então será mais racional concluirmos toda a estrutura em um só lugar (em uma aula). É aqui que as classes aninhadas não estáticas entram em ação. Essencialmente, esta é uma descrição mais detalhada de alguns detalhes da nossa classe externa. Neste exemplo, precisamos criar asas para um avião - esquerda e direita. Vamos criar!
public class Airplane {
    private String name, id, flight;
    private Wing leftWing = new Wing("Red", "X3"), rightWing = new Wing("Blue", "X3");

    public Airplane(String name, String id, String flight) {
        this.name = name;
        this.id = id;
        this.flight = flight;
    }

    private class Wing {
        private String color, model;

        private Wing(String color, String model) {
            this.color = color;
            this.model = model;
        }

        // getters/setters
    }

    // getters/setters
}
Então criamos uma classe aninhada não estática Wing(asa) dentro de uma classe Airplane(avião) e adicionamos duas variáveis ​​- asa esquerda e asa direita. E cada asa tem suas próprias propriedades (cor, modelo) que podemos alterar. Dessa forma, você pode equipar as estruturas tanto quanto precisar. E observe: anteriormente no diagrama havia muitas peças para a aeronave e, de fato, podemos dividir todas as peças em classes internas, mas tal processo nem sempre é aconselhável. Tais momentos precisam ser rastreados dependendo da tarefa. Talvez você não precise de asas para resolver o problema. Então não há necessidade de fazê-los. É como cortar pernas, braços, tronco e cabeça de uma pessoa - é possível, mas por que se essa classe é usada apenas para armazenar dados sobre pessoas? Recursos de classes Java aninhadas não estáticas:
  1. Eles existem apenas em objetos, então para criá-los você precisa de um objeto. Ou seja: projetamos nossa asa para fazer parte de um avião, então para criar uma asa precisamos de um avião, senão não precisamos dele.
  2. Não pode haver variáveis ​​estáticas dentro de uma classe Java. Se você precisar de algumas constantes ou qualquer outra coisa estática, será necessário movê-las para uma classe externa. Isso se deve ao acoplamento próximo da classe aninhada não estática com a classe externa.
  3. A classe tem acesso total a todos os campos privados da classe externa. Esse recurso funciona de duas maneiras.
  4. Você pode obter uma referência a uma instância de uma classe externa. Exemplo: Avião.este é um link para um avião, este é um link para uma asa.

Classes estáticas dentro de uma classe externa

Este tipo de classe não é diferente de uma classe externa regular, exceto por uma coisa: para criar uma instância de tal classe, você precisa listar todo o caminho da classe externa até a classe desejada, separado por um ponto. Por exemplo: Building.Plaftorm platform = new Building.Platform(); Classes estáticas são usadas para colocar classes relacionadas lado a lado para que a estrutura lógica seja mais fácil de trabalhar. Por exemplo: podemos criar uma classe externa Building, onde haverá uma lista específica de classes que representarão um edifício específico.
public abstract class Building {
    private String name, address, type;

    Building(String name, String address) {
        this.name = name;
        this.address = address;
    }

    public static class Platform extends Building {
        public Platform(String name, String address) {
            super(name, address);
            setType("Platform");
        }

        // some additional logic
    }

    public static class House extends Building {
        public House(String name, String address) {
            super(name, address);
            setType("House");
        }

        // some additional logic
    }

    public static class Shop extends Building {
        public Shop(String name, String address) {
            super(name, address);
            setType("Shop");
        }

        // some additional logic
    }

    // getters/setters
}
Este exemplo demonstra como as classes estáticas permitem empacotar uma estrutura lógica em um formato mais conveniente. Se não existissem, precisaríamos criar 4 classes completamente diferentes. As vantagens desta abordagem:
  1. O número de aulas diminuiu.
  2. Todas as classes estão dentro de sua classe pai. Somos capazes de rastrear toda a hierarquia sem abrir cada classe separadamente.
  3. Podemos nos referir à classe Building, e o IDE já irá solicitar a lista completa de todas as subclasses desta classe. Isso tornará mais fácil encontrar as aulas de que você precisa e mostrará o quadro completo de forma mais holística.
Um exemplo de criação de uma instância de uma classe estática aninhada:Building.Shop myShop = new Building.Shop(“Food & Fun!”, “Kalyaeva 8/53”); Também gostaria de observar que esta estratégia é usada em classes 2D AWT para descrever formas, como Line2D, Arc2D, Ellipse2D e outras.

Aulas locais

Essas classes são declaradas dentro de outros métodos. Na verdade, eles possuem todas as propriedades de uma classe aninhada não estática, apenas suas instâncias só podem ser criadas em um método, e o método não pode ser estático (para criá-los você precisa de uma instância de uma classe externa, uma referência a um instância do objeto de chamada é passada implicitamente para métodos não estáticos e em um método estático não há método para este link). Mas eles têm características próprias:
  1. As classes locais só podem funcionar com variáveis ​​de método final. O problema é que instâncias de classes locais podem ser armazenadas no heap após a conclusão do método e a variável pode ser apagada. Se a variável for declarada final, o compilador poderá salvar uma cópia da variável para uso posterior pelo objeto. E mais uma coisa: desde as versões 8+ do Java, você pode usar variáveis ​​​​não finais em classes locais, mas apenas com a condição de que elas não sejam alteradas.
  2. As classes locais não podem ser declaradas com modificadores de acesso.
  3. As classes locais têm acesso às variáveis ​​do método.
Classes locais raramente são encontradas, pois dificultam a leitura do código e não apresentam nenhuma vantagem, exceto uma - acesso às variáveis ​​​​do método. Não sei que exemplo de aula local pode ser usado para mostrar seu uso eficaz, então vou apenas mostrar meu exemplo. Digamos que temos uma turma Person(será assumido que se trata de uma pessoa) com propriedades street(rua), house(casa). Gostaríamos de devolver algum objeto para acessar apenas a localização da pessoa. Para isso, criamos a interface AddressContainer, que implica no armazenamento de dados sobre a localização de uma pessoa.
public class Person {
    private String name, street, house;

    public Person(String name, String street, String house) {
        this.name = name;
        this.street = street;
        this.house = house;
    }

    private interface AddressContainer {
        String getStreet();
        String getHouse();
    }

    public AddressContainer getAddressContainer() {
        class PersonAddressContainer implements AddressContainer {
            final String street = Person.this.street, house = Person.this.house;

            @Override
            public String getStreet() {
                return this.street;
            }

            @Override
            public String getHouse() {
                return this.house;
            }
        }

        return new PersonAddressContainer();
    }

    public static void main(String[] args) {
        Person person = new Person("Nikita", "Sholohova", "17");

        AddressContainer address = person.getAddressContainer();

        System.out.println("Address: street - " + address.getStreet() + ", house - " + address.getHouse());
    }

    // getters/setters
}
Como você pode ver, dentro do método criamos uma classe que implementa o armazenamento da localização de uma pessoa, criamos variáveis ​​constantes ali (para que após sair do método as variáveis ​​fossem armazenadas em um objeto) e implementamos um método para obter o endereço e casa. Agora podemos usar este objeto em outros locais do programa para obter a localização de uma pessoa. Entendo que esse exemplo não é o ideal e seria mais correto fazê-lo simplesmente deixando os getters na classe Person, porém, foi mostrado a criação desta classe e sua possível utilização, e aí fica a seu critério.

Aulas anônimas

Nos bastidores, as classes anônimas são apenas classes aninhadas não estáticas regulares. Sua peculiaridade é a facilidade de uso. Você pode escrever sua classe diretamente ao criar uma instância de outra classe.
public class Animal {
    public void meow() {
        System.out.println("Meow!");
    }

    public static void main(String[] args) {
        Animal anonTiger = new Animal() {
            @Override
            public void meow() {
                System.out.println("Raaar!");
            }
        };

        Animal notAnonTiger = new Animal().new Tiger();

        anonTiger.meow(); // будет выведено Raaar!
        notAnonTiger.meow(); // будет выведено Raaar!
    }

    private class Tiger extends Animal {
        @Override
        public void meow() {
            System.out.println("Raaar!");
        }
    }
}
Em essência, simplesmente combinamos duas coisas em um só lugar: criar uma instância de uma classe ( Animal) e criar uma instância de sua classe interna herdeira ( Tiger). Caso contrário, precisaremos criar a classe separadamente e usar construções mais longas para obter o mesmo resultado. A utilização de classes anónimas justifica-se em muitos casos, nomeadamente quando:
  • o corpo da classe é muito curto;
  • apenas uma instância da classe é necessária;
  • a classe é utilizada no local onde foi criada ou imediatamente após;
  • O nome da classe não é importante e não facilita a compreensão do código.
Classes anônimas são frequentemente usadas em GUIs para criar manipuladores de eventos. Por exemplo, para criar um botão e reagir ao seu clique:
JButton b2 = new JButton("Click");
b2.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        System.out.println("Кнопка нажата!");
    }
});
No entanto, após o Java 8 eles começaram a usar expressões lambda, mas ainda muito código foi escrito antes da versão 8 e você pode encontrar (e encontrará durante seu treinamento em JavaRush) tais inscrições.\ Análogo com lambdas:
JButton b2 = new JButton("Click");
b2.addActionListener(e -> System.out.println("Кнопка нажата!"));
Fim do artigo Obrigado a todos pela atenção e espero que tenham aprendido algo novo ou entendido algo que não entendiam antes. Gostaria também de esclarecer que este artigo pertence à categoria “atenção aos detalhes” . Este é meu primeiro trabalho, então espero que tenha sido útil para alguém. Num futuro próximo, quando surgirem novas ideias, tentarei escrever outra coisa, só tenho uma ideia... Boa sorte a todos e sucesso na programação :)
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION