存取檢查,就是查看成員屬性、成員方法的使用是否符合存取權限(public、protected、default、private)。
有點太理論化了,簡單來說,如果一個類別的成員(屬性或方法)的存取權限是private,那麼該成員只能在目前類別中使用;如果一個類別的成員的存取權限是public,那麼該成員可以在任意類別中使用;如果一個類別的成員的存取權限是default,那麼該成員只能在同一個套件下面的類別中使用;如果一個類別的成員的訪問權限是protected,那麼該成員可以在同一個套件下面的類別中和其他套件下面的該類別的子類別中使用。
如果,類別的成員的存取權限是default,你卻在另一個套件中使用了該成員,當編譯時,編譯器會進行存取檢查,發現成員的使用與給定的存取權限不一致,因此會報錯。
舉個例子,在com.example套件下建立People類,有四個成員變數。在com.example.app包下(它是不同於com.example的包)下,使用People類別的四個成員變數。
package com.example; package com.example; public class People { private int privateVar = 1; int defaultVar = 2; protected int protectedVar = 3; public int publicVar = 4; } package com.example.app; import com.example.People; public class TestMain { public static void main(String[] args) { People p = new People(); System.out.println(p.privateVar); System.out.println(p.defaultVar); System.out.println(p.protectedVar); System.out.println(p.publicVar); } }
編譯後提示,publicVar的使用符合public的存取權限,所以沒有出錯。
相信大家都了解存取檢查是什麼,那麼,反射物件的存取檢查是怎麼的呢?
一個類別的成員屬性、成員方法、建構函數,在反射中分別抽象化為Field、Method、Counstructor類別。
我們可以使用Field存取物件的成員屬性,成員屬性的存取權限,編譯器是不知道的,只有執行時才知道。因此對於反射物件(例如Field)存取權限的檢查只能交給虛擬機器。
如果,虛擬機器在執行時,發現成員的使用與給定的存取權限不一致,如下程式碼
package com.example.app; import com.example.People; import java.lang.reflect.Field; public class TestMain { public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException { People p = new People(); Class cl = p.getClass(); // 利用反射访问private修饰的成员变量 Field f = cl.getDeclaredField("privateVar") System.out.println(f.get(p)); } }
執行時,拋出例外:java.lang.IllegalAccessException
#綜上,存取檢查可以時編譯器在編譯時進行或虛擬機器在執行時進行(主要是針對反射)
setAccessible(boolean flag)
#方法是AccessibleObject類別中的一個方法,它是Field、 Method、Constructor的公共父類別。當Field、Method或Constructor (三者都是反射物件)分別用於設定欄位(set(Object obj, Object value)
)或取得欄位(get(Object obj)
)、呼叫方法(invoke(Object obj, Object... args)
)或建立和初始化類別的新實例(newInstance(Object... initargs)
)時,將執行運行時訪問檢查。
引用自《Java核心技術第十版》
#注意:方法名稱setAccessible很容易讓人產生誤解,給人們的感覺是設定了成員的可訪問性,例如,覺得public修飾的成員是任意類別都可以訪問的,所以可訪問標誌是true;覺得private修飾的成員只有本類可以訪問,所以可訪問標誌是false。其實不然,不管是什麼存取權限,其可存取標誌的值都為false。
測試程式碼如下:
package com.example.app; import com.example.People; import java.lang.reflect.Field; public class TestMain { public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException { People p = new People(); Class cl = p.getClass(); // 打印输出所有成员变量的名字及可访问标志 for (Field f : cl.getDeclaredFields()) { System.out.println(f.getName() + ": " + f.isAccessible()); } } }
輸入結果:
#上面中的API說得很清楚,這個可訪問標誌表示是否屏蔽Java語言的存取檢查,預設值是false,(上面已經測試)
可以透過setAccessible(true)
修改預設值,如此會屏蔽Java語言的(運行時)訪問檢查,使得物件的私有成員可以訪問,而不報錯。
package com.example.app; import com.example.People; import java.lang.reflect.Field; public class TestMain { public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException { People p = new People(); Class cl = p.getClass(); for (Field f : cl.getDeclaredFields()) { //屏蔽对象的访问检查 f.setAccessible(true); // 访问不符合访问权限的成员属性 System.out.println(f.getName() + " = " + f.get(p)); } } }
輸入結果:
#以上是Java反射的setAccessible()方法怎麼使用的詳細內容。更多資訊請關注PHP中文網其他相關文章!