Ir para conteúdo

[Tutorial] Descomplicando a API Reflection


Out of Orbit

Posts Recomendados

q1kMRRu.png

 

O que é reflection?

 

Reflection é um recurso do java que permite manipular e editar classes, métodos, atributos, etc em tempo de execução.

Com isso, por exemplo, é possível instanciar uma classe sem que a mesma seja adicionada ao projeto.

 

Além disso, dá até para modificar e acessar construtores, atributos e métodos privados. Sabe aquela string privada que você ficava doido querendo mudar? Com reflection isso é possível.

 

Mas como manipular as classes? Primeiro é preciso adquirir uma referência à classe, mas como fazer isso?

Existem três maneiras de fazer isso:

// Através de uma instância da classe

String string = "Reflection é legal";
Class<?> clazz = string.getClass();
// Através da própria classe

Class<String> clazz = String.class;
// Através do método Class#forName(String className);

try {
	Class<?> clazz = Class.forName("java.lang.String");
} catch (ClassNotFoundException e) {
	e.printStackTrace();
}

Como foi possível observar, nos dois primeiros métodos é necessário que as classes em questão façam parte do projeto.

Já no último método, basta que você tenha o nome da classe. Mas é só isso? Não, isso é só a ponta do iceberg, a partir daqui infinitas possibilidades são abertas para a manipulação da classe.

 

Constructor   (docs)

 

O que é um Constructor? É uma classe que permite instanciar as classes.

Como conseguir os construtores de uma classe?

// Através do método Class#getConstructors();

Constructor[] constructors = clazz.getConstructors(); 
/* Através do método Class#getConstructor(Class<?>... parameterTypes);
*  Note que com esse método é necessário especificar os parâmetros do construtor
*/

try {
	Constructor<?> constructor = clazz.getConstructor(String.class);
} catch (NoSuchMethodException e1) {
	e1.printStackTrace();
} catch (SecurityException e2) {
	e2.printStackTrace();
} 

Construtor em mãos, mas como conseguir uma instância da classe?

É agora que utilizaremos o método Constructor#newInstance(Object... initargs);

/* Note que os parâmetros que você utilizar no newInstance();
*  Devem ser idênticos ao do construtor que você está utilizando
*/

try {
	Constructor<?> constructor = clazz.getConstructor(String.class);
	Object string = constructor.newInstance("Criei uma string com Reflection =D");
} catch (Exception e) {
	e.printStackTrace();
}

Mas se o método newInstance() retorna um Object, como que eu irei utilizar os métodos e atributos da instância?

Eu tive todo esse trabalho para instância uma classe atoa? Não. Veremos a seguir como manipular os métodos e atributos da nossa instância.

 

Field   (docs)

 

Esta é a classe que permite acessar e modificar os atributos de uma instância.

Para acessar os atributos da classe vamos utilizar o método Class#getDeclaredFields();

Field[] field = clazz.getDeclaredFields();

Mas e se eu precisar de buscar por um atributo específico? Tal como a array de carácteres de uma String?

// Para isso utilizaremos o método Class#getDeclaredField(String name);

try {
	Field field = clazz.getDeclaredField("value");
} catch (Exception e) {
	e.printStackTrace();
}

Talvez você tenha percebido que para conseguir aquele atributo, utilizamos o método da Classe, e não da instância que criamos agora a pouco. Se não percebeu, tudo bem, mas agora deve estar se perguntando, onde entra o objeto que fizemos?

 

Nós iremos utilizar o método Field#get(Object object); onde object é a instância de onde vamos buscar o atributo especificado. Mas e se for um atributo estático, que não pertence ao escopo da instância mas sim ao da classe? Basta colocar null.

 

Mas antes de acessarmos o atributo, você talvez tenha pensado: "Mas eu não sabia da existência desse atributo". Pois é, eu também não sabia, tive que olhar na source da classe String. Isso é porque o atributo é privado, então para acessarmos ele é necessário um método bem especial, o AccessibleObject#setAccessible(boolean flag);

field.setAccessible(true);

Agora sim podemos pegar o atributo.

try {
	Object value = field.get(string);
} catch (Exception e) {
	e.printStackTrace();
}

Mas o atributo value é uma array, o que fazer?

try {
	Object[] value = (Object[]) field.get(string);
} catch (Exception e) {
	e.printStackTrace();
}

Basta fazer um cast.

 

Method   (docs)

 

Agora chega a parte mais interessante, os métodos.

Assim como o Field, para conseguir os métodos de uma classe utilizaremos Class#getDeclaredMethods();

Method[] methods = clazz.getDeclaredMethods();

Apesar da semelhança para conseguir os métodos declarados, existe uma pequena diferença na hora de buscar por um método específico, pois além do nome, é necessário apresentar os parâmetros do método em questão.

 

Como exemplo pegaremos o método String#length();

/* Note que caso o método em questão não precise de argumentos
*  Só é necessário o nome do mesmo: clazz.getDeclaredMethod("length");
/*

try {
	Method method = clazz.getDeclaredMethod("indexOf", String.class);
} catch (Exception e) {
	e.printStackTrace();
}

Agora você deve ter notado que a nossa instância não fui utilizada né?

Para chamar o método nós precisamos do método Method#invoke(Object obj, Object... args);

try {
	method.invoke(string, "Criei");
} catch (Exception e) {
	e.printStackTrace();
}

Observação: Assim como no Field, se o método for estático basta colocar o primeiro parâmetro como null.

 

Considerações finais

 

Este tutorial foi bem simples pois ele foca nas classes mais usadas do pacote java.lang.reflect

Você pode ter mais informações sobre reflection acessando esses links:

Link para o comentário
Compartilhar em outros sites

Belo tutorial, ainda assim não consegui entender por completo.

Parabéns!

Obrigado, esse tutorial foi bem básico. Mas teve algo específico do tutorial que não tenha entendido?

 

 

Krl, muito bom cara, isso era uma coisa que eu não tinha muito interesse em aprender kkk

Obrigado, pois é, reflection é um pouco chato de aprender kk :v

Editado por Out of Orbit
Link para o comentário
Compartilhar em outros sites

Então usando isso daria pra fazer um programa ou um plugin para modificar Strings de uma aplicação que esta sendo executada? Eu tenho um jogo em JAVA só que ele é em inglês usando reflection eu poderia modificar as Strings desse jogo?

Pelo o que entendi, sim.

 

Obrigado, esse tutorial foi bem básico. Mas teve algo específico do tutorial que não tenha entendido?

 

 

Obrigado, pois é, reflection é um pouco chato de aprender kk :v

 

Eu entendi na verdade, fui pesquisando mais a fundo e entendi.

Link para o comentário
Compartilhar em outros sites

Então usando isso daria pra fazer um programa ou um plugin para modificar Strings de uma aplicação que esta sendo executada? Eu tenho um jogo em JAVA só que ele é em inglês usando reflection eu poderia modificar as Strings desse jogo?

 

Não, porque as classes desse jogo já estão compiladas. Com reflection você pode alterar apenas objetos.

 

Imagine que você quer fazer um programa que o usuário digite o nome de uma classe e então seja exibido todos os métodos, atríbutos, superclasse, construtor etc. Não seria viável reescrever todo o código para cada classe, aí que entra o reflection.

Link para o comentário
Compartilhar em outros sites

Então usando isso daria pra fazer um programa ou um plugin para modificar Strings de uma aplicação que esta sendo executada? Eu tenho um jogo em JAVA só que ele é em inglês usando reflection eu poderia modificar as Strings desse jogo?

 

Bom, se a String que você quer modificar estiver em um Field e este field não for final (porque, se for final, o compilador já vai ter "inline-zado" a String, fazendo com que a alteração tenha efeito), basta modificar o valor do Field.

Caso contrário você terá que alterar direto no arquivo .class. Você pode tentar usar esta ferramenta que eu fiz: https://leonardosnt.github.io/jar-string-editor/que permite alterar as strings de um jar.

Link para o comentário
Compartilhar em outros sites

Bom, se a String que você quer modificar estiver em um Field e este field não for final (porque, se for final, o compilador já vai ter "inline-zado" a String, fazendo com que a alteração tenha efeito), basta modificar o valor do Field.

Caso contrário você terá que alterar direto no arquivo .class. Você pode tentar usar esta ferramenta que eu fiz: https://leonardosnt.github.io/jar-string-editor/que permite alterar as strings de um jar.

Eu dei uma estudada melhor sobre Reflection e ja entendi varias paradas como essas... vlw pelo comment e pele explicação pai

Link para o comentário
Compartilhar em outros sites

Participe da Conversa

Você pode postar agora e se cadastrar mais tarde. Se você tiver uma conta, a class='ipsType_brandedLink' href='https://gamersboard.com.br/login/' data-ipsDialog data-ipsDialog-size='medium' data-ipsDialog-title='Sign In Now'>acesse agora para postar com sua conta.
Observação: sua postagem exigirá aprovação do moderador antes de ficar visível.

Visitante
Responder

×   Você colou conteúdo com formatação.   Remover formatação

  Apenas 75 emoticons são permitidos.

×   Seu link foi incorporado automaticamente.   Exibir como um link em vez disso

×   Seu conteúdo anterior foi restaurado.   Limpar Editor

×   Você não pode colar imagens diretamente. Carregar ou inserir imagens do URL.

Processando...
×
×
  • Criar Novo...