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 Internas class MyOuter { class MyInner {} } %javac MyOuter.java MyOuter.class MyOuter$MyInner.class %java MyOuter$MyInner
Classes Internas class MyOuter { class MyInner {} } %javac MyOuter.java MyOuter.class MyOuter$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 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); } } }
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 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(); }
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(); -> LEGAL outer.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 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 ();
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 ();
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étodos public 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étodos public  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étodos public  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étodos public 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(); -> ILEGAL class 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ônimas class 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ô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?
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 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(); }
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

Classes Internas

  • 1.
  • 2.
    Classes Internas Temgerado 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 Podemacessar 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 classMyOuter { class MyInner {} } %javac MyOuter.java MyOuter.class MyOuter$MyInner.class %java MyOuter$MyInner
  • 5.
    Classes Internas classMyOuter { class MyInner {} } %javac MyOuter.java MyOuter.class MyOuter$MyInner.class %java MyOuter$MyInner -> ERRO
  • 6.
    Classes Internas %javaMyOuter$MyInner -> ERRO Uma classe interna regular não pode ter nenhuma declaração static Lembrando: uma classe interna regular não é static
  • 7.
    Classes Internas classMyOuter{ private int x = 7; class MyInner{ public void seeOuter(){ System.out.println(“x: ”+x); } } }
  • 8.
    Classes Internas Parainstanciar uma classe interna, é preciso uma instância da classe externa
  • 9.
    Classes Internas classMyOuter{ 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 MyInnerin = 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 publicstatic 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 Regraspara 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 publicstatic void main(String[] args){ Outer outer = new Outer(); outer.new Inner(); outer.new Outer.Inner(); }
  • 14.
    Classes Internas publicstatic void main(String[] args){ Outer outer = new Outer(); outer.new Inner(); -> LEGAL outer.new Outer.Inner(); -> ILEGAL }
  • 15.
    Classes Internas classMyOuter{ class MyInner{} void makeInner(){ MyInner a = new MyInner(); MyInner b = this.new MyInner(); } }
  • 16.
    Classes Internas Eo this? O this refere-se ao objeto da classe interna Outer.this refere-se ao objeto da classe externa
  • 17.
    Classes Internas publicclass 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 publicclass 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 Modificadoresaplicáveis a classes internas: final abstract public private protected strictfp static a classe interna vira classe aninhada nested class
  • 20.
    Classes Internas Locaisa Métodos public void m(){ class Inner{ public void doSomething(){ System.out.println("x:"+ x ); } } new Inner().doSomething(); } Gera: Outer.class e Outer$1Inner.class
  • 21.
    Classes Internas Locaisa Métodos public static void m(){ class Inner{ public void doSomething(){ System.out.println("x:"+ x ); } } new Inner().doSomething(); } Gera: Outer.class e Outer$1Inner.class
  • 22.
    Classes Internas Locaisa Métodos public static void m(){ class Inner{ public void doSomething(){ System.out.println("x:"+ x ); -> ILEGAL } } new Inner().doSomething(); } Gera: Outer.class e Outer$1Inner.class
  • 23.
    Classes Internas Locaisa 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 Locaisa 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 Locaisa 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 Locaisa 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
  • 27.
    Classes Internas Locaisa Métodos Só podem receber os modificadores: final abstract
  • 28.
    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"); } }; }
  • 29.
    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?
  • 30.
    Classes Internas AnônimasPopcorn 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ônimasPopcorn 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ônimasPopcorn 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ônimasCuidado! Runnable r = new Runnable(); -> ILEGAL Runnable r = new Runnable(){ public void run(){ } }; -> LEGAL
  • 34.
    Classes Internas Anônimascomo Parâmetro System.out.println( new Popcorn(){ public String toString(){ return “new poporn”; } } ); ->“ new popcorn”
  • 35.
    Classes Estáticas AninhadasSã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 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(); }
  • 37.
    Classes Internas Cuidadocom 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