Classe con un campo privato

Conoscete tutti molto bene i modificatori di accesso al campo. E se un campo ha il modificatore privato , non possiamo accedervi dall'esterno.


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

Controlliamo l'accessibilità nella nostra classe principale :


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

Non abbiamo accesso aletàcampo, ma abbiamo la riflessione. :) E con il suo aiuto, possiamo accedere e lavorare con campi privati.

Ottenere un campo privato da un oggetto usando la riflessione

Prendiamo un array di tutti i campi nella nostra classe usando il metodo getDeclaredFields() . Restituisce un oggetto Field con cui possiamo lavorare e modificare:


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

soprannome pubblico dell'età privata

Nel metodo getFieldNames , otteniamo due campi dalla nostra classe. Il metodo getModifiers restituisce il modificatore del nostro campo e getName restituisce il suo nome. Ora proviamo a modificare ed accedere a questo campo. Innanzitutto, proviamo a ottenere dati da un campo pubblico:


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

Possiamo accedere al campo sia con l'aiuto della riflessione sia usando il nostro riferimento all'oggetto. È tutto bellissimo! Passiamo a un campo privato.

Cambieremo il nome del campo richiesto in privatoetàcampo:


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

Non abbiamo accesso tramite l'oggetto creato, quindi prova a utilizzare la riflessione. Otteniamo un errore:

IllegalAccessException

Otteniamo un IllegalAccessException . Diamo un'occhiata a cosa c'è dentro:

Proviamo a capirlo.

Un'eccezione IllegalAccessException viene generata quando un'applicazione tenta di creare in modo riflessivo un'istanza (diversa da un array), impostare o ottenere un campo o richiamare un metodo, quando il metodo attualmente in esecuzione non ha accesso alla definizione della classe specificata, campo, metodo o costruttore.

Anche i metodi qui generano questa eccezione. Per evitare questa eccezione, utilizzeremo un metodo speciale per accedere al campo privato.

setAccessibile(flag booleano)

Questo metodo consente di evitare i controlli di accesso di sicurezza per un campo o una classe. Possiamo passare true o false al metodo per determinare se verranno eseguiti i controlli di accesso di sicurezza per il campo. Proviamo a correggere il nostro codice:


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

Diamo un'occhiata al risultato:

Il valore attuale è 10

Grande! Abbiamo informazioni sulla nostra classe. Proviamo anche a modificare il nostro campo assegnandogli un nuovo valore:


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

Dopo aver modificato il nostro campo, otteniamo:

Il valore attuale è 19

Proviamo a chiamare 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));
}

Dopo aver ripristinato l'accessibilità a false , ci imbattiamo nuovamente nella nostra eccezione quando proviamo a chiamare il metodo get :

Quindi fai attenzione quando lavori con campi privati ​​e non dimenticare che la riflessione è uno strumento molto potente!