Javaの別のクラスからの「プライベート」フィールドの値の読み取り
1. 概要
このクイックチュートリアルでは、Javaの別のクラスからprivateフィールドの値にアクセスする方法について説明します。
チュートリアルを開始する前に、privateアクセス修飾子がフィールドの偶発的な誤用を防ぐことを理解する必要があります。 ただし、それらにアクセスしたい場合は、 ReflectionAPIを使用してアクセスできます。
2. 例
いくつかのprivateフィールドを使用してサンプルクラスPersonを定義しましょう。
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 フィールドにアクセスできるようにするには、 Field#setAccessibleメソッドを呼び出す必要があります:
Person person = new Person();
Field nameField = person.getClass().getDeclaredField("name");
nameField.setAccessible(true);
上記の例では、最初に Class#getDeclaredField メソッドを使用して、取得するフィールド– name –を指定します。 次に、 nameField.setAccessible(true)を使用してフィールドにアクセスできるようにします。
4. プライベートプリミティブフィールドへのアクセス
Field#getXxxメソッドを使用して、プリミティブであるプライベートフィールドにアクセスできます。
4.1. 整数フィールドへのアクセス
getByte、 getShort 、 getInt 、および getLong メソッドを使用して、 byteにアクセスできます。 、 short 、 int 、および longフィールド。
@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);
}
プリミティブ型を使用してオートボクシングを実行することもできます。
@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メソッドは、wideningもサポートします。
@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. フローティングタイプフィールドへのアクセス
floatおよびdoubleフィールドにアクセスするには、それぞれgetFloatおよびgetDoubleメソッドを使用する必要があります。
@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. 文字フィールドへのアクセス
char フィールドにアクセスするには、getCharメソッドを使用できます。
@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. ブールフィールドへのアクセス
同様に、 getBoolean メソッドを使用して、booleanフィールドにアクセスできます。
@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. オブジェクトであるprivateフィールドへのアクセス
Field#getメソッドを使用して、オブジェクトであるプライベートフィールドにアクセスできます。 一般的なgetメソッドはオブジェクトを返すため、値を使用するには、オブジェクトをターゲットタイプにキャストする必要があることに注意してください。
@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. 例外
次に、privateフィールドにアクセスしているときにJVMがスローする可能性のある例外について説明します。
6.1. IllegalArgumentException
ターゲットフィールドのタイプと互換性のないgetXxxアクセサーを使用すると、JVMは IllegalArgumentExceptionをスローします。 この例では、 nameField.getInt(person)と書くと、フィールドのタイプが String であり、 int またはではないため、JVMはこの例外をスローします。 ]整数:
@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));
}
すでに見てきたように、 getXxx メソッドは、プリミティブ型の拡張をサポートしています。 拡大を成功させるには、正しいターゲットを提供する必要があることに注意することが重要です。 それ以外の場合、JVMは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は IllegalAccessExceptionをスローします。 上記の例では、ステートメント nameField.setAccessible(true)を記述しない場合、JVMは例外をスローします。
@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
Person クラスに存在しないフィールドにアクセスしようとすると、JVMはNoSuchFieldExceptionをスローする可能性があります。
Assertions.assertThrows(NoSuchFieldException.class,
() -> person.getClass().getDeclaredField("firstName"));
6.4. NullPointerException
最後に、ご想像のとおり、フィールド名をnull として渡すと、JVMは NullPointerExceptionをスローします。
Assertions.assertThrows(NullPointerException.class,
() -> person.getClass().getDeclaredField(null));
7. 結論
このチュートリアルでは、別のクラスのクラスのprivateフィールドにアクセスする方法を説明しました。 また、JVMがスローできる例外とその原因も確認しました。
いつものように、この例の完全なコードは、GitHubでから入手できます。