25%OFF no 1º ano | 50%OFF No 2º ano

Últimos dias!

Últimos dias!

00

DIAS

00

HORAS

00

MIN

00

SEG

Strings (i)mutáveis?

Strings (i)mutáveis?
trusso
trusso

Compartilhe

Todos sabemos que, em Java, Strings são objetos imutáveis. Sendo assim, qualquer chamada de método em uma referência para String NÃO irá alterar o valor da referenciada. Uma sugestão aqui é uma pesquisa sobre o pattern Flyweight que é utilizado nesta classe e justifica tal imutabilidade.

Exemplo:

 public class Teste {

public static void main(String \[\] args) throws Exception { String nome = "Thadeu de Russo e Carmo"; nome.toUpperCase(); System.out.println(nome); } } 
Banner da Black Friday da Alura com destaque para até 50% de desconto em cursos, válido até 29/11. Transforme a sua carreira com o maior desconto do ano, matricule-se já!

O output será Thadeu de Russo e Carmo.

Nos gabamos para nossos colegas quem estão no início de carreira em Java sobre tal conhecimento, que é cobrado inclusive na prova de certificação de programador. Poderiamos também criar uma função que "executasse" algumas alterações.

Algo como:

 public class Teste {

public static void main(String \[\] args) throws Exception { String nome = "Thadeu de Russo e Carmo"; alteraString(nome); System.out.println(nome); } } 

O output será Thadeu de Russo e Carmo.

Pelo que conhecemos, independentemente do conteúdo da função alteraString(String), nunca conseguiríamos alterar o conteúdo referenciado por nome, certo? Errado!!!!

Utilizando os recursos da API de Reflection, conseguimos facilmente realizar tal alteração. Mãos a obra!

 import java.lang.reflect.Field;

public class Teste {

public static void main(String \[\] args) throws Exception { String nome = "Thadeu de Russo e Carmo"; alteraString(nome); System.out.println(nome); } public static void alteraString(String nome) throws Exception { Field value = String.class.getDeclaredField("value"); //1 value.setAccessible(true); //2 char \[\] charsDaString = (char \[\]) value.get(nome); // 3 charsDaString\[0\] = 't'; charsDaString\[1\] = 'H'; charsDaString\[2\] = 'A'; charsDaString\[3\] = 'D'; charsDaString\[4\] = 'E'; } } 

Uow!!!! Mágica? Vamos ao que esta acontecendo nas linhas numeradas.

linha 1 - Estamos pegando uma referencia para um objeto do tipo java.lang.reflect.Field para o atributo "value" da classe String. linha 2 - Este é um campo privado (basta olhar o fonte da classe String) e para conseguirmos acesso a ele, temos que "nos dar acesso". (Olha o encapsulamento indo para o buraco!!) linha 3 - Na instancia que eu tenho (nome), eu desejo pegar o field value (que é o array onde os caracteres são armazenados).

Nas demais linhas nós simplesmente trocamos os valores dos caracteres. O que será que teremos impresso? Ta-da!! "tHADEu de Russo e Carmo". Opa, algo diferente do que haviamos afirmado mais acima. Vale afirmar que fazer tal modificação em uma String é uma péssima idéia, dado o pool de Strings: alguém pode estar compartilhando essa String com você, e enxergará essa alteração sem ter previsto tal acontecimento!

O que fizemos no código acima foi, simplemente brincar com a API de Reflection. API esta que permite coisas como injeção de dependência como no EJB3, vRaptor, JBoss Seam, etc. Aqueles que já trabalharam com os velhos applets devem estar pensando: "Achei uma falha de segurança no Java!". Isso não é verdade pois dentro do método setAccessible(boolean) da classe Field, existe uma validação junto ao SecurityManager.

Vale atentar ao fato de que é possível alterar tais propriedades no arquivo java.policy que fica sob a pasta %JAVA_HOME%\jre\lib\security.

Finalizando, aqueles que não conheciam ou não sabiam o poder da API de Reflection, viram que com um simples código, conseguimos "mutar" uma String, imaginem com um pouco mais de código o que não é possível de se fazer.

Veja outros artigos sobre Programação