Classe avec un champ privé

Vous connaissez tous très bien les modificateurs d'accès aux champs. Et si un champ a le modificateur privé , nous ne pouvons pas y accéder de l'extérieur.


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

Vérifions l'accessibilité dans notre 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
  }
}

Nous n'avons pas accès auâgeterrain, mais nous avons une réflexion. :) Et avec son aide, nous pouvons accéder et travailler avec des champs privés.

Obtenir un champ privé à partir d'un objet en utilisant la réflexion

Obtenons un tableau de tous les champs de notre classe en utilisant la méthode getDeclaredFields() . Il renvoie un objet Field avec lequel nous pouvons travailler et modifier :


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;
    }
âge privé
surnom public

Dans la méthode getFieldNames , nous obtenons deux champs de notre classe. La méthode getModifiers renvoie le modificateur de notre champ et getName renvoie son nom. Essayons maintenant de modifier et d'accéder à ce champ. Essayons d'abord d'obtenir des données à partir d'un champ public :


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);
}
Code Gym
Code Gym

Nous pouvons accéder au champ à la fois avec l'aide de la réflexion et en utilisant notre référence à l'objet. Tout est bon! Passons à un domaine privé.

Nous allons changer le nom du champ demandé en notre privéâgechamp:


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);
}

Nous n'avons pas accès via l'objet créé, essayez donc d'utiliser la réflexion. Nous obtenons une erreur :

IllegalAccessException

Nous obtenons une IllegalAccessException . Jetons un coup d'œil à ce qu'il y a à l'intérieur :

Essayons de comprendre.

Une exception IllegalAccessException est levée lorsqu'une application tente de créer de manière réflexive une instance (autre qu'un tableau), de définir ou d'obtenir un champ, ou d'invoquer une méthode, lorsque la méthode en cours d'exécution n'a pas accès à la définition de la classe, du champ, méthode ou constructeur.

Les méthodes ici lèvent également cette exception. Pour éviter cette exception, nous utiliserons une méthode spéciale pour accéder au champ privé.

setAccessible(drapeau booléen)

Cette méthode permet d'éviter les contrôles d'accès de sécurité pour un champ ou une classe. Nous pouvons transmettre true ou false à la méthode pour déterminer si des contrôles d'accès de sécurité seront effectués pour le champ. Essayons de corriger notre code :


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);
}

Regardons le résultat :

La valeur actuelle est 10

Super! Nous avons des informations sur notre classe. Essayons également de changer notre champ en lui attribuant une nouvelle valeur :


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);
}

Après avoir changé notre champ, nous obtenons :

La valeur actuelle est 19

Essayons d'appeler 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));
}

Après avoir restauré l'accessibilité à false , nous rencontrons à nouveau notre exception lorsque nous essayons d'appeler la méthode get :

Soyez donc prudent lorsque vous travaillez avec des champs privés et n'oubliez pas que la réflexion est un outil très puissant !