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)的用处是赋予反射对象超级权限,绕过语言权限检查。

 

posted on 2018-02-23 18:05  猫咪大王  阅读(11037)  评论(0编辑  收藏  举报