Клас с частно поле

Всички знаете много добре за модификаторите за достъп до полето. И ако едно поле има частен модификатор, тогава нямаме достъп до него отвън.


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

Нека проверим достъпността в нашия главен клас:


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

Нямаме достъп довъзрастполе, но имаме отражение. :) И с негова помощ можем да имаме достъп и да работим с частни полета.

Получаване на лично поле от обект чрез отражение

Нека получим масив от всички полета в нашия клас с помощта на метода getDeclaredFields() . Той връща обект Field , с който можем да работим и да го променяме:


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;
    }
частна възраст
публичен псевдоним

В метода getFieldNames получаваме две полета от нашия клас. Методът getModifiers връща модификатора на нашето поле, а getName връща името му. Сега нека се опитаме да променим и да получим достъп до това поле. Първо, нека се опитаме да получим данни от публично поле:


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

Можем да получим достъп до полето Howто с помощта на отражение, така и чрез нашата препратка към обекта. Всичко е страхотно! Да преминем към частно поле.

Ще променим името на поисканото поле на нашето личновъзрастполе:


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

Нямаме достъп чрез създадения обект, така че опитайте да използвате отражение. Получаваме грешка:

IllegalAccessException

Получаваме IllegalAccessException . Нека да надникнем Howво има вътре:

Нека се опитаме да го разберем.

Изключение IllegalAccessException се хвърля, когато приложение се опитва рефлективно да създаде екземпляр (различен от масив), да зададе or получи поле or да извика метод, когато текущо изпълняваният метод няма достъп до дефиницията на посочения клас, поле, метод or конструктор.

Методите тук също хвърлят това изключение. За да избегнем това изключение, ще използваме специален метод за достъп до частното поле.

setAccessible (булев флаг)

Този метод дава възможност да се избегнат проверките за достъп за сигурност за поле or клас. Можем да предадем true or false на метода, за да определим дали ще се извършват проверки за достъп за сигурност за полето. Нека се опитаме да коригираме нашия 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);
}

Да видим резултата:

Текущата стойност е 10

Страхотен! Получихме информация за нашия клас. Нека също опитаме да променим нашето поле, като му присвоим нова стойност:


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

След като променим нашето поле, получаваме:

Текущата стойност е 19

Нека опитаме да извикаме 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));
}

След като възстановим достъпността до false , отново се натъкваме на нашето изключение, когато се опитваме да извикаме метода get :

Така че бъдете внимателни, когато работите с частни полета и не забравяйте, че отражението е много мощен инструмент!