访问检查,就是查看成员属性、成员方法的使用是否符合访问权限(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中文网其他相关文章!