field.setAccessible(true) 简介
今天查看别人写的代码时,发现这样一句代码,顿时来了兴趣。
需要注意setAccessible 并不是在Field中的,而是在AccessibleObject中。
下面是AccessibleObject的解释:
意思是 AccessibleObject 类是 Field Method Constructor 类的基类。它提供反射对象绕过Java语言权限控制检查的权限。
当Fields Methods Constructors被用来set get 对象域,调用方法或者产生初始化对象实例的时候会践行权限检查(public default(package) protected private)。
将反射对象中的 accessible 标志位设置为 true,就意味着允许客户端拥有超级权限,比如Java对象序列化 或者 其他持久化机制等通常禁止的机制。
所以我们在accessible 标志位设置为true 的时候需要非常谨慎,这会带来一定的安全隐患。
** * The AccessibleObject class is the base class for Field, Method and * Constructor objects. It provides the ability to flag a reflected * object as suppressing default Java language access control checks * when it is used. The access checks--for public, default (package) * access, protected, and private members--are performed when Fields, * Methods or Constructors are used to set or get fields, to invoke * methods, or to create and initialize new instances of classes, * respectively. * * <p>Setting the {@code accessible} flag in a reflected object * permits sophisticated applications with sufficient privilege, such * as Java Object Serialization or other persistence mechanisms, to * manipulate objects in a manner that would normally be prohibited. * * <p>By default, a reflected object is <em>not</em> accessible. * * @see Field * @see Method * @see Constructor * @see ReflectPermission * * @since 1.2 */
下面是 field.setAccessible(true); 方法的解释。
意思就是改方式是用来设置获取权限的。
如果 accessible 标志被设置为true,那么反射对象在使用的时候,不会去检查Java语言权限控制(private之类的);
如果设置为false,反射对象在使用的时候,会检查Java语言权限控制。
需要注意的是,设置为true会引起安全隐患。
/** * Set the {@code accessible} flag for this object to * the indicated boolean value. A value of {@code true} indicates that * the reflected object should suppress Java language access * checking when it is used. A value of {@code false} indicates * that the reflected object should enforce Java language access checks. * * <p>First, if there is a security manager, its * {@code checkPermission} method is called with a * {@code ReflectPermission("suppressAccessChecks")} permission. * * <p>A {@code SecurityException} is raised if {@code flag} is * {@code true} but accessibility of this object may not be changed * (for example, if this element object is a {@link Constructor} object for * the class {@link java.lang.Class}). * * <p>A {@code SecurityException} is raised if this object is a {@link * java.lang.reflect.Constructor} object for the class * {@code java.lang.Class}, and {@code flag} is true. * * @param flag the new value for the {@code accessible} flag * @throws SecurityException if the request is denied. * @see SecurityManager#checkPermission * @see java.lang.RuntimePermission */
下面举例说明一下它的用处
1、首先新建一个bean类---Book
public class Book { public String getBookId() { return bookId; } public void setBookId(String bookId) { this.bookId = bookId; } public String getBookName() { return BookName; } public void setBookName(String bookName) { BookName = bookName; } private String bookId; private String BookName; }
2、创建工具类,使用反射来进行对象的set操作。
public class ReflectUtil { private static Field getField(Object obj, String fieldName) { Field field = null; for (Class<?> clazz = obj.getClass(); clazz != Object.class; clazz = clazz.getSuperclass()) { try { field = clazz.getDeclaredField(fieldName); break; } catch (NoSuchFieldException e) { System.out.println("catch NoSuchFieldException."); //这里不用做处理,子类没有该字段可能对应的父类有,都没有就返回null。 } } return field; } /** * 利用反射设置指定对象的指定属性为指定的值. * * @param obj 目标对象 * @param fieldName 目标属性 * @param fieldValue 目标值 */ public static void setFieldValue(Object obj, String fieldName, String fieldValue) { Field field = ReflectUtil.getField(obj, fieldName); if (field != null) { try { field.setAccessible(true); field.set(obj, fieldValue); System.out.println("success!"); } catch (IllegalArgumentException e) { System.out.println("++++++setFieldValue IllegalArgumentException:::+++++++" + e); } catch (IllegalAccessException e) { System.out.println("++++++setFieldValue IllegalAccessException:::+++++++" + e); } } } }
3、测试,首先注释调下面这行代码,然后在main方法中调用反射工具类进行变量set。
field.setAccessible(true);
public class Test3 { public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException { Book book = new Book(); ReflectUtil.setFieldValue(book,"bookId","1"); } }
下面是结果,报错,表示不能对private域进行操作。
我们将注释取消,再运行一下,发现成功了。
这就证明了field.setAccessible(true)的用处是赋予反射对象超级权限,绕过语言权限检查。