Clasa cu teren privat

Cu toții știți foarte bine despre modificatorii de acces la câmp. Și dacă un câmp are modificatorul privat , atunci nu îl putem accesa din exterior.


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

Să verificăm accesibilitatea în clasa noastră principală :


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

Nu avem acces lavârstăcâmp, dar avem reflecție. :) Și cu ajutorul lui, putem accesa și lucra cu domenii private.

Obținerea unui câmp privat de la un obiect folosind reflexia

Să obținem o matrice a tuturor câmpurilor din clasa noastră folosind metoda getDeclaredFields() . Returnează un obiect Field cu care putem lucra și modifica:


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

porecla publică de vârstă privată

În metoda getFieldNames , obținem două câmpuri din clasa noastră. Metoda getModifiers returnează modificatorul câmpului nostru, iar getName returnează numele acestuia. Acum să încercăm să modificăm și să accesăm acest câmp. Mai întâi, să încercăm să obținem date dintr-un câmp 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);
}
CodeGym
CodeGym

Putem accesa câmpul atât cu ajutorul reflecției, cât și folosind referința noastră la obiect. Totul e minunat! Să trecem la un domeniu privat.

Vom schimba numele câmpului solicitat în privatvârstăcamp:


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

Nu avem acces prin obiectul creat, așa că încercați să utilizați reflectarea. Primim o eroare:

IllegalAccessException

Primim o excepție IllegalAccessException . Să aruncăm o privire la ceea ce este înăuntru:

Să încercăm să ne dăm seama.

O excepție IllegalAccessException este lansată atunci când o aplicație încearcă să creeze reflexiv o instanță (alta decât o matrice), să seteze sau să obțină un câmp sau să invoce o metodă, atunci când metoda care se execută în prezent nu are acces la definiția clasei, câmpului specificat, metoda sau constructorul.

Metodele de aici aruncă și această excepție. Pentru a evita această excepție, vom folosi o metodă specială pentru a accesa câmpul privat.

setAccessible(steagul boolean)

Această metodă face posibilă evitarea verificărilor de acces de securitate pentru un câmp sau clasă. Putem trece adevărat sau fals metodei pentru a determina dacă se vor efectua verificări de acces de securitate pentru câmp. Să încercăm să ne reparăm codul:


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

Să ne uităm la rezultat:

Valoarea curentă este 10

Grozav! Am primit informații despre clasa noastră. Să încercăm, de asemenea, să ne schimbăm câmpul prin alocarea unei noi valori:


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

După ce ne schimbăm domeniul, obținem:

Valoarea curentă este 19

Să încercăm să apelăm 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));
}

După ce am restabilit accesibilitatea la false , întâlnim din nou excepția noastră când încercăm să apelăm metoda get :

Așa că aveți grijă când lucrați cu domenii private și nu uitați că reflecția este un instrument foarte puternic!