Lesen des Werts von 'privaten' Feldern aus einer anderen Klasse in Java

1. Übersicht

In diesem kurzen Tutorial werden wir diskutieren, wie wir von einer anderen Klasse in Java auf den Wert eines privaten Feldes zugreifen können .

Bevor wir mit dem Tutorial beginnen, müssen wir verstehen, dass der Modifikator für den privaten Zugriff den versehentlichen Missbrauch von Feldern verhindert. Wenn wir jedoch darauf zugreifen möchten, können wir dies mithilfe der Reflection-API tun.

2. Beispiel

Definieren wir eine Beispielklasse Person mit einigen privaten Feldern:

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. Private Felder zugänglich machen

Um ein privates Feld zugänglich zu machen, müssen wir die Methode Field # setAccessible aufrufen :

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

Im obigen Beispiel geben wir zuerst das Feld an, das wir abrufen möchten - name - mithilfe der Methode Class # getDeclaredField . Dann machen wir das Feld mit nameField.setAccessible (true) zugänglich .

4. Zugriff auf private primitive Felder

Mit den Field # getXxx- Methoden können wir auf die privaten Felder zugreifen, die Grundelemente sind.

4.1. Zugriff auf ganzzahlige Felder

Wir können die Methoden getByte, getShort , getInt und getLong verwenden, um auf die Felder byte , short , int und long zuzugreifen :

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

Es ist auch möglich, Autoboxing mit primitiven Typen durchzuführen:

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

Die getXxx- Methoden für primitive Datentypen unterstützen auch die Erweiterung:

@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. Zugriff auf Floating Type-Felder

Um den Zugriff Schwimmer und Doppel Felder, müssen wir die verwenden getFloat und getDouble Methoden dargestellt:

@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. Zugriff auf Zeichenfelder

Um auf die Zeichenfelder zuzugreifen , können wir die Methode getChar verwenden:

@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. Zugriff auf Boolesche Felder

Ebenso können wir die getBoolean- Methode verwenden, um auf das boolesche Feld zuzugreifen :

@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. Zugriff auf private Felder, die Objekte sind

Mit der Field # get- Methode können wir auf die privaten Felder zugreifen , die Objekte sind . Es ist zu beachten, dass die generische get- Methode ein Objekt zurückgibt , daher müssen wir es in den Zieltyp umwandeln, um den Wert zu verwenden :

@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. Ausnahmen

Lassen Sie uns nun die Ausnahmen diskutieren, die die JVM beim Zugriff auf die privaten Felder auslösen kann .

6.1. IllegalArgumentException

Die JVM löst eine IllegalArgumentException aus , wenn wir einen getXxx- Accessor verwenden, der nicht mit dem Typ des Zielfelds kompatibel ist . Wenn wir in unserem Beispiel nameField.getInt (person) schreiben, löst die JVM diese Ausnahme aus, da das Feld vom Typ String und nicht vom Typ int oder Integer ist :

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

Wie wir bereits gesehen haben, unterstützen die getXxx- Methoden die Erweiterung für die primitiven Typen. Es ist wichtig zu beachten, dass wir das richtige Ziel für die Erweiterung angeben müssen, um erfolgreich zu sein . Andernfalls löst die JVM eine IllegalArgumentException aus :

@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

Die JVM löst eine IllegalAccessException aus, wenn wir versuchen, auf ein Feld zuzugreifen, das keine Zugriffsrechte hat . Wenn wir im obigen Beispiel die Anweisung nameField.setAccessible (true) nicht schreiben, löst die JVM die Ausnahme aus:

@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

Wenn wir versuchen, auf ein Feld zuzugreifen, das in der Person- Klasse nicht vorhanden ist , kann die JVM NoSuchFieldException auslösen :

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

6.4. NullPointerException

Schließlich löst die JVM erwartungsgemäß eine NullPointerException aus, wenn wir den Feldnamen als null übergeben :

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

7. Fazit

In diesem Tutorial haben wir gesehen, wie wir auf die privaten Felder einer Klasse in einer anderen Klasse zugreifen können . Wir haben auch die Ausnahmen gesehen, die die JVM auslösen kann, und was sie verursacht.

Wie immer ist der vollständige Code für dieses Beispiel auf GitHub verfügbar.