JavaRush /Blogue Java /Random-PT /Classes internas aninhadas ou classe interna em Java

Classes internas aninhadas ou classe interna em Java

Publicado no grupo Random-PT
Olá! Hoje começaremos a examinar um tópico importante - como as classes aninhadas funcionam em Java. Em inglês elas são chamadas de classes aninhadas. Java permite criar algumas classes dentro de outras:
class OuterClass {
    ...
    static class StaticNestedClass {
        ...
    }
    class InnerClass {
        ...
    }
}
São essas classes que são chamadas aninhadas. Eles são divididos em 2 tipos:
  1. Classes aninhadas não estáticas - classes aninhadas não estáticas. Elas também são chamadas de classes internas de outra forma.
  2. Classes aninhadas estáticas - classes aninhadas estáticas.
Por sua vez, as classes internas possuem dois subtipos especiais. Além do fato de que uma classe interna pode ser apenas uma classe interna, ela também pode ser:
  • aula local
  • classe anônima
Um pouco difícil? :) Está tudo bem, aqui está um diagrama para maior clareza. Volte a isso durante a palestra se de repente você se sentir confuso! Classes internas aninhadas - 2Na palestra de hoje falaremos sobre Inner classes - classes internas (também são classes aninhadas não estáticas, classes aninhadas não estáticas). Elas estão especialmente destacadas no diagrama geral para que você não se perca :) Vamos começar com a pergunta óbvia: por que essas classes são chamadas de “internas”? A resposta é bem simples: porque eles são criados dentro de outras classes. Aqui está um exemplo:
public class Bicycle {

   private String model;
   private int weight;

   public Bicycle(String model, int weight) {
       this.model = model;
       this.weight = weight;
   }

   public void start() {
       System.out.println("Go!");
   }

   public class HandleBar {

       public void right() {
           System.out.println("Steering wheel to the right!");
       }

       public void left() {

           System.out.println("Steering wheel to the left!");
       }
   }

   public class Seat {

       public void up() {

           System.out.println("The seat is up!");
       }

       public void down() {

           System.out.println("The seat is down!");
       }
   }
}
Aqui temos uma aula Bicycle- bicicleta. Possui 2 campos e 1 método - start(). Classes internas aninhadas - 3Sua diferença de uma classe normal é que ela possui duas classes, cujo código está escrito dentro Bicycle- são as classes HandleBar(volante) e Seat(assento). Estas são classes completas: como você pode ver, cada uma delas tem seus próprios métodos. Neste ponto, você pode ter uma pergunta: por que colocamos uma classe dentro de outra? Por que torná-los internos? Ok, digamos que precisamos de classes separadas para volante e assento no programa. Mas você não precisa aninhá-los! Você pode fazer aulas regulares. Por exemplo, assim:
public class HandleBar {
   public void right() {
       System.out.println("Steering wheel to the right!");
   }

   public void left() {

       System.out.println("Steering wheel left");
   }
}

public class Seat {

   public void up() {

       System.out.println("The seat is up!");
   }

   public void down() {

       System.out.println("The seat is down!");
   }
}
Muito boa pergunta! É claro que não temos limitações técnicas – podemos fazê-lo desta forma. Trata-se mais de projetar classes corretamente do ponto de vista de um programa específico e do significado desse programa. Classes internas são classes para destacar uma determinada entidade em um programa que está inextricavelmente ligada a outra entidade. Volante, assento, pedais são os componentes de uma bicicleta. Separados da bicicleta, não fazem sentido. Se separarmos todas essas classes de classes públicas, nosso programa poderia ter, por exemplo, o seguinte código:
public class Main {

   public static void main(String[] args) {
       HandleBar handleBar = new HandleBar();
       handleBar.right();
   }
}
Hum... O significado desse código é até difícil de explicar. Temos um guidão de bicicleta estranho (por que é necessário? Não faço ideia, para ser sincero). E esse volante vira para a direita... sozinho, sem bicicleta... por algum motivo. Ao separar a essência do volante da essência da bicicleta, perdemos a lógica do nosso programa. Usando uma classe interna, o código parece completamente diferente:
public class Main {

   public static void main(String[] args) {

       Bicycle peugeot = new Bicycle("Peugeot", 120);
       Bicycle.HandleBar handleBar = peugeot.new HandleBar();
       Bicycle.Seat seat = peugeot.new Seat();

       seat.up();
       peugeot.start();
       handleBar.left();
       handleBar.right();
   }
}
Saída do console:

Сиденье поднято выше!
Поехали!
Руль влево!
Руль вправо!
O que estava acontecendo de repente fez sentido! :) Criamos um objeto bicicleta. Criamos dois de seus “subobjetos” - o volante e o assento. Elevamos o assento mais alto por conveniência - e lá fomos nós: rolamos e dirigimos para onde precisamos ir! :) Os métodos que precisamos são chamados nos objetos necessários. Tudo é simples e conveniente. Neste exemplo, destacar o guidão e o assento melhora o encapsulamento (estamos ocultando dados sobre as partes da bicicleta dentro da classe correspondente) e nos permite criar uma abstração mais detalhada. Agora vamos examinar outra situação. Digamos que queremos criar um programa que modele uma loja de bicicletas e peças. Classes internas aninhadas - 4Nesta situação, nossa solução anterior falhará. Dentro dos limites de uma loja de peças, cada parte individual de uma bicicleta tem um significado, mesmo independente da essência da bicicleta. Por exemplo, precisaremos de métodos como “vender pedais a um comprador”, “comprar um assento novo”, etc. Seria um erro usar classes internas aqui - cada parte individual da bicicleta dentro do nosso novo programa tem seu próprio significado: é separada da essência da bicicleta e não está de forma alguma ligada a ela. É nisso que você deve prestar atenção se estiver se perguntando se precisa usar classes internas ou separar todas as entidades em classes separadas. A programação orientada a objetos é ótima porque facilita a modelagem de entidades do mundo real. Isso é o que você pode usar como guia ao decidir se deseja usar classes internas. Em uma loja real, as peças são separadas das bicicletas – isso é normal. Isso significa que isso estará correto ao projetar um programa. Ok, resolvemos a “filosofia” :) Agora vamos nos familiarizar com os importantes recursos “técnicos” das classes internas. Aqui está o que você definitivamente precisa lembrar e entender:
  1. Um objeto de uma classe interna não pode existir sem um objeto de uma classe “externa”.

    Isso é lógico: por isso fizemos aulas Seatinternas HandleBar, para que volantes e assentos sem dono não aparecessem aqui e ali no nosso programa.

    Este código não será compilado:

    public static void main(String[] args) {
    
       HandleBar handleBar = new HandleBar();
    }

    A seguinte característica importante segue disso:

  2. Um objeto de uma classe interna tem acesso às variáveis ​​da classe “externa”.

    Por exemplo, vamos adicionar Bicycleuma variável à nossa classe int seatPostDiameter- o diâmetro do espigão do selim.

    Então, na classe interna, Seatpodemos criar um método getSeatParam()que nos informará o parâmetro do assento:

    public class Bicycle {
    
       private String model;
       private int weight;
    
       private int seatPostDiameter;
    
       public Bicycle(String model, int weight, int seatPostDiameter) {
           this.model = model;
           this.weight = weight;
           this.seatPostDiameter = seatPostDiameter;
    
       }
    
       public void start() {
           System.out.println("Go!");
       }
    
       public class Seat {
    
           public void up() {
    
               System.out.println("The seat is up!");
           }
    
           public void down() {
    
               System.out.println("The seat is down!");
           }
    
           public void getSeatParam() {
    
               System.out.println("Seat parameter: seatpost diameter = " + Bicycle.this.seatPostDiameter);
           }
       }
    }

    E agora podemos obter esta informação em nosso programa:

    public class Main {
    
       public static void main(String[] args) {
    
           Bicycle bicycle = new Bicycle("Peugeot", 120, 40);
           Bicycle.Seat seat = bicycle.new Seat();
    
           seat.getSeatParam();
       }
    }

    Saída do console:

    
    Параметр сиденья: диаметр подседельного штыря = 40

    Prestar atenção:a nova variável é declarada com o modificador mais estrito - private. E ainda a classe interna tem acesso!

  3. Um objeto de classe interna não pode ser criado em um método estático de uma classe “externa”.

    Isso é explicado pelos recursos de design das classes internas. Uma classe interna pode ter construtores com parâmetros ou apenas um construtor padrão. Mas independentemente disso, quando criamos um objeto da classe interna, uma referência a um objeto da classe “externa” é silenciosamente passada para ele. Afinal, a presença de tal objeto é um pré-requisito. Caso contrário não seremos capazes de criar objetos da classe interna.

    Mas se o método da classe externa for estático, então o objeto da classe externa pode nem existir! Isso significa que a lógica da classe interna será quebrada. Nessa situação, o compilador gerará um erro:

    public static Seat createSeat() {
    
       //Bicycle.this cannot be referenced from a static context
       return new Seat();
    }
  4. Uma classe interna não pode conter variáveis ​​e métodos estáticos.

    A lógica aqui é a mesma: métodos e variáveis ​​estáticos podem existir e ser chamados mesmo que não haja nenhum objeto.

    Mas sem um objeto da classe “externa”, não teremos acesso à classe interna.

    Uma contradição óbvia! Portanto, é proibida a presença de variáveis ​​e métodos estáticos em classes internas.

    O compilador gerará um erro ao tentar criá-los:

    public class Bicycle {
    
       private int weight;
    
    
       public class Seat {
    
           //inner class cannot have static declarations
           public static void getSeatParam() {
    
               System.out.println("Seat parameter: seatpost diameter = " + Bicycle.this.seatPostDiameter);
           }
       }
    }
  5. Ao criar um objeto de uma classe interna, seu modificador de acesso desempenha um papel importante.

    Uma classe interna pode ser denotada pelos modificadores de acesso padrão - public,, e .privateprotectedpackage private

    Por que isso é importante?

    Isso afeta onde em nosso programa podemos instanciar a classe interna.

    Se nossa classe Seatfor declarada como public, podemos criar seus objetos em qualquer outra classe. O único requisito é que o objeto da classe “externa” também exista.

    Aliás, já fizemos isso aqui:

    public class Main {
    
       public static void main(String[] args) {
    
           Bicycle peugeot = new Bicycle("Peugeot", 120);
           Bicycle.HandleBar handleBar = peugeot.new HandleBar();
           Bicycle.Seat seat = peugeot.new Seat();
    
           seat.up();
           peugeot.start();
           handleBar.left();
           handleBar.right();
       }
    }

    Acessamos facilmente a classe interna HandleBardo arquivo Main.

    Se declararmos a classe interna como private, só teremos acesso à criação de objetos dentro da classe “externa”.

    SeatNão poderemos mais criar um objeto de fora:

    private class Seat {
    
       //methods
    }
    
    public class Main {
    
       public static void main(String[] args) {
    
           Bicycle bicycle = new Bicycle("Peugeot", 120, 40);
    
           //Bicycle.Seat has a private access in 'Bicycle'
           Bicycle.Seat seat = bicycle.new Seat();
       }
    }

    Você provavelmente já entendeu a lógica :)

  6. Os modificadores de acesso para classes internas funcionam da mesma forma que para variáveis ​​regulares.

    O modificador protectedfornece acesso a uma variável de classe em suas classes descendentes e em classes que estão no mesmo pacote.

    O mesmo protectedfunciona para classes internas. Objetos protectedde classe interna podem ser criados:

    • dentro da classe "externa";
    • nas suas classes descendentes;
    • nas classes que estão no mesmo pacote.

    Se a classe interna não tiver um modificador de acesso ( package private), os objetos da classe interna poderão ser criados

    • dentro da classe "externa";
    • em classes que estão no mesmo pacote.

    Você está familiarizado com modificadores há muito tempo, então não haverá problemas aqui.

Por enquanto é tudo :) Mas não relaxe! Classes aninhadas internas são um tópico bastante amplo que continuaremos a explorar em lições futuras. Agora você pode atualizar a palestra sobre aulas internas do nosso curso. E da próxima vez falaremos sobre classes aninhadas estáticas.
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION