CodeGym /Cursos /All lectures for PT purposes /Mudando o estado interno de um objeto usando reflexão

Mudando o estado interno de um objeto usando reflexão

All lectures for PT purposes
Nível 1, Lição 82
Disponível

Classe com um campo privado

Todos vocês sabem muito bem sobre modificadores de acesso de campo. E se um campo tiver o modificador privado , não podemos acessá-lo de fora.


public class Person {
  private int age;
  public String nickname;
  public Person(int age, String nickname) {
   this.age = age;
   this.nickname = nickname;
  }
}

Vamos verificar a acessibilidade em nossa classe Main :


public class Main {
   public static void main(String[] args) {
     Person person = new Person();  
     System.out.println(person.nickname);
    // System.out.println(person.age); No access to the field
  }
}

Não temos acesso aoidadecampo, mas temos reflexão. :) E com sua ajuda podemos acessar e trabalhar com campos privados.

Obtendo um campo privado de um objeto usando reflexão

Vamos obter um array de todos os campos da nossa classe usando o método getDeclaredFields() . Ele retorna um objeto Field com o qual podemos trabalhar e modificar:


public static void main(String[] args) {
        Field[] fields = Person.class.getDeclaredFields();
        List<String> actualFieldNames = getFieldNames(fields);
        actualFieldNames.forEach(System.out::println);
    }

    static List<String> getFieldNames(Field[] fields) {
        List<String> fieldNames = new ArrayList<>();
        for (Field field : fields)
            fieldNames.add(Modifier.toString(field.getModifiers()) + " " + field.getName());
        return fieldNames;
    }
idade privada
apelido público

No método getFieldNames , obtemos dois campos de nossa classe. O método getModifiers retorna o modificador do nosso campo e getName retorna seu nome. Agora vamos tentar modificar e acessar este campo. Primeiro, vamos tentar obter dados de um campo público:


public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
    Person person = new Person(10, "CodeGym");

    Field field = Person.class.getDeclaredField("nickname");
    String nickname = (String) field.get(person);
    System.out.println(nickname);

    System.out.println(person.nickname);
}
CodeGym
CodeGym

Podemos acessar o campo tanto com a ajuda da reflexão quanto usando nossa referência ao objeto. Tudo é bom! Vamos passar para um campo privado.

Mudaremos o nome do campo solicitado para nosso privadoidadecampo:


public static void main(String[]args)throws NoSuchFieldException, IllegalAccessException {
		Person person = new Person(10, "CodeGym");

    Field field = Person.class.getDeclaredField("age");
    int age =(int)field.get(person);
    System.out.println(age);

    // System.out.println(person.age);
}

Não temos acesso através do objeto criado, então tente usar a reflexão. Obtemos um erro:

IllegalAccessException

Obtemos um IllegalAccessException . Vamos dar uma olhada no que tem dentro:

Vamos tentar descobrir.

Uma IllegalAccessException é lançada quando um aplicativo tenta criar reflexivamente uma instância (diferente de uma matriz), definir ou obter um campo ou invocar um método, quando o método atualmente em execução não tem acesso à definição da classe, campo, método ou construtor.

Os métodos aqui também lançam essa exceção. Para evitar essa exceção, usaremos um método especial para acessar o campo privado.

setAccessible(sinalizador booleano)

Este método permite evitar verificações de acesso de segurança para um campo ou classe. Podemos passar true ou false para o método para determinar se as verificações de acesso de segurança serão executadas para o campo. Vamos tentar corrigir nosso código:


public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
    Person person = new Person(10, "CodeGym");

    Field field = Person.class.getDeclaredField("age");
    field.setAccessible(true);

    int age = (int) field.get(person);
    System.out.println("The current value is " + age);
}

Vejamos o resultado:

O valor atual é 10

Ótimo! Recebemos informações sobre nossa turma. Vamos também tentar alterar nosso campo atribuindo um novo valor a ele:


public static void main(String[]args)throws NoSuchFieldException, IllegalAccessException {
Person person = new Person(10, "CodeGym");

    Field field = Person.class.getDeclaredField("age");
    field.setAccessible(true);

    field.set(person, 19);

    int age =(int)field.get(person);
    System.out.println("The current value is " + age);
}

Depois de mudar nosso campo, obtemos:

O valor atual é 19

Vamos tentar chamar setAccessible(false) .


public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
    Person person = new Person(10, "CodeGym");

    Field field = Person.class.getDeclaredField("age");
    
    field.setAccessible(true);
    field.set(person, 19);
    field.setAccessible(false);

    System.out.println("The current value is " + field.get(person));
}

Depois de restaurar a acessibilidade para false , encontramos nossa exceção novamente quando tentamos chamar o método get :

Portanto, tenha cuidado ao trabalhar com campos privados e não se esqueça de que a reflexão é uma ferramenta muito poderosa!

Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION