2. 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
3. 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
4. Classes Internas
class MyOuter {
class MyInner {}
}
%javac MyOuter.java
MyOuter.class
MyOuter$MyInner.class
%java MyOuter$MyInner
5. Classes Internas
class MyOuter {
class MyInner {}
}
%javac MyOuter.java
MyOuter.class
MyOuter$MyInner.class
%java MyOuter$MyInner → ERRO
6. 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
8. Classes Internas
• Para instanciar uma classe interna, é preciso
uma instância da classe externa
9. Classes Internas
class MyOuter{
private int x = 7;
public void makeInner(){
MyInner in = new MyInner();
in.seeOuter();
}
class MyInner{
public void seeOuter(){
System.out.println(“x: ”+x);
}
}
}
10. 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?
11. Classes Internas
public 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();
}
12. 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
13. Classes Internas
public static void main(String[] args){
Outer outer = new Outer();
outer.new Inner();
outer.new Outer.Inner();
}
15. Classes Internas
class MyOuter{
class MyInner{}
void makeInner(){
MyInner a = new MyInner();
MyInner b = this.new MyInner();
}
}
16. Classes Internas
• E o this?
• O this refere-se ao objeto da classe interna
• Outer.this refere-se ao objeto da classe
externa
17. Classes Internas
public 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();
18. Classes Internas
public 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();
19. Classes Internas
• Modificadores aplicáveis a classes internas:
– final
– abstract
– public
– private
– protected
– strictfp
– static
• a classe interna vira classe aninhada
• nested class
20. Classes Internas Locais a Métodos
public void m(){
class Inner{
public void doSomething(){
System.out.println(quot;x:quot;+x);
}
}
new Inner().doSomething();
}
Gera: Outer.class e Outer$1Inner.class
21. Classes Internas Locais a Métodos
public static void m(){
class Inner{
public void doSomething(){
System.out.println(quot;x:quot;+x);
}
}
new Inner().doSomething();
}
Gera: Outer.class e Outer$1Inner.class
22. Classes Internas Locais a Métodos
public static void m(){
class Inner{
public void doSomething(){
System.out.println(quot;x:quot;+x); → ILEGAL
}
}
new Inner().doSomething();
}
Gera: Outer.class e Outer$1Inner.class
23. Classes Internas Locais a Métodos
public class Outer{
public void m1(){
class Inner{}
}
public void m2(){
class Inner{}
}
}
Gera: Outer.class, Outer$1Inner.class e Outer$1Inner.class
24. Classes Internas Locais a Métodos
public void m(){
class Inner{}
Inner inner = new Inner(); → LEGAL
}
public void m(){
Inner inner = new Inner(); → ILEGAL
class Inner{}
}
25. 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
}
}
}
}
26. 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
28. Classes Internas Anônimas
class Popcorn {
public void pop() {
System.out.println(quot;popcornquot;);
}
}
class Food {
Popcorn p = new Popcorn() {
public void pop() {
System.out.println(quot;anonymous popcornquot;);
}
};
}
29. Classes Internas Anônimas
Popcorn 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?
30. 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()
31. 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()
32. 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
33. Classes Internas Anônimas
• Cuidado!
Runnable r = new Runnable(); → ILEGAL
Runnable r = new Runnable(){
public void run(){ }
}; → LEGAL
34. Classes Internas Anônimas como
Parâmetro
System.out.println(
new Popcorn(){
public String toString(){
return “new poporn”;
}
}
);
→“new popcorn”
35. 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
36. Classes Estáticas Aninhadas
public 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();
}
37. 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