Classes Internas

Preview:

DESCRIPTION

Slides sobre classes internas de Java

Citation preview

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

Recommended