帶有私有字段的類
你們都非常了解字段訪問修飾符。如果一個字段有private修飾符,那麼我們就不能從外部訪問它。
public class Person {
private int age;
public String nickname;
public Person(int age, String nickname) {
this.age = age;
this.nickname = nickname;
}
}
讓我們檢查Main類中的可訪問性:
public class Main {
public static void main(String[] args) {
Person person = new Person();
System.out.println(person.nickname);
// System.out.println(person.age); No access to the field
}
}
我們無權訪問年齡領域,但我們確實有反思。:) 在它的幫助下,我們可以訪問和使用私有字段。
使用反射從對像中獲取私有字段
讓我們使用getDeclaredFields()方法獲取我們類中所有字段的數組。它返回一個我們可以使用和修改的Field對象:
public static void main(String[] args) {
Field[] fields = Person.class.getDeclaredFields();
List<String> actualFieldNames = getFieldNames(fields);
actualFieldNames.forEach(System.out::println);
}
static List<String> getFieldNames(Field[] fields) {
List<String> fieldNames = new ArrayList<>();
for (Field field : fields)
fieldNames.add(Modifier.toString(field.getModifiers()) + " " + field.getName());
return fieldNames;
}
公開暱稱
在getFieldNames方法中,我們從類中獲取兩個字段。getModifiers 方法返回字段的修飾符,getName 方法返回其名稱。現在讓我們嘗試修改和訪問這個字段。首先,讓我們嘗試從公共字段獲取數據:
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
Person person = new Person(10, "CodeGym");
Field field = Person.class.getDeclaredField("nickname");
String nickname = (String) field.get(person);
System.out.println(nickname);
System.out.println(person.nickname);
}
代碼健身房
我們可以藉助反射和使用我們對對象的引用來訪問該字段。一切都很好!讓我們進入一個私人領域。
我們會將請求字段的名稱更改為我們的私有字段年齡場地:
public static void main(String[]args)throws NoSuchFieldException, IllegalAccessException {
Person person = new Person(10, "CodeGym");
Field field = Person.class.getDeclaredField("age");
int age =(int)field.get(person);
System.out.println(age);
// System.out.println(person.age);
}
我們無法通過創建的對象進行訪問,因此請嘗試使用反射。我們得到一個錯誤:
非法訪問異常
我們得到一個IllegalAccessException。讓我們來看看裡面有什麼:
讓我們試著弄明白。
IllegalAccessException當應用程序試圖反射性地創建實例(數組除外)、設置或獲取字段或調用方法時拋出,而當前正在執行的方法無權訪問指定類、字段的定義,方法或構造函數。
這裡的方法也會拋出這個異常。為了避免這種異常,我們將使用一種特殊的方法來訪問私有字段。
setAccessible(布爾標誌)
此方法可以避免對字段或類進行安全訪問檢查。我們可以將true或false傳遞給該方法,以確定是否對該字段執行安全訪問檢查。讓我們嘗試修復我們的代碼:
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
Person person = new Person(10, "CodeGym");
Field field = Person.class.getDeclaredField("age");
field.setAccessible(true);
int age = (int) field.get(person);
System.out.println("The current value is " + age);
}
讓我們看看結果:
偉大的!我們得到了關於我們班級的信息。讓我們也嘗試通過為它分配一個新值來更改我們的字段:
public static void main(String[]args)throws NoSuchFieldException, IllegalAccessException {
Person person = new Person(10, "CodeGym");
Field field = Person.class.getDeclaredField("age");
field.setAccessible(true);
field.set(person, 19);
int age =(int)field.get(person);
System.out.println("The current value is " + age);
}
改變我們的領域後,我們得到:
讓我們嘗試調用setAccessible(false)。
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
Person person = new Person(10, "CodeGym");
Field field = Person.class.getDeclaredField("age");
field.setAccessible(true);
field.set(person, 19);
field.setAccessible(false);
System.out.println("The current value is " + field.get(person));
}
將可訪問性恢復為false後,當我們嘗試調用get方法時再次遇到異常:
所以在處理私有字段時要小心,不要忘記反射是一個非常強大的工具!
GO TO FULL VERSION