Klasa z polem prywatnym

Każdy z Was doskonale zna modyfikatory dostępu do pól. A jeśli pole ma modyfikator private , to nie będziemy mieli dostępu z zewnątrz.


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

Sprawdźmy dostępność w naszej Głównej :


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

Dostęp do polawiekmy nie, ale mamy refleksję. A za jego pomocą możemy uzyskać dostęp do prywatnych pól i pracować z nimi.

Uzyskiwanie prywatnego pola z obiektu poprzez odbicie

Pobierzmy tablicę wszystkich pól w naszej klasie za pomocą metody getDeclaredFileds() . Zwraca klasę Fileds , z którą będziemy pracować i dalej przekształcać:


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

pseudonim publiczny w wieku prywatnym

W metodzie getFieldNames otrzymujemy dwa pola z naszej klasy. Metoda getModifiers zwraca nasz modyfikator pola, a getName zwraca nazwę. Teraz spróbujmy zmodyfikować i uzyskać dostęp do tego pola. Najpierw spróbujmy uzyskać dane z pola publicznego:


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

Dostęp do pola mamy zarówno za pomocą refleksji, jak i za pomocą odniesienia do przedmiotu. Wszystko w porządku! Przechodzimy na prywatne pole.

Zmień nazwę pola, do którego chcemy trafić, na nasze pole prywatnewiek:


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

Nie mamy dostępu przez utworzoną instancję klasy, więc próbujemy przez refleksję i napotykamy błąd:

Wyjątek nielegalnego dostępu

Mamy wyjątek IllegalAccessException . Wejdźmy do środka i zobaczmy, co jest w środku:

Spróbujmy to rozgryźć.

Wyjątek IllegalAccessException jest generowany, gdy aplikacja próbuje refleksyjnie utworzyć instancję (inną niż tablica), ustawić lub pobrać pole lub wywołać metodę, ale aktualnie wykonywana metoda nie ma dostępu do definicji określonej klasy, pola, metoda lub konstruktor.

Istnieją również metody, które zgłaszają ten wyjątek. Aby uniknąć zgłaszania takiego wyjątku, użyjemy specjalnej metody dostępu do pola prywatnego.

setAccessible(flaga logiczna)

Ta metoda pozwala uniknąć sprawdzania dostępu do metody pola lub klasy ze względu na jej modyfikator dostępu. Do metody możemy przekazać parametr true lub false , który określi, czy potrzebujemy kontroli dostępu do pól. Spróbujmy naprawić nasz kod:


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

Spójrzmy na wynik:

Obecna wartość - 10

Świetnie, mamy dane naszej klasy. Spróbujmy jednocześnie zmienić nasze pole, ustawiając w nim nową wartość:


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

Próbujemy zmienić nasze pole i uzyskać wynik:

Obecna wartość - 19

Próbuję ustawić 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));
}

Po zwróceniu dostępu do false , ponownie napotykamy nasz wyjątek, gdy próbujemy wywołać metodę get :

Bądź więc ostrożny podczas pracy z polami prywatnymi i nie zapominaj, że odbicie jest bardzo potężnym narzędziem do pracy!