Java 如何授予对反射检索的所有私有字段值的访问权限?

Java 如何授予对反射检索的所有私有字段值的访问权限?,java,reflection,Java,Reflection,是否可以在不使用field.setAccessible(true)的情况下获取字段值 我的意思是,我可以简单地授予对特定类的所有私有字段的访问权限,而不必在每次读取时调用setter吗?不,您不能。为什么?您可以准备一次字段对象,缓存它并使用它进行多次读取 // do it once Field field = object.getClass().getDeclaredField(fieldName); field.setAccessible(true); // use man

是否可以在不使用
field.setAccessible(true)的情况下获取字段值


我的意思是,我可以简单地授予对特定类的所有私有字段的访问权限,而不必在每次读取时调用setter吗?

不,您不能。为什么?您可以准备一次字段对象,缓存它并使用它进行多次读取

 // do it once
 Field field = object.getClass().getDeclaredField(fieldName);    
 field.setAccessible(true);

 // use many times:
 for(million times)
     Object value = field.get(object);

不,你不能。为什么?您可以准备一次字段对象,缓存它并使用它进行多次读取

 // do it once
 Field field = object.getClass().getDeclaredField(fieldName);    
 field.setAccessible(true);

 // use many times:
 for(million times)
     Object value = field.get(object);

您不必对每个字段访问重复该操作。每个类/字段只需执行一次,但有一种有效的方法:

static final class Accessor extends ClassValue<Map<String,Field>> {
    @Override protected Map<String, Field> computeValue(Class<?> type) {
        Field[] fields=type.getDeclaredFields();
        AccessibleObject.setAccessible(fields, true);
        Map<String,Field> map=new HashMap<>(fields.length);
        for(Field f: fields) map.put(f.getName(), f);
        return map;
    }
}
static final Accessor FIELD_ACCESSOR = new Accessor();
请注意,
ClassValue
只负责对每个类执行一次操作,而缓存的值不会阻止类垃圾回收,并且
AccessibleObject.setAccessible(…)
将一次应用于所有声明的字段


但是请记住,这些只是实际类的声明字段,您必须手动迭代超类层次结构来搜索它们的字段。字段名不必在类层次结构中是唯一的。

您不必对每个字段访问重复该操作。每个类/字段只需执行一次,但有一种有效的方法:

static final class Accessor extends ClassValue<Map<String,Field>> {
    @Override protected Map<String, Field> computeValue(Class<?> type) {
        Field[] fields=type.getDeclaredFields();
        AccessibleObject.setAccessible(fields, true);
        Map<String,Field> map=new HashMap<>(fields.length);
        for(Field f: fields) map.put(f.getName(), f);
        return map;
    }
}
static final Accessor FIELD_ACCESSOR = new Accessor();
请注意,
ClassValue
只负责对每个类执行一次操作,而缓存的值不会阻止类垃圾回收,并且
AccessibleObject.setAccessible(…)
将一次应用于所有声明的字段



但是请记住,这些只是实际类的声明字段,您必须手动迭代超类层次结构来搜索它们的字段。字段名在类层次结构中不必是唯一的。

不,不能。为什么?您可以准备一次
字段
对象,缓存它并使用它进行多次读取。出于性能考虑。因为我使用反射来生成一个平面键值,比如基于复杂bean的map。当从bean生成时,我希望能够跳过
setAccessible()
,这样我就不必在每个映射的每个属性上设置它。也许如果您获取字段数组并以某种方式(流、列表、普通循环等)对其进行循环,只需重新使用
字段
对象进行读取即可。@kan您能更具体地说明重新使用吗?不,您不能。为什么?您可以准备一次
字段
对象,缓存它并使用它进行多次读取。出于性能考虑。因为我使用反射来生成一个平面键值,比如基于复杂bean的map。当从bean生成时,我希望能够跳过
setAccessible()
,这样我就不必在每个映射的每个属性上设置它。也许如果您获取字段数组并以某种方式(流、列表、普通循环等)对其进行循环,只需重新使用
字段
对象进行读取即可。@kan您能更具体地说明重新使用吗?我知道我可以多次检索同一对象上的字段,而无需调用setter。但是如果
对象
发生变化,意味着创建了一个新对象,那么我必须再次调用setter,对吗?字段用于类,而不是对象。每个
getClass()
可以有字段。我也有一个缓存。这样我就可以创建一个
Set cache
,并在调用
setAccessible()
后将字段放在那里。然后调用
cache.get(field).get(object)
来访问新对象的值。这就是你的建议吗?是的,但不完全是。您可以有一个缓存,例如
Map
。例如class->fieldName->field。我知道我可以多次检索同一对象上的字段,而无需调用setter。但是如果
对象
发生变化,意味着创建了一个新对象,那么我必须再次调用setter,对吗?字段用于类,而不是对象。每个
getClass()
可以有字段。我也有一个缓存。这样我就可以创建一个
Set cache
,并在调用
setAccessible()
后将字段放在那里。然后调用
cache.get(field).get(object)
来访问新对象的值。这就是你的建议吗?是的,但不完全是。您可以有一个缓存,例如
Map
。例如class->fieldName->field.那么简而言之-
AccessibleObject.setAccessible(object.getClass().getDeclaredFields(),true)
?我以前不知道这个把戏,谢谢@Janez Kuhar:嗯,您必须保留
字段[]
数组,作为对
Class.getName的下一个调用‌Fields()
将返回一个新的
字段
实例数组,该数组不可访问。可访问属性绑定到特定的
字段
实例,表示同一字段的其他
字段
实例可能具有不同的可访问状态。因此简而言之-
AccessibleObject.setAccessible(object.getClass().getDeclaredFields(),true)
?我以前不知道这个把戏,谢谢@Janez Kuhar:嗯,您必须保留
字段[]
数组,作为对
Class.getName的下一个调用‌Fields()
将返回一个新的
字段
实例数组,该数组不可访问。可访问属性绑定到特定的
字段
实例,表示同一字段的其他
字段
实例可能具有不同的可访问状态。