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から入手できます。