Membaca Nilai Bidang 'peribadi' dari Kelas yang berbeza di Jawa

1. Gambaran keseluruhan

Dalam tutorial ringkas ini, kita akan membincangkan bagaimana kita dapat mengakses nilai bidang peribadi dari kelas yang berlainan di Java.

Sebelum memulakan tutorial, kita perlu memahami bahawa pengubah akses peribadi mencegah penyalahgunaan medan secara tidak sengaja. Namun, jika kita ingin mengaksesnya, kita dapat melakukannya dengan menggunakan Reflection API.

2. Contoh

Mari tentukan sampel kelas Orang dengan beberapa bidang peribadi :

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. Menjadikan Padang Persendirian Boleh Diakses

Untuk menjadikan bidang peribadi boleh diakses, kita harus memanggil kaedah Field # setAccessible :

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

Dalam contoh di atas, pertama-tama kita tentukan bidang yang ingin kita ambil - name - dengan menggunakan kaedah Class # getDeclaredField . Kemudian kami menjadikan medan dapat diakses menggunakan nameField.setAccessible (true) .

4. Mengakses Medan Primitif swasta

Kita boleh mengakses bidang peribadi yang primitif dengan menggunakan kaedah Field # getXxx .

4.1. Mengakses Medan Integer

Kita boleh menggunakan kaedah getByte, getShort , getInt , dan getLong untuk mengakses medan bait , pendek , int , dan panjang masing-masing:

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

Anda juga boleh melakukan autoboxing dengan jenis primitif:

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

The getXxx kaedah untuk jenis data primitif juga menyokong pelebaran:

@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. Mengakses Medan Jenis Terapung

Untuk mengakses medan terapung dan berganda , kita perlu menggunakan kaedah getFloat dan getDouble , masing-masing:

@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. Mengakses Bidang Perwatakan

Untuk mengakses medan char , kita dapat menggunakan kaedah 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. Mengakses Boolean Fields

Begitu juga, kita boleh menggunakan kaedah getBoolean untuk mengakses medan 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. Mengakses Medan Persendirian Yang Merupakan Objek

Kita boleh mengakses swasta bidang yang objek dengan menggunakan # get Field kaedah . Perlu diperhatikan bahawa kaedah get generik mengembalikan Objek , jadi kita perlu memasukkannya ke jenis sasaran untuk memanfaatkan nilai :

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

Sekarang, mari kita bincangkan pengecualian yang dapat dilemparkan oleh JVM semasa mengakses medan peribadi .

6.1. PengecualianArgumentElegal

JVM akan membuang IllegalArgumentException jika kita menggunakan aksesori getXxx yang tidak sesuai dengan jenis medan sasaran . Dalam contoh kami, jika kami menulis namaField.getInt (orang) , JVM membuang pengecualian ini kerana bidangnya adalah jenis String dan bukan int atau Integer :

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

Seperti yang telah kita lihat, kaedah getXxx menyokong pelebaran untuk jenis primitif. Penting untuk diperhatikan bahawa kita perlu memberikan sasaran yang betul agar pelebaran berjaya . Jika tidak, JVM melemparkan 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. Pengecualian Tidak Sah

JVM akan melemparkan IllegalAccessException jika kita cuba mengakses medan yang tidak mempunyai hak akses . Dalam contoh di atas, jika kita tidak menulis nama pernyataanField.setAccessible (benar) , maka JVM membuang pengecualian:

@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

Sekiranya kita cuba mengakses medan yang tidak ada di kelas Person , maka JVM boleh membuang NoSuchFieldException :

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

6.4. NullPointerException

Akhirnya, seperti yang anda jangkakan, JVM melemparkan NullPointerException jika kami memberikan nama bidang sebagai nol :

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

7. Kesimpulannya

Dalam tutorial ini, kita telah melihat bagaimana kita dapat mengakses bidang peribadi kelas di kelas lain. Kami juga melihat pengecualian yang boleh dilemparkan JVM dan apa yang menyebabkannya.

Seperti biasa, kod lengkap untuk contoh ini terdapat di GitHub.