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.