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

1. Oversigt

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

Før vi begynder med vejledningen, skal vi forstå, at privat adgangsmodifikator forhindrer utilsigtet misbrug af felter. Men hvis vi ønsker at få adgang til dem, kan vi gøre det ved hjælp af Reflection API.

2. Eksempel

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

offentlig klasseperson {privat String name = "John"; privat byte alder = 30; privat kort uidNumber = 5555; privat int pinCode = 452002; privat lang kontaktNummer = 123456789L; privat flydehøjde = 6.1242f; privat dobbeltvægt = 75,2564; privat char kønn = 'M'; privat boolsk aktiv = sand; // getters og setters}

3. Making privat Marker tilgængelige

At lave nogen privat tilgængelig i marken, vi er nødt til at kalde Felt # sætTilgængelig metode:

Person person = ny person (); Field nameField = person.getClass (). GetDeclaredField ("navn"); nameField.setAccessible (true);

I ovenstående eksempel specificerer vi først det felt, som vi vil hente - navn - ved hjælp af Klasse # getDeclaredField metode. Derefter gør vi feltet tilgængeligt ved hjælp af nameField.setAccessible (true).

4. Adgang privat Primitive felter

Vi kan få adgang til privat felter, der er primitive ved hjælp af Felt # getXxx metoder.

4.1. Adgang til helhedsfelter

Vi kan bruge getByte,getShort, getIntog getLong metoder til at få adgang til byte,kort, intog lang felter, henholdsvis:

@Test offentlig ugyldig nårGetIntegerFields_thenSuccess () kaster undtagelse {Person person = ny person (); Field ageField = person.getClass (). GetDeclaredField ("age"); ageField.setAccessible (true); byte alder = ageField.getByte (person); Assertions.assertEquals (30, alder); Felt uidNumberField = person.getClass (). GetDeclaredField ("uidNumber"); uidNumberField.setAccessible (true); kort uidNumber = uidNumberField.getShort (person); Assertions.assertEquals (5555, uidNumber); Felt pinCodeField = person.getClass (). GetDeclaredField ("pinCode"); pinCodeField.setAccessible (sand); int pinCode = pinCodeField.getInt (person); Assertions.assertEquals (452002, pinCode); Felt contactNumberField = person.getClass (). GetDeclaredField ("contactNumber"); contactNumberField.setAccessible (sand); lang contactNumber = contactNumberField.getLong (person); Assertions.assertEquals (123456789L, contactNumber); }

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

@Test offentlig ugyldig nårDoAutoboxing_thenSuccess () kaster undtagelse {Person person = ny person (); Felt pinCodeField = person.getClass (). GetDeclaredField ("pinCode"); pinCodeField.setAccessible (true); Heltal pinCode = pinCodeField.getInt (person); Assertions.assertEquals (452002, pinCode); }

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

@Test offentlig ugyldig nårDoWidening_thenSuccess () kaster Undtagelse {Person person = ny person (); Felt pinCodeField = person.getClass (). GetDeclaredField ("pinCode"); pinCodeField.setAccessible (true); Lang pinCode = pinCodeField.getLong (person); Assertions.assertEquals (452002L, pinCode); }

4.2. Adgang til flydende typefelter

Adgang flyde og dobbelt felter, skal vi bruge getFloat og getDouble metoder henholdsvis:

@Test offentlig ugyldig nårGetFloatingTypeFields_thenSuccess () kaster undtagelse {Person person = ny person (); Field heightField = person.getClass (). GetDeclaredField ("højde"); heightField.setAccessible (true); flydehøjde = højdeFelt.getFloat (person); Assertions.assertEquals (6.1242f, højde); Field weightField = person.getClass (). GetDeclaredField ("vægt"); weightField.setAccessible (true); dobbeltvægt = weightField.getDouble (person); Assertions.assertEquals (75.2564, vægt); }

4.3. Adgang til tegnfelter

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

@Test offentlig ugyldig nårGetCharacterFields_thenSuccess () kaster Undtagelse {Person person = ny person (); Felt genderField = person.getClass (). GetDeclaredField ("køn"); genderField.setAccessible (true); char køn = genderField.getChar (person); Assertions.assertEquals ('M', køn); }

4.4. Adgang til boolske felter

På samme måde kan vi bruge getBoolean metode til at få adgang til boolsk Mark:

@Test offentlig ugyldig nårGetBooleanFields_thenSuccess () kaster undtagelse {Person person = ny person (); Felt activeField = person.getClass (). GetDeclaredField ("aktiv"); activeField.setAccessible (true); boolsk aktiv = activeField.getBoolean (person); Assertions.assertTrue (aktiv); }

5. Adgang privat Felter, der er genstande

Vi kan få adgang til privat felter, der er objekter ved hjælp af Felt # få metode. Det er at bemærke, at den generiske metode returnerer en Objekt, så vi bliver nødt til at kaste det til måltypen for at gøre brug af værdien:

@Test offentlig ugyldig nårGetObjectFields_thenSuccess () kaster undtagelse {Person person = ny person (); Field nameField = person.getClass (). GetDeclaredField ("navn"); nameField.setAccessible (true); String name = (String) nameField.get (person); Assertions.assertEquals ("John", navn); }

6. Undtagelser

Lad os nu diskutere de undtagelser, som JVM kan kaste, mens de får adgang til privat felter.

6.1. IllegalArgumentException

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

@Test offentlig ugyldighed givenInt_whenSetStringField_thenIllegalArgumentException () kaster Undtagelse {Person person = ny person (); Field nameField = person.getClass (). GetDeclaredField ("navn"); 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 det Vi er nødt til at give det korrekte mål for udvidelse for at blive en succes. Ellers kaster JVM en IllegalArgumentException:

@Test offentlig ugyldighed givenInt_whenGetLongField_thenIllegalArgumentException () kaster Undtagelse {Person person = ny person (); Felt contactNumberField = person.getClass (). GetDeclaredField ("contactNumber"); contactNumberField.setAccessible (sand); Assertions.assertThrows (IllegalArgumentException.class, () -> contactNumberField.getInt (person)); }

6.2. Ulovlig adgangsundtagelse

JVM vil kaste en Ulovlig adgangsundtagelsehvis vi prøver at få adgang til et felt, der ikke har adgangsrettigheder. I ovenstående eksempel, hvis vi ikke skriver udsagnet nameField.setAccessible (true), så kaster JVM undtagelsen:

@Test offentlig ugyldig nårFieldNotSetAccessible_thenIllegalAccessException () kaster undtagelse {Person person = ny person (); Field nameField = person.getClass (). GetDeclaredField ("navn"); Assertions.assertThrows (IllegalAccessException.class, () -> nameField.get (person)); }

6.3. NoSuchFieldException

Hvis vi prøver at få adgang til et felt, der ikke findes i Person klasse, så kunne JVM kaste NoSuchFieldException:

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

6.4. NullPointerException

Endelig, som du forventer, kaster JVM en NullPointerExceptionhvis vi videregiver feltnavnet som nul:

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

7. Konklusion

I denne vejledning har vi set, hvordan vi kan få adgang til privat 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.