我正在尝试打印对象的公共属性,这些属性可以是基元,也可以是对象。通过使用Reflection,我设法打印方法(getMethods(((和基元字段(getDeclaredFields(((-线程中的异常";主";java.lang.IollegalArgumentException:无法将B字段A.b1设置为A
我的问题在
else {
Object o = f.get(this);
printProperties(o);
我如何将B类的引用发送到printProperties,以便进入B类并打印所有属性等?
示例-
public class A {
public String s1;
public int 1;
public B b1;
}
public class B {
public String s2;
public int 2;
public C c1;
}
public void printProperties(Object reflectObject) throws IllegalAccessException {
Class reflectClass = (Class) reflectObject;
String className = reflectClass.getName();
System.out.println(className);
Method [] classMethod = reflectClass.getMethods();
for(Method m :classMethod){
System.out.println("Name "+m.getName());
System.out.println("Return "+m.getReturnType());
}
System.out.println("Fields");
Field[] fields = reflectClass.getDeclaredFields();
for (Field f : fields){
if(f.getType().isPrimitive()||f.getType().isAssignableFrom(String.class)){
System.out.println("Field "+f.getName());
}
else {
Object o = f.get(this);
printProperties(o);
}
f.get(this)
的问题是字段的声明类与this
的类型不兼容。由于您是递归遍历字段,因此应该使用字段的值。下一行printProperties(o);
表明您已经想到了这样一种方法。但这与方法的第一行Class reflectClass = (Class) reflectObject;
相矛盾。字段的值不是Class
对象。但是,第一次调用并没有立即以ClassCastException
失败,而是到达了get(this)
点,这表明该方法的初始调用方确实传递了Class
对象,而不是实际的实例。
可以只使用声明的类型,而不使用运行时对象。如果您采用此路线,则应该保持一致,并将参数声明为Class
:
public void printProperties(Class<?> reflectClass) throws IllegalAccessException {
String className = reflectClass.getName();
System.out.println(className);
for(Method m: reflectClass.getMethods()) {
System.out.println("Name " + m.getName());
System.out.println("Return " + m.getReturnType());
}
System.out.println("Fields");
for(Field f: reflectClass.getDeclaredFields()) {
System.out.println("Field " + f.getName());
Class<?> fieldType = f.getType();
if(!fieldType.isPrimitive() && fieldType != String.class) {
printProperties(fieldType);
}
}
}
然后,您可以用printProperties(getClass());
或printProperties(someObject.getClass());
调用它,也可以直接指定类型,例如printProperties(A.class);
。
另一种方法是使用实际值及其类。在这种情况下,您必须修复调用者,以便传递对象,如printProperties(this);
或printProperties(someObject);
。如果您传递了一个Class
,而预期是Object
,编译器不会发出警告。在这种情况下,您将检查类java.lang.Class
。
public void printProperties(Object reflectObject) throws IllegalAccessException {
Class<?> reflectClass = reflectObject.getClass();
String className = reflectClass.getName();
System.out.println(className);
for(Method m :reflectClass.getMethods()) {
System.out.println("Name " + m.getName());
System.out.println("Return " + m.getReturnType());
}
System.out.println("Fields");
for(Field f : reflectClass.getDeclaredFields()) {
System.out.println("Field " + f.getName());
Class<?> fieldType = f.getType();
if(!fieldType.isPrimitive() && fieldType != String.class) {
Object fieldValue = f.get(reflectObject);
if(fieldValue != null) printProperties(fieldValue);
}
}
}
这使用实际值的类型。因此,当字段引用子类型的对象时,将检查该子类型。另一方面,这种方法不能检测null
。您可以将这两种方法结合起来,在字段的值为null
时使用字段的声明类型。这是留给读者的练习。当您同时使用这两种方法时,建议为它们指定不同的名称,以最大限度地减少将Class
和Object
混淆的可能性。