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()
将返回一个新的字段
实例数组,该数组不可访问。可访问属性绑定到特定的字段
实例,表示同一字段的其他字段
实例可能具有不同的可访问状态。