java setaccessible_Java setAccessible() 方法

这篇博客探讨了Java反射机制如何用于访问私有对象。通过示例代码展示了直接访问私有对象会抛出IllegalAccessException,而通过setAccessible(true)可以绕过访问限制。还介绍了一个通用的toString方法,该方法能够遍历对象的所有字段,包括私有字段,并将其转换为字符串表示形式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.直接通过 Field 访问 private 对象会报错

测试代码如下:

public void accessPrivateObjects(){

Employee employee = new Employee("hrm",500,2000,11,11);

for(Field f : employee.getClass().getDeclaredFields()){

try{

System.out.println(f.get(employee));

}catch (IllegalAccessException e){

e.printStackTrace();

}

}

}

public class Employee extends People{

private double salary;

private LocalDate hireDay;

...

}

报错:

java.lang.IllegalAccessException: class fiveChapter.FiveChapter cannot access a member of class fiveChapter.Employee with modifiers "private"

原因:

由于 salary 是一个私有域, 所以 get 方法将会抛出一个IllegalAccessException。只有利用 get 方法才能得到可访问域的值。除非拥有访问权限,否则Java 安全机制只允许査看任意对象有哪些域, 而不允许读取它们的值。

反射机制的默认行为受限于 Java 的访问控制。然而, 如果一个 Java 程序没有受到安全管理器的控制, 就可以覆盖访问控制。 为了达到这个目的, 需要调用 Field、 Method 或Constructor 对象的 setAccessible 方法。

--《Java核心技术 卷1 基础知识 原书第10版》P199

2.利用 setAccessible 访问私有对象的值

name属性为 Employee类的超类 People类的成员,getDeclaredFields()返回值不包括超类成员

getField()仅能获取类(及其父类可以自己测试) public属性成员

/**

* 利用反射获取 private 域的值,不包含超类域

* 输出:500.0

* 2000-11-11

*/

public static void accessPrivateObjects(){

Employee employee = new Employee("hrm",500,2000,11,11);

for(Field f : employee.getClass().getDeclaredFields()){

f.setAccessible(true);

try{

System.out.println(f.get(employee));

}catch (IllegalAccessException e){

e.printStackTrace();

}

}

}

3.setAccessible方法分析

setAccessible为AccessibleObject 类中的一个方法,是它是 Field、 Method 和 Constructor 类的公共超类。这个特性是为调试、 持久存储和相似机制提供的。

因而想访问 Field、 Method 和 Constructor 的私有对象,均需 setAccessible。

public void setAccessible(boolean flag)

5e4abbce071b8e86707326b9fb1760bd.png

public static void setAccessible(AccessibleObject[] array, boolean flag)

5af427e824dbac6b67f99665daecd99e.png

4.可供任意类使用的通用 toString方法

其中使用getDeclaredFileds 获得所有的数据域, 然后使用 setAccessible 将所有的域设置为可访问的。 对于每个域,获得了名字和值。递归调用 toString方法, 将每个值转换成字符串。

public class ObjectAnalyzer {

private ArrayList visited = new ArrayList<>();

/**

* 将对象转换为列出所有字段的字符串表示形式。

* @param object

* @return 包含对象类名以及所有字段名和值的字符串

*/

public String toString(Object object){

if(object == null) return "null";

if(visited.contains(object)) return "...";

visited.add(object);

Class cl = object.getClass();//返回一个Class类型的实例

//如果是 String 类直接返回对象

if(cl == String.class) return (String) object;

//如果该实例是数组

if(cl.isArray()){

//返回表示数组的组件类型的类 。 如果此类不表示数组类,则此方法返回null。

String r = cl.getComponentType() + "[]{";

for(int i = 0; i < Array.getLength(object); i++){

if(i > 0) r+= ",";

//返回指定数组对象中索引组件的值,即返回 object 数组对象索引 i 的值

Object val = Array.get(object,i);

//isPrimitive() 确定指定的类对象是否表示基本类型

if(cl.getComponentType().isPrimitive()) r += val;

else r += toString(val);

}

return r + "}";

}

String r = cl.getName();

do{

r += "[";

Field[] fields = cl.getDeclaredFields();

//设置可访问 private 对象的值

AccessibleObject.setAccessible(fields,true);

for(Field f : fields){

if(!Modifier.isStatic(f.getModifiers())){

if(!r.endsWith("[")) r += ",";

r += f.getName() + "=";

try{

//返回域所属类型的 Class 对象

Class t = f.getType();

Object val = f.get(object);

if(t.isPrimitive()) r += val;

else r += toString(val);

}catch (Exception e){

e.printStackTrace();

}

}

}

r += "]";

cl = cl.getSuperclass();

}while (cl != null);

return r;

}

}

测试:

public void objectAnalyzerTest(){

ArrayList squares = new ArrayList<>();

for(int i = 1; i <= 5; i++){

squares.add(i * i);

}

System.out.println(new ObjectAnalyzer().toString(squares));

}

输出结果为:

java.util.ArrayList[elementData=class java.lang.Object[]{java.lang.Integer[value=1][][],java.lang.Integer[value=4][][],java.lang.Integer[value=9][][],java.lang.Integer[value=16][][],java.lang.Integer[value=25][][],null,null,null,null,null},size=5][modCount=5][][]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值