Classes internas (postagem 1/2)
Autor: Gustavo | Publicado: 2015-03-16T09:19:00-03:00


Classes
internas são aquelas que são definidas dentro de uma outra classe.
Ultimamente dififíceis de serem encontrdas em uma aplcação por
serem mal vistas por não trazerem uma aparência familiar.  Mas
podem oferecer grandes benefícios quando bem desenhadas dentro de
uma aplicação.

 Integradas
ao java a partir da versão 1.1 onde ainda era muito utilizado a API
SWING, as classes internas davam muita facilidade para o 
desenvolvimento de aplicações com interace gráfica trazendo
eficientes formas de desenvolver algo em situações específiacas.
Deixando inclusive mais fácil de ler e de realizar manutenção.

 Tive
o privilégio de trabalhar no DATASUS usando esta API e foi quando
mais me deparei com estas classes que a princípio podem “machucar
a vista” mas que depois que se entende, muito se pode tirar
proveito desta funcionalidade.

 Em
geral as classes internas proporciona que você defina uma classe
dentro da outra viabilizando novas funcionalidades para suas classes
já que poderá fazer com que uma classe seja menmbro da outra. Da
mesma forma que uma classe possui variáveis e métodos-membros, elas
poderão ter classes memboros.

Elas
podem ser definidas de 4 formas diferentes:


Classes
 Internas Comum


Classes
 Internas locais de métodos


Classes
 Internas anônimas


Classes
 estáticas





 A
instância de uma classe interna compartilha todas as informações
da classe externa. Esse relacionamento especial concede ao código da
classe interna acesso a membros da classe que estiver encapsulada
(externa) como se a classe interna fizesse parte da externa. O que na
verdade não deixa de ser. 


 Debemos
lembrar que sempre que estivermos utilizando uma classe interna,
teremos acesso aos membros privados da instancia da classe externa na
verdade, todos os membros da classe externa e vice-versa. Além da
própria classe interna ser um membro-classe da classe extena, elas
possuem um relacionamento íntimo e isso só nos beneficia caso o
projeto seja bem arquitetado.




Codificando
a Classe interna Comum






 Uma
classe interna comum poderá ser definida da mesma forma que qulquer
outro membro (atributo ou método) de uma classe, com exceção da
definição static.

 Logo,
podemos usar modificadores em uma classe interna com as seguintes
palavras reservadas do java:




final


abstract


public


private


protected


strictfp





 Apesar
de não ser possível utilizar a palavra reservada static em
classes, veremos que será possível tal abordagem da declaração
de classes internas. Mas não falarei sobre este caso agora por suas
características serem um pouco diferentes, desta forma falarei
separadamente no último tópico destes post sobre classes internas
estáticas.

Tendo
falado das definições e das possíveis formas de se declarar uma
classe interna, vamos ao código &lt;o/

 Para
se  declarar uma classe interna, podemos simplesmente definir uma
classe dentro de outra classe conforme abaixo:



public
class
ClasseExterna {

 public
static
void
main(String... args)
{

  System.out.println("Vai
Medina!! #BrazilianStorm");

 }

 class
ClasseInterna {  

 }//
fecha
classe
interna

}//
fecha
classe
externa



 Uma
observação interessante é que se você gosta de compilar rodar as
classes pelo terminal, ao executar o comando:



$
 javac ClasseExterna.java



Notará
que serão criado 2 arquivos com extensão .class



ClasseExterna.class

ClasseExterna$ClasseInterna.class



 Diferente
do que se possa imaginar, é possível executar a classe interna só
que seu comportamento será como se executasse a classe extena, isso
quer dizer que se executarmos o código acima conforme abaixo
teremos:



$
 javac ClasseExterna.java

$
java ClasseExterna$ClasseInterna

Vai
Medina!! #BrazilianStorm



 Vale
lembrar  que estou usando Java 7 pois até onde sei pelos livros de
certificação de java 5 isto não deveria ser possível.




Acessando
membros e Instanciando uma classe Interna




 Para
começarmos lembramos que uma instância é um objeto que usa como
referência os atributos de uma classe. Como uma classe interna não
deixa de ser um membro da classe externa, a classe interana terá
como acessar qualquer outro membro da classe externa por mais que
este esteja com o modificador privado conforme o código abaixo:



public
class
ClasseExterna {

 private
int
x
= 7;

 private
String textoDeIncentivo="Vai
Medina!! #BrazilianStorm";





 class
ClasseInterna {



  public
void
getTextoDeIncentivo(){

  
 System.out.println(

    "Outer
x is "
+ClasseExterna.this.textoDeIncentivo);

  }

  public
void
getXExterno() {

   System.out.println("Outer
x is "
+ ClasseExterna.this.x);

  }

 }//
fecha
classe
interna

}



 Conforme
podemos ver por mais que os membors “x” e “textoDeIncentivo”
sejam privados, a ClasseInterna com uma referência a classe externa,
consegue acessar normalmente. Existe forma mais simples de acessar os
membros externos pela classe interna, sem a utilização da
referência da classe externa conforme abaixo:

  public
void
getTextoDeIncentivo(){

   System.out.println("Outer
x is "
+ textoDeIncentivo);

  }

  public
void
getXExterno() {

   System.out.println("Outer
x is "
+ x);

  }

Mas
eu não a recomendo, prefiro sempre que possível utilizar a
referência this
e a referência da classe externa caso necessário.
O deselnvolvedor que pergar seu código para maniutenção também
agradecerá a gentileza, até porque se por algum motivo acabarem
tendo a necessidade de sobrescrever a variável na classe interna,
não afetará o resto da aplicação por estar bem codificada
conforme
mostraremos a seguir:



public
class
ClasseExterna {

 private
int
x
= 7;

 private
String textoDeIncentivo="Vai
Medina!! #BrazilianStorm";





 class
ClasseInterna {

   private
int
x=3;

  public
void
getTextoDeIncentivo(){

   System.out.println("textoDeIncentivo
é "
+ textoDeIncentivo);

   System.out.println("ou
textoDeIncentivo
é
"
+           ClasseExterna.this.textoDeIncentivo);

  }

  public
void
getXExterno() {

   System.out.println("x
é
"
+ ClasseExterna.this.x);

  }

  public
void
getXInterno()
{

   System.out.println("this.x
é
"
+ this.x);

   System.out.println("x
é
"
+ x);

  }

 }//
fecha
classe
interna

}

 Ao
ler o código acima, veremos que temos um atributo sobrescrito na
classe interna, para imprimir esta variável precisamos referenciar a
classe externa, depois a classe  interna, para finalmente as
variáveis ClasseExterna.this.x.
Usando somente o nome
da variável como
anteriormente mencionamos,
irá o programdor poderá
estar se equivocando,
pensando que está referenciando a variável externa quando na
verdade está referenciando o
a classe interna. Vale
lembrar que caso não esteja sobrescrevendo a variável é totalmente
aceitável colocar somente a nomclatura da variável confome
utilizado na implressão da variável textoDeIncentivo.

' Instanciar
uma classe ou se preferir criar um objeto de uma classe interna é
tão simples como qualquer outra, comecamos usando a classe de
referência, damos um nome a referência que será criada depois a
palavra reservada new
e
finalizamos com a classe de instância conforme abaixo:



ClasseInterna
ci = new
ClasseInterna();



 Vale
lembrar antes que  a instanciação conforme acima só será válida
caso realize por
dentro da classe ClasseExterna
isto porque não é possível instâncias somente a classe interna
sem ter uma referência da classe externa, o que é totalmente fácil
de compreender né? Vejamos a lógica.... Se a classe interna é
vista como um membro qualquer da classe externa, imagine como iremos
por exemplo pegar o atributo textoDeIncentivo
da ClasseExterna sem a referência da mesma? Para instanciarmos uma
classe interna 
em outra classe, precisaremos
sempre da
classe externa como
referência:



ClasseExterna
ce = new
ClasseExterna();

ce.getClasseInterna();//possui
uma
linha
ClasseInterna ci
= new ClasseInterna();

 //
ou

ClasseExterna.ClasseInterna
ci
= ce.new
ClasseInterna();



 //
ou

ClasseExterna.ClasseInterna
ceci
= new
ClasseExterna().new
ClasseInterna();



 Todas
as variáveis declaradas acima, possuem uma referência a classe
externa e a classe interna de formas diferentes, mas todas conseguem
acessar qualquer método ou qualquer atributo de ambas as classes.




Classes
internas locais de métodos




 Uma
classe interna local de método conforme o nome já diz  é uma
classe que é declarada internamente em um método podendo ser em uma
classe ou até mesmo em
um método que já se encontra
dentro de uma classe interna. A
classe local (forma que será dito de agora em diante) nunca
será utilizada fora do método que foi
delclarado.



Exemplo:

public
void
getClasseLocalInterna() {//
abre
método

 class
LocalInterna { //
inicia
classe
interna

  public
void
getClasseLocalInterna() {//
inicia
metodo
da
classe

   System.out.println("Método
de uma Classe Local Interna");

  }//
fecha
metodo
da
classe

 }//
fecha
classe
interna

}



 Diferente
das outras classes
internas que
descrevemos até agora, a classe local não poderá ter seu
modificador como public
,private,protected
ou static
sobrando
então abstract
e final
.

 O
que mais deveremos prestar
atenção é
quanto
as variáveis que são utilizadas dentro de uma classe local. Não
é possível utilizar variáveis locais de
um
método em sua classe interna local,
a não ser é claro que o
atributo seja
definida como final.
 O motivo disto é simples, sabemos que as variáveis locais e as
variáveis de instância são armazenadas em memórias diferentes. Em
quanto a primeira é armazenada em pilha e tem seu início a
qualquer momento da
declaração
de
um método, e
seu fim ao término de um método, o
que é um pouco diferente das
variáveis de instância que
são
armazenadas em um heap
fazendo
com que possam continuar ativos
após o término no método, uma
vez que esta
variável de referência possa ser passada para outra variável que
tem seu escopo maior que
a do método que a variável local foi definida,
imagine
o que ocorreria quando esta variável de instância tentasse acessar
uma variável local em algum momento fora do método.
Resumindo
já
que as variáveis locais
não
tem garantias de continuarem ativas como as variáveis
de intâncias,
eles não poderão uriliza-las,
repetindo, a não ser que sejam marcadas como final.



 Bem
aqui finalizarei a parte deste do post sobre Classes internas. Irei
finalizar o assunto no próximo post que pretendo colocar na
quarta-feira ou sexta-feira. Mas caso queiram baixar o código, já
se encontra na conta GitHub. Tanto o material de hoje quanto a do
próximo post.

Grato
e Criticas a vontade :)


Git=&gt;https://github.com/gmachado1/blog