Classes Internas
Raphael Marques
Classes Internas• Tem gerado relações de amor e ódio desde sua
introdução na versão 1.1
• Permite criar uma classe dentro de outra
• Uma classe é um MEMBRO de outra classe (como campos e métodos)
• Na prova geralmente são utilizadas em exemplos sobre outros tópicos
Classes Internas
• Podem acessar todos os membros da classe externa, mesmo os private
• Isso não quebra o encapsulamento
• Classe interna regular:– Não é static– Não é local a um método– Não é anônima
Classes Internasclass MyOuter {
class MyInner {}}
%javac MyOuter.java
MyOuter.classMyOuter$MyInner.class
%java MyOuter$MyInner
Classes Internasclass MyOuter {
class MyInner {}}
%javac MyOuter.java
MyOuter.classMyOuter$MyInner.class
%java MyOuter$MyInner → ERRO
Classes Internas
• %java MyOuter$MyInner → ERRO
• Uma classe interna regular não pode ter nenhuma declaração static
• Lembrando: uma classe interna regular não é static
Classes Internas
class MyOuter{private int x = 7;
class MyInner{public void seeOuter(){
System.out.println(“x: ”+x);}
}}
Classes Internas
• Para instanciar uma classe interna, é preciso uma instância da classe externa
Classes Internasclass MyOuter{
private int x = 7;
public void makeInner(){MyInner in = new MyInner();in.seeOuter();
}
class MyInner{public void seeOuter(){
System.out.println(“x: ”+x);}
}}
Classes Internas
• MyInner in = new MyInner();
• Só é possível porque não existe nenhuma outra classe chamada MyInner acessível
• E como acessar a classe interna se ela precisa de uma instancia da classe externa?
Classes Internaspublic static void main(String[] args){
MyOuter outer = new MyOuter();MyOuter.MyInner inner = mo.new MyInner();inner.seeOuter();
}
public static void main(String[] args){MyOuter.MyInner inner = new MyOuter().new MyInner();inner.seeOuter();
}
Classes Internas
• Regras para utilização:– Use MyInner dentro da classe externa
– Use MyOuter.MyInner fora da classe externa
– Use MyInner fora da classe externa se você já tem uma instância da classe externa
Classes Internas
public static void main(String[] args){Outer outer = new Outer();outer.new Inner();outer.new Outer.Inner();
}
Classes Internas
public static void main(String[] args){Outer outer = new Outer();outer.new Inner(); → LEGALouter.new Outer.Inner(); → ILEGAL
}
Classes Internas
class MyOuter{class MyInner{}
void makeInner(){MyInner a = new MyInner();MyInner b = this.new MyInner();
}}
Classes Internas
• E o this?
• O this refere-se ao objeto da classe interna
• Outer.this refere-se ao objeto da classe externa
Classes Internaspublic class Outer{
private int x = 7;public class Inner{
private int x = 5;public void doSomething(){
...println(this.getClass());
...println(Outer.this.getClass());
...println(x);
...println(this.x);
...println(Outer.this.x);}
}}...new Outer().new Inner(). doSomething();
Classes Internaspublic class Outer{
private int x = 7;public class Inner{
private int x = 5;public void doSomething(){
...println(this.getClass()); → class Outer$Inner
...println(Outer.this.getClass()); → class Outer
...println(x); → 5
...println(this.x); → 5
...println(Outer.this.x); → 7}
}}...new Outer().new Inner(). doSomething();
Classes Internas
• Modificadores aplicáveis a classes internas:– final– abstract– public– private– protected– strictfp– static
• a classe interna vira classe aninhada• nested class
Classes Internas Locais a Métodospublic void m(){
class Inner{public void doSomething(){
System.out.println("x:"+x);}
}new Inner().doSomething();
}
Gera: Outer.class e Outer$1Inner.class
Classes Internas Locais a Métodospublic static void m(){
class Inner{public void doSomething(){
System.out.println("x:"+x);}
}new Inner().doSomething();
}
Gera: Outer.class e Outer$1Inner.class
Classes Internas Locais a Métodospublic static void m(){
class Inner{public void doSomething(){
System.out.println("x:"+x); → ILEGAL
}}new Inner().doSomething();
}
Gera: Outer.class e Outer$1Inner.class
Classes Internas Locais a Métodospublic class Outer{
public void m1(){class Inner{}
}public void m2(){
class Inner{}}
}
Gera: Outer.class, Outer$1Inner.class e Outer$1Inner.class
Classes Internas Locais a Métodos
public void m(){class Inner{}Inner inner = new Inner(); → LEGAL
}
public void m(){Inner inner = new Inner(); → ILEGALclass Inner{}
}
Classes Internas Locais a Métodos
• Uma classe interna local não pode usar as variáveis locais do método em que a classe interna está.
public class Outer{void doSomething(){
int x = 0;class Inner{
public void seeOuter(){System.out.println(x); → ILEGAL
}}
}}
Classes Internas Locais a Métodos
• Porque?– A variável local ao método só existe durante a execução do
método– Depois que o método termina a variável vira história– Mas a referência ao objeto da classe interna pode se manter
na memória
• Solução:– Marcar a variável local como final– É uma exigência do compilador
Classes Internas Locais a Métodos
• Só podem receber os modificadores:– final– abstract
Classes Internas Anônimasclass Popcorn {
public void pop() {System.out.println("popcorn");
}}
class Food {Popcorn p = new Popcorn() {
public void pop() {System.out.println("anonymous popcorn");
}};
}
Classes Internas AnônimasPopcorn p = new Popcorn() { ... }
• O campo p da classe Food não faz referência à um objeto da classe Popcorn, mas sim a um objeto da subclasse anônima de Popcorn.
• Pode ser utilizado para estender superclasses ou implementar UMA interface
• O construtor usado deve existir na superclasse
• É possível declarar construtores em classes anônimas?
Classes Internas Anônimas
Popcorn p = new Popcorn();– Objeto da classe Popcorn
Popcorn p = new Popcorn() {public void pop() {...}
};– Objeto da subclasse anônima de Popcorn– Sobrescrevendo o método pop()
Classes Internas Anônimas
Popcorn p = new Popcorn();– Objeto da classe Popcorn
Popcorn p = new Popcorn() {public void pop() {...}
}; ← ← ← ← ← ← ← ← ← ← ← ← ←– Objeto da subclasse anônima de Popcorn– Sobrescrevendo o método pop()
Classes Internas Anônimas
Popcorn p = new Popcorn() {public void pop() {...}public void something() {...}
};
O segundo método não estará acessível na referência p
Classes Internas Anônimas
• Cuidado!
Runnable r = new Runnable();→ ILEGAL
Runnable r = new Runnable(){public void run(){ }
}; → LEGAL
Classes Internas Anônimas como Parâmetro
System.out.println(new Popcorn(){
public String toString(){return “new poporn”;
}}
);→“new popcorn”
Classes Estáticas Aninhadas
• São classes internas estáticas– Não são classes internas pela definição
• A classe interna pode ser acessada sem precisar de uma instancia da classe externa
Classes Estáticas Aninhadaspublic class Outer{
public static class Nest {}public static void main(String[] args){
Nest n = new Nest();}
}...public static void main(String[] args){
Outer.Nest n = new Outer.Nest();}
Classes Internas
• Cuidado com a sintaxe estranha
• Saiba as características de classes internas, locais a métodos, e classes aninhadas
• Não esqueça do ; quando criar uma classe anônima atribuindo a uma referência
Top Related