您的位置:首页 > 编程语言 > Java开发

结合反射,获取泛型对象的类成员变量的值

2016-07-17 11:17 633 查看
网上找到的都是反射获取已知对象的,索性自己实现了。

先上代码:

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
* Created by jackie on 2016/7/14.
*/
public class TestReflect<T> {
public static void main(String args[]) throws NoSuchFieldException, IllegalAccessException, InstantiationException, ClassNotFoundException {
Message m1 = new Message();
Message m2 = new Message();
List<Message> list = new ArrayList<>();
list.add(m1);
list.add(m2);
////这里是我测试通过集合类工具加工的不可修改List是否会影响泛型传递后的对象,
// 不过显然不会,只是对List的修改做了限制。unmodifiableList的使用场景请自行百度
List<Message> unmodifiedList = Collections.unmodifiableList(list);
//所以这里如果业务没涉及可以不管,下面方法的传参unmodifiableList可以改成list。
new TestReflect<Message>().printObjectValue(unmodifiedList, Message.class.getName());
}

public void printObjectValue(List<T> object, String className) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
Object ot = Class.forName(className).newInstance();
Class c = ot.getClass();
Field[] fields = c.getDeclaredFields();//取得所有类成员变量

//        //遍历所有类成员变量
//        for (Field f:fields
//             ) {
//            System.out.println(f.getName());
//        }
//        //遍历所有方法
//        Method[] methods = c.getMethods();
//        for (Method m:methods
//             ) {
//            System.out.println(m.getName());
//        }

//取消每个属性的安全检查
for(Field f:fields){
f.setAccessible(true);
}

//打印传入的每个对象的所有类成员属性值
for (int j = 0; j < object.size(); j++)
for (int i = 0; i < fields.length; i++) {
try {
System.out.println(fields[i].getName() + ":" + fields[i].get(object.get(j)));
} catch (Exception e) {
e.printStackTrace();
}
}
}
}


/**
* Created by jackie on 2016/7/15.
*/
public class Message {
public Message(){
num=1;
}

public int getNum() {
return num;
}

public void setNum(int num) {
this.num = num;
}

private int num;

private String message="你好";

public String getMessage() {
return message;
}

public void setMessage(String message) {
this.message = message;
}
}


无论传入的是什么类型的对象,如果直接拿泛型类去反射都是拿到泛型本身的属性和方法,拿不到类对象的属性方法,于是经常会抛类似这样的异常:java.lang.IllegalArgumentException: Can not set java.lang.reflect.Constructor field java.lang.Class.cachedConstructor to Message

我的解决思路很简单:传进来类对象的同时也把对象的ClassName传进来,再用反射API构造该类对象的实例,再拿到该对象的Class再反射获得该类对象的属性(getDeclareFields和getFields的区别自己注意下)和方法,接着就可以按正常反射获取对象属性值的操作来实现了。

如果按以上操作能抛出类似上面说的异常,请在调用该方法前检查要传入的对象的类对象和传入的类对象名称是否对应。比如我在业务中遇到的持久层封装,进行SQL查询后是将取到的值放到一个Object[]数组的,天真的我只是看到返回的对象类型为QueryPage<Message>,再getContent取到List<Message>类型就以为里面放的是Message的对象数组,坑了很久才发现里面放的是Object[]数组,只保留了值,丢失了键。为什么会这样呢,等我搞清楚再更帖。

发现原因了,hibernate的HQL语句如果写成select num from Message;这样的话查询结果是放在Object[]里,如果写成select new Message(num) from Message;则查询结果会放在一个Message对象中(当然要为该对象写对应的构造方法,且这里的new Message是要写全包名)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息