Java >> Java tutorial >  >> Tag >> private

Læsning af værdien af ​​'private' felter fra en anden klasse i Java

1. Oversigt

I denne hurtige selvstudie vil vi diskutere, hvordan vi kan få adgang til værdien af ​​en privat felt fra en anden klasse i Java.

Før vi starter med selvstudiet, skal vi forstå, at den private adgangsmodifikator forhindrer utilsigtet misbrug af felter. Men hvis vi ønsker at få adgang til dem, kan vi gøre det ved at bruge Reflection API.

2. Eksempel

Lad os definere en prøveklasse Person med nogle private felter:

public class Person {

    private String name = "John";
    private byte age = 30;
    private short uidNumber = 5555;
    private int pinCode = 452002;
    private long contactNumber = 123456789L;
    private float height = 6.1242f;
    private double weight = 75.2564;
    private char gender = 'M';
    private boolean active = true;

    // getters and setters
}

3. Gør privat Tilgængelige felter

For at gøre enhver privat felt tilgængeligt, vi er nødt til at kalde Field#setAccessible metode:

Person person = new Person(); 
Field nameField = person.getClass().getDeclaredField("name"); 
nameField.setAccessible(true);

I ovenstående eksempel angiver vi først det felt, som vi ønsker at hente – navn – ved at bruge Class#getDeclaredField metode. Derefter gør vi feltet tilgængeligt ved hjælp af nameField.setAccessible(true) .

4. Adgang til privat Primitive felter

Vi kan få adgang til den private felter, der er primitive ved at bruge Felt#getXxx metoder.

4.1. Adgang til heltalsfelter

Vi kan bruge getByte, getShort , getInt , og getLong metoder til at få adgang til byten , kort , int , og lang felter, henholdsvis:

@Test
public void whenGetIntegerFields_thenSuccess() 
  throws Exception {
    Person person = new Person();

    Field ageField = person.getClass().getDeclaredField("age");
    ageField.setAccessible(true);

    byte age = ageField.getByte(person);
    Assertions.assertEquals(30, age);

    Field uidNumberField = person.getClass().getDeclaredField("uidNumber");
    uidNumberField.setAccessible(true);

    short uidNumber = uidNumberField.getShort(person);
    Assertions.assertEquals(5555, uidNumber);

    Field pinCodeField = person.getClass().getDeclaredField("pinCode");
    pinCodeField.setAccessible(true);

    int pinCode = pinCodeField.getInt(person);
    Assertions.assertEquals(452002, pinCode);

    Field contactNumberField = person.getClass().getDeclaredField("contactNumber");
    contactNumberField.setAccessible(true);

    long contactNumber = contactNumberField.getLong(person);
    Assertions.assertEquals(123456789L, contactNumber);
}

Det er også muligt at udføre autoboxing med primitive typer:

@Test
public void whenDoAutoboxing_thenSuccess() 
  throws Exception {
    Person person = new Person();

    Field pinCodeField = person.getClass().getDeclaredField("pinCode");
    pinCodeField.setAccessible(true);

    Integer pinCode = pinCodeField.getInt(person);
    Assertions.assertEquals(452002, pinCode);
}

getXxx metoder til primitive datatyper understøtter også udvidelse:

@Test
public void whenDoWidening_thenSuccess() 
  throws Exception {
    Person person = new Person();

    Field pinCodeField = person.getClass().getDeclaredField("pinCode");
    pinCodeField.setAccessible(true);

    Long pinCode = pinCodeField.getLong(person);
    Assertions.assertEquals(452002L, pinCode);
}

4.2. Adgang til flydende typefelter

For at få adgang til float og dobbelt felter, skal vi bruge getFloat og getDouble metoder, henholdsvis:

@Test
public void whenGetFloatingTypeFields_thenSuccess() 
  throws Exception {
    Person person = new Person();

    Field heightField = person.getClass().getDeclaredField("height");
    heightField.setAccessible(true);

    float height = heightField.getFloat(person);
    Assertions.assertEquals(6.1242f, height);
    
    Field weightField = person.getClass().getDeclaredField("weight");
    weightField.setAccessible(true);

    double weight = weightField.getDouble(person);
    Assertions.assertEquals(75.2564, weight);
}

4.3. Adgang til tegnfelter

For at få adgang til char felter, kan vi bruge getChar metode:

@Test
public void whenGetCharacterFields_thenSuccess() 
  throws Exception {
    Person person = new Person();

    Field genderField = person.getClass().getDeclaredField("gender");
    genderField.setAccessible(true);

    char gender = genderField.getChar(person);
    Assertions.assertEquals('M', gender);
}

4.4. Adgang til booleske felter

På samme måde kan vi bruge getBoolean metode til at få adgang til boolesk felt:

@Test
public void whenGetBooleanFields_thenSuccess() 
  throws Exception {
    Person person = new Person();

    Field activeField = person.getClass().getDeclaredField("active");
    activeField.setAccessible(true);

    boolean active = activeField.getBoolean(person);
    Assertions.assertTrue(active);
}

5. Adgang til privat Felter, der er objekter

Vi kan få adgang til den private felter, der er objekter ved at bruge Field#get metode . Det er at bemærke, at den generiske get metode returnerer et objekt , så vi bliver nødt til at caste den til måltypen for at gøre brug af værdien :

@Test
public void whenGetObjectFields_thenSuccess() 
  throws Exception {
    Person person = new Person();

    Field nameField = person.getClass().getDeclaredField("name");
    nameField.setAccessible(true);

    String name = (String) nameField.get(person);
    Assertions.assertEquals("John", name);
}

6. Undtagelser

Lad os nu diskutere de undtagelser, som JVM'en kan give, mens den får adgang til den private felter.

6.1. IllegalArgumentException

JVM'et vil kaste IllegalArgumentException hvis vi bruger en getXxx accessor, der er inkompatibel med målfeltets type . I vores eksempel, hvis vi skriver nameField.getInt(person) , kaster JVM denne undtagelse, da feltet er af typen String og ikke int eller Heltal :

@Test
public void givenInt_whenSetStringField_thenIllegalArgumentException() 
  throws Exception {
    Person person = new Person();
    Field nameField = person.getClass().getDeclaredField("name");
    nameField.setAccessible(true);

    Assertions.assertThrows(IllegalArgumentException.class, () -> nameField.getInt(person));
}

Som vi allerede har set, er getXxx metoder understøtter udvidelse for de primitive typer. Det er vigtigt at bemærke, at vi er nødt til at angive det korrekte mål, for at udvidelsen kan lykkes . Ellers kaster JVM en IllegalArgumentException :

@Test
public void givenInt_whenGetLongField_thenIllegalArgumentException() 
  throws Exception {
    Person person = new Person();
    Field contactNumberField = person.getClass().getDeclaredField("contactNumber");
    contactNumberField.setAccessible(true);

    Assertions.assertThrows(IllegalArgumentException.class, () -> contactNumberField.getInt(person));
}

6.2. IllegalAccessException

JVM'et vil kaste en IllegalAccessException hvis vi forsøger at få adgang til et felt, der ikke har adgangsrettigheder . I ovenstående eksempel, hvis vi ikke skriver sætningen nameField.setAccessible(true) , så kaster JVM undtagelsen:

@Test
public void whenFieldNotSetAccessible_thenIllegalAccessException() 
  throws Exception {
    Person person = new Person();
    Field nameField = person.getClass().getDeclaredField("name");

    Assertions.assertThrows(IllegalAccessException.class, () -> nameField.get(person));
}

6.3. NoSuchFieldException

Hvis vi forsøger at få adgang til et felt, der ikke eksisterer i Person klasse, så kunne JVM'et kaste NoSuchFieldException :

Assertions.assertThrows(NoSuchFieldException.class,
  () -> person.getClass().getDeclaredField("firstName"));

6.4. NullPointerException

Endelig, som du ville forvente, kaster JVM en NullPointerException hvis vi sender feltnavnet som null :

Assertions.assertThrows(NullPointerException.class,
  () -> person.getClass().getDeclaredField(null));

7. Konklusion

I denne vejledning har vi set, hvordan vi kan få adgang til den private felter i en klasse i en anden klasse. Vi har også set de undtagelser, som JVM kan kaste, og hvad der forårsager dem.

Som altid er den komplette kode til dette eksempel tilgængelig på GitHub.


Java tag