Klass med privat fält

Ni vet alla mycket väl om fältåtkomstmodifierare. Och om ett fält har den privata modifieraren kan vi inte komma åt det från utsidan.


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

Låt oss kontrollera tillgängligheten i vår huvudklass :


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

Vi har inte tillgång tillålderfältet, men vi har reflektion. :) Och med dess hjälp kan vi komma åt och arbeta med privata fält.

Få ett privat fält från ett objekt med hjälp av reflektion

Låt oss få en array av alla fält i vår klass med metoden getDeclaredFields() . Det returnerar ett Field -objekt som vi kan arbeta med och modifiera:


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;
    }
privat ålder
offentligt smeknamn

I metoden getFieldNames får vi två fält från vår klass. Metoden getModifiers returnerar vårt fälts modifierare och getName returnerar dess namn. Låt oss nu försöka ändra och komma åt detta fält. Låt oss först försöka få data från ett offentligt fält:


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

Vi kan komma åt fältet både med hjälp av reflektion och med hjälp av vår referens till objektet. Allt är bra! Låt oss gå vidare till ett privat område.

Vi kommer att ändra namnet på det begärda fältet till vårt privataålderfält:


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

Vi har inte tillgång via det skapade objektet, så försök använda reflektion. Vi får ett felmeddelande:

IllegalAccessException

Vi får ett IllegalAccessException . Låt oss ta en titt på vad som finns inuti:

Låt oss försöka lista ut det.

En IllegalAccessException kastas när en applikation reflekterande försöker skapa en instans (annan än en array), sätta eller hämta ett fält, eller anropa en metod, när den för närvarande exekverande metoden inte har tillgång till definitionen av den angivna klassen, fältet, metod eller konstruktör.

Metoderna här kastar också detta undantag. För att undvika detta undantag kommer vi att använda en speciell metod för att komma åt det privata fältet.

setAccessible(boolesk flagga)

Denna metod gör det möjligt att undvika säkerhetskontroller för ett fält eller en klass. Vi kan skicka sant eller falskt till metoden för att avgöra om säkerhetskontroller kommer att utföras för fältet. Låt oss försöka fixa vår 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);
}

Låt oss titta på resultatet:

Det aktuella värdet är 10

Bra! Vi fick information om vår klass. Låt oss också försöka ändra vårt fält genom att tilldela det ett nytt värde:


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

Efter att ha bytt fält får vi:

Nuvarande värde är 19

Låt oss försöka anropa 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));
}

Efter att ha återställt tillgängligheten till false stöter vi på vårt undantag igen när vi försöker anropa get -metoden:

Så var försiktig när du arbetar med privata områden, och glöm inte att reflektion är ett mycket kraftfullt verktyg!