class OuterClass {
...
static class StaticNestedClass {
...
}
class InnerClass {
...
}
}
São essas classes que são chamadas aninhadas. Eles são divididos em 2 tipos:
- Classes aninhadas não estáticas - classes aninhadas não estáticas. Elas também são chamadas de classes internas de outra forma.
- Classes aninhadas estáticas - classes aninhadas estáticas.
- aula local
- classe anônima
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()
. Sua 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. Nesta 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:
-
Um objeto de uma classe interna não pode existir sem um objeto de uma classe “externa”.
Isso é lógico: por isso fizemos aulas
Seat
internasHandleBar
, 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:
-
Um objeto de uma classe interna tem acesso às variáveis da classe “externa”.
Por exemplo, vamos adicionar
Bicycle
uma variável à nossa classeint seatPostDiameter
- o diâmetro do espigão do selim.Então, na classe interna,
Seat
podemos criar um métodogetSeatParam()
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! -
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(); }
-
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); } } }
-
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 .private
protected
package private
Por que isso é importante?
Isso afeta onde em nosso programa podemos instanciar a classe interna.
Se nossa classe
Seat
for declarada comopublic
, 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
HandleBar
do arquivoMain
.Se declararmos a classe interna como
private
, só teremos acesso à criação de objetos dentro da classe “externa”.Seat
Nã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 :)
-
Os modificadores de acesso para classes internas funcionam da mesma forma que para variáveis regulares.
O modificador
protected
fornece acesso a uma variável de classe em suas classes descendentes e em classes que estão no mesmo pacote.O mesmo
protected
funciona para classes internas. Objetosprotected
de 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.
GO TO FULL VERSION