De waarde van ‘privé’ velden uit een andere klasse in Java lezen

1. Overzicht

In deze korte tutorial bespreken we hoe we toegang kunnen krijgen tot de waarde van a privaat veld uit een andere klasse in Java.

Voordat we met de zelfstudie beginnen, moeten we begrijpen dat de privaat access modifier voorkomt het onbedoeld misbruik van velden. Als we er echter toegang toe willen hebben, kunnen we dit doen door de Reflection API te gebruiken.

2. Voorbeeld

Laten we een voorbeeldklasse definiëren Persoon met wat privaat velden:

openbare klasse Persoon {private String name = "John"; leeftijd van privé-bytes = 30; privé kort uidNumber = 5555; privé int pinCode = 452002; privé lang contactNumber = 123456789L; privé vlotterhoogte = 6.1242f; dubbel privégewicht = 75,2564; privé char geslacht = 'M'; private boolean active = true; // getters en setters}

3. Maken privaat Velden toegankelijk

Om er een te maken privaat veld toegankelijk, we moeten de Veld # setAccessible methode:

Persoon persoon = nieuwe persoon (); Veld nameField = person.getClass (). GetDeclaredField ("naam"); nameField.setAccessible (true);

In het bovenstaande voorbeeld specificeren we eerst het veld dat we willen ophalen - naam - door de Klasse # getDeclaredField methode. Vervolgens maken we het veld toegankelijk met nameField.setAccessible (true).

4. Toegang privaat Primitieve velden

Wij kunnen Toegang krijgen tot privaat velden die primitief zijn door de Veld # getXxx methoden.

4.1. Toegang tot Integer-velden

We kunnen de getByte,getShort, getInt, en getLong methoden om toegang te krijgen tot het byte,kort, int, en lang velden, respectievelijk:

@Test openbare leegte whenGetIntegerFields_thenSuccess () gooit Uitzondering {Persoon persoon = nieuwe persoon (); Veld ageField = person.getClass (). GetDeclaredField ("leeftijd"); ageField.setAccessible (true); byte age = ageField.getByte (persoon); Assertions.assertEquals (30, leeftijd); Veld uidNumberField = person.getClass (). GetDeclaredField ("uidNumber"); uidNumberField.setAccessible (true); korte uidNumber = uidNumberField.getShort (persoon); Assertions.assertEquals (5555, uidNumber); Veld pinCodeField = person.getClass (). GetDeclaredField ("pinCode"); pinCodeField.setAccessible (true); int pinCode = pinCodeField.getInt (persoon); Assertions.assertEquals (452002, pinCode); Veld contactNumberField = person.getClass (). GetDeclaredField ("contactNumber"); contactNumberField.setAccessible (true); lang contactNumber = contactNumberField.getLong (persoon); Assertions.assertEquals (123456789L, contactNumber); }

Het is ook mogelijk om autoboxen uit te voeren met primitieve typen:

@Test openbare leegte whenDoAutoboxing_thenSuccess () gooit uitzondering {Persoon person = nieuwe persoon (); Veld pinCodeField = person.getClass (). GetDeclaredField ("pinCode"); pinCodeField.setAccessible (true); Geheel getal pinCode = pinCodeField.getInt (persoon); Assertions.assertEquals (452002, pinCode); }

De getXxx methoden voor primitieve gegevenstypen ondersteunen ook verbreding:

@Test openbare leegte whenDoWidening_thenSuccess () gooit Uitzondering {Persoon persoon = nieuwe persoon (); Veld pinCodeField = person.getClass (). GetDeclaredField ("pinCode"); pinCodeField.setAccessible (true); Lange pinCode = pinCodeField.getLong (persoon); Assertions.assertEquals (452002L, pinCode); }

4.2. Toegang tot zwevende typevelden

Om toegang te krijgen vlotter en dubbele velden, moeten we de getFloat en getDouble methoden, respectievelijk:

@Test openbare leegte whenGetFloatingTypeFields_thenSuccess () gooit Uitzondering {Persoon person = nieuwe Persoon (); Veld heightField = person.getClass (). GetDeclaredField ("hoogte"); heightField.setAccessible (true); zwevende hoogte = hoogteField.getFloat (persoon); Assertions.assertEquals (6.1242f, hoogte); Veld weightField = person.getClass (). GetDeclaredField ("gewicht"); weightField.setAccessible (true); dubbel gewicht = weightField.getDouble (persoon); Assertions.assertEquals (75.2564, gewicht); }

4.3. Toegang tot tekenvelden

Om toegang te krijgen tot het char velden, kunnen we de getChar methode:

@Test openbare leegte whenGetCharacterFields_thenSuccess () gooit Uitzondering {Persoon persoon = nieuwe persoon (); Veld genderField = person.getClass (). GetDeclaredField ("geslacht"); genderField.setAccessible (true); char gender = genderField.getChar (persoon); Assertions.assertEquals ('M', geslacht); }

4.4. Toegang tot Booleaanse velden

Evenzo kunnen we de getBoolean methode om toegang te krijgen tot het boolean veld:

@Test openbare leegte whenGetBooleanFields_thenSuccess () gooit Uitzondering {Persoon persoon = nieuwe persoon (); Veld activeField = person.getClass (). GetDeclaredField ("actief"); activeField.setAccessible (true); boolean active = activeField.getBoolean (persoon); Assertions.assertTrue (actief); }

5. Toegang privaat Velden die objecten zijn

Wij kunnen Toegang krijgen tot privaat velden die objecten zijn met behulp van de Veld # get methode. Het is op te merken dat de generieke krijgen methode geeft een Voorwerp, dus we moeten het naar het doeltype casten om de waarde te gebruiken:

@Test openbare leegte whenGetObjectFields_thenSuccess () gooit Uitzondering {Persoon persoon = nieuwe persoon (); Veld nameField = person.getClass (). GetDeclaredField ("naam"); nameField.setAccessible (true); String name = (String) nameField.get (persoon); Assertions.assertEquals ("John", naam); }

6. Uitzonderingen

Laten we nu de uitzonderingen bespreken die de JVM kan gooien bij het openen van het privaat velden.

6.1. IllegalArgumentException

De JVM zal gooien IllegalArgumentExceptionals we een getXxx accessor die niet compatibel is met het type van het doelveld. Als we in ons voorbeeld schrijven nameField.getInt (persoon), genereert de JVM deze uitzondering omdat het veld van het type is Draad en niet int of Geheel getal:

@ Test openbare ongeldige gegevenInt_whenSetStringField_thenIllegalArgumentException () gooit Uitzondering {Persoon persoon = nieuwe Persoon (); Veld nameField = person.getClass (). GetDeclaredField ("naam"); nameField.setAccessible (true); Assertions.assertThrows (IllegalArgumentException.class, () -> nameField.getInt (persoon)); }

Zoals we al hebben gezien, is de getXxx methoden ondersteunen verbreding voor de primitieve typen. Het is belangrijk om dat op te merken we moeten het juiste doelwit geven om verbreding succesvol te laten zijn. Anders gooit de JVM een IllegalArgumentException:

@ Test openbare ongeldige gegevenInt_whenGetLongField_thenIllegalArgumentException () gooit Uitzondering {Persoon persoon = nieuwe Persoon (); Veld contactNumberField = person.getClass (). GetDeclaredField ("contactNumber"); contactNumberField.setAccessible (true); Assertions.assertThrows (IllegalArgumentException.class, () -> contactNumberField.getInt (persoon)); }

6.2. IllegalAccessException

De JVM gooit een IllegalAccessExceptionals we proberen toegang te krijgen tot een veld dat geen toegangsrechten heeft. In het bovenstaande voorbeeld, als we de verklaring niet schrijven nameField.setAccessible (true), dan gooit de JVM de uitzondering:

@Test openbare leegte whenFieldNotSetAccessible_thenIllegalAccessException () gooit Uitzondering {Persoon persoon = nieuwe persoon (); Veld nameField = person.getClass (). GetDeclaredField ("naam"); Assertions.assertThrows (IllegalAccessException.class, () -> nameField.get (persoon)); }

6.3. NoSuchFieldException

Als we proberen toegang te krijgen tot een veld dat niet bestaat in de Persoon klasse, dan zou de JVM kunnen gooien NoSuchFieldException:

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

6.4. NullPointerException

Eindelijk, zoals je zou verwachten, gooit de JVM een NullPointerExceptionals we de veldnaam doorgeven als nul:

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

7. Conclusie

In deze zelfstudie hebben we gezien hoe we toegang kunnen krijgen tot het privaat velden van een klasse in een andere klasse. We hebben ook de uitzonderingen gezien die de JVM kan gooien en waardoor ze worden veroorzaakt.

Zoals altijd is de volledige code voor dit voorbeeld beschikbaar op GitHub.