我有一个对抽象对象A的引用。此对象在任何时候也是对象B、C或D的实例。
无论扩展类如何,我都需要引用A中某种类型的私有 final字段。
我不知道字段的名称,只知道它的类型,这是抽象类中所有其他字段所独有的。我无法更改列出的四个类中的任何一个的代码。使用 getDeclaredFields() 返回我当时拥有的任何扩展类中的字段。
如何获得对该字段的引用?
我有一个对抽象对象A的引用。此对象在任何时候也是对象B、C或D的实例。
无论扩展类如何,我都需要引用A中某种类型的私有 final字段。
我不知道字段的名称,只知道它的类型,这是抽象类中所有其他字段所独有的。我无法更改列出的四个类中的任何一个的代码。使用 getDeclaredFields() 返回我当时拥有的任何扩展类中的字段。
如何获得对该字段的引用?
如果您没有直接自己上课,那么您可以执行以下操作 -
Field[] fields = obj.getClass().getSuperclass().getDeclaredFields();
for(Field field : fields) {
if(field.getType() == String.class) { //assume the type is String
}
}
但是,如果您可以访问该课程,那么它将是
Field[] fields = B.class.getSuperclass().getDeclaredFields();
甚至
Field[] fields = A.class.getDeclaredFields();
import java.lang.reflect.Field;
abstract class A {
private final String secret = "got it";
}
class B extends A {
private final String secret = "try again";
}
public class Test {
public static void main(String[] args) throws IllegalAccessException {
Class neededType = String.class;
A a = new B();
Class c = a.getClass();
Class sc = c.getSuperclass();
Field flds[] = sc.getDeclaredFields();
for (Field f : flds) {
if (neededType.equals(f.getType())) {
f.setAccessible(true);
System.out.println(f.get(a));
}
}
}
}
您需要在 A 类本身上调用getDeclaredFields(),然后使用反射来设置可以访问的字段
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
public class Test{
public static void main(String args[]){
B someB = new B();
B otherB = new B();
Field uniqueField = null;
for(Field f : A.class.getDeclaredFields()){
if(!Modifier.isFinal(f.getModifiers()))
continue;
if(!UNIQUE.class.isAssignableFrom(f.getType()))
continue;
uniqueField = f;
break;
}
if(null == uniqueField)
throw new NullPointerException();
uniqueField.setAccessible(true);
try{
System.out.println(uniqueField.get(someB) != uniqueField.get(otherB));
}catch(IllegalArgumentException | IllegalAccessException e){
throw new RuntimeException(e);
}
}
}
class UNIQUE{
}
class A{
private final UNIQUE u;
private final String someOtherMember = "";
A(){
u = new UNIQUE();
}
}
class B extends A{
}
如果您没有对 A 类的直接引用,或者如果有多个超类具有此唯一字段,那么您可以遍历每个超类(确保在每个站点检查您没有一路爬到对象)通过在上面的示例中执行更多类似的操作
Class<?> clazz = someB.getClass();
classClimb: do{
for(Field f : clazz.getDeclaredFields()){
if(!Modifier.isFinal(f.getModifiers()))
continue;
if(!UNIQUE.class.isAssignableFrom(f.getType()))
continue;
uniqueField = f;
break classClimb;
}
}while(Object.class != (clazz = clazz.getSuperclass()));
if(null == uniqueField)
throw new NullPointerException();
uniqueField.setAccessible(true);
try{
System.out.println(uniqueField.get(someB) != uniqueField.get(otherB));
}catch(IllegalArgumentException | IllegalAccessException e){
throw new RuntimeException(e);
}
请记住,在这种情况下,您必须对每个对象进行反射,进行一些缓存,或者拥有多个特定于每个预期超类的反射站点。