Skip to content

2.4 Create top level and nested classes

Weverton edited this page Aug 31, 2016 · 16 revisions

Lembretes:

  • Uma non static inner class pode ter membros static, mas eles devem ser final;
  • non static inner class pode utilizar qualquer modificador de acesso;
  • non static inner class não pode ter métodos static;
  • nested class dentro de métodos não podem ser declaradas static;
  • Uma classe anonima é implicitamente final;
  • Uma classe anonima pode ser declarada dentro de um método static;

O código abaixo não compila, no método public void doA() { inner1.doA(); } o método apresentado na classe anônima não é acessível.
Lembre também que na criação da classe anônima é necessário finalizar com ;

public class TopClass {
   public Inner inner1 = new Inner(){
       public void doA(){  System.out.println("doing A"); }
   };
   public void doA() { inner1.doA(); }
}

class Inner {
   int value;
}


Instanciando inner class:

public class TestClass{
   public class A{}
   public static class B {}

   public static void main(String args[]){
      class C{}
   }
}

Opção valida:

new TestClass().new A();

A classe B é static inner class e não pode ser instanciada dessa maneira:

new TestClass().new B();

Maneira correta:

new TestClass.B()

Uma static inner class pode ter membros não static.

class TopClass {
	static class Inner {	
		private String nome;	
	}
}

Lembretes:

  • Uma inner class pode ser privada;
  • Uma inner class pode herdar da outer class;
  • Para acessar um atributo da outer class: Onion.this.data
public class Onion {
	private String data = "skin";

	private class Layer extends Onion {
		String data = "thegoodpart";

		public String getData() {
			return data;
		}
		public String getDataDoOnion() {
			return Onion.this.data;
		}
	}

	public String getData() {
		return new Layer().getData();
	}
	
	public String getDataDoOnion() {
		return new Layer().getDataDoOnion();
	}

	public static void main(String[] args) {
		Onion o = new Onion();
		System.out.println(o.getData());        // thegoodpart
		System.out.println(o.getDataDoOnion()); // skin
	}
}

Lembretes:

public class Teste2 {

	private String strPrivada = "private";
	protected String strProtegida = "protected";;
	String strPadrao = "default";
	public String strPublica = "public";;
	
	// inner class
	public class Inner{
		
		private void teste() {
			// Independente do modificador de acesso, os membros pode ser utilizado na inner class
			
			System.out.println(strPrivada);
			System.out.println(strProtegida);
			System.out.println(strPadrao);
			System.out.println(strPublica);
			
			System.out.println(Teste2.this.strPrivada);
			System.out.println(Teste2.this.strProtegida);
			System.out.println(Teste2.this.strPadrao);
			System.out.println(Teste2.this.strPublica);
		}
		
	}
	
	// static inner class
	public static class InnerStatic{
		
		private void teste() {
			// Os membros da outer class nao são static então nao compila
			
//			System.out.println(strPrivada);
//			System.out.println(strProtegida);
//			System.out.println(strPadrao);
//			System.out.println(strPublica);
//			
//			System.out.println(Teste2.this.strPrivada);
//			System.out.println(Teste2.this.strProtegida);
//			System.out.println(Teste2.this.strPadrao);
//			System.out.println(Teste2.this.strPublica);
			System.out.println("Teste");
		}
		
	}
	
	public static void main(String[] args) {
		//Para funcionar deve existir uma instancia de Teste2
//		new Inner();
		
		new Teste2().new Inner().teste();
		
		new InnerStatic().teste();
		
		new Teste2.InnerStatic().teste();
	}
	
}

Lembre que nem sempre é possivel referencia um membro da outer class na inner class.
O exemplo abaixo é um deles: shodowing

public class Teste3 {

	private String nome = "Eu sou Outer";;
	
	class Inner extends Teste3 {
		
		private String nome = "Eu sou Inner";

		public String getNome() {
			return nome;
		}
		
		public String getNomeOuter() {
			return Teste3.this.nome;
		}
		
	}
	
	public static void main(String[] args) {
	        System.out.println(new Teste3().new Inner().nome); //Eu sou Inner
		System.out.println(new Teste3().nome); //Eu sou Outer
		System.out.println(new Teste3().new Inner().getNomeOuter()); //Eu sou Outer	
	}

}

É possivel criar instancias diferentes com a mesma outer class.

public class Teste4 {

	class Inner {}
	
	public static void main(String[] args) {
		Teste4 teste4 = new Teste4();
		
		Inner inner1 = teste4.new Inner();
		Inner inner2 = teste4.new Inner();
		
		System.out.println("Estão apontandos para o mesmo objeto = " + (inner1 == inner2)); // false
	}

}

Lembretes:

  • Mesmo uma outer class sendo final ela pode ter inner class;
  • O no access modifier static não pode ser utilizado em top level class ou class que não é membro;
  • Classes declaradas dentro de metodos não podem ser static;
  • Classes anônimas não podem definir construtores explicitos;

Uma static inner class pode ter uma non - static inner class.

public class Teste6 {
	
	// static inner class
	public static class InnerStatic {
		// inner class dentro de uma static inner class
		class InnerInner {}
	}
	
	public static void main(String[] args) {
		// instanciando uma classe que esta dentro da static inner class
		new Teste6.InnerStatic().new InnerInner();
	}
	
}

O codigo abaixo não compila. A inner class foi criada em um método static e não tem referencia ao objeto TestFrame.

public class TestFrame extends Frame {

	String s = "Message";

	public static void main(String args[]) {
		TestFrame t = new TestFrame();
		Button b = new Button("press me");
		b.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				System.out.println("Message is " + s);
			}
		});
		t.add(b);
	}
}

Membro static em non static inner class não funciona, só se for final.

class Outer {
   class Inner
   {
     static int k = 10; // com final compila
   }
}

Se a classe tem um construtor a anonima pode utiliza-lo.

//outer class
class TestClass {
	
	//construtor com parametro
	public TestClass(int i) {}

	//método de instancia
	public void m1() {
		
		//classe anonima utilizando o contrutor que tem um parametro
		TestClass al = new TestClass(10) {	
			public void actionPerformed(ActionEvent e) {
			}	
		};
	}
}