通过需要决定使用 getFields 还是 getDeclaredFields
方法 | 功能 |
---|---|
getFields() | 获取所有public字段,包括父类字段 |
getDeclaredFields() | 获取所有字段,public和protected和private,但是不包括父类字段 |
获取单个:
/**
* 根据属性名获取属性值
*
* @param fieldName
* @param object
* @return
*/
protected String getFieldValueByFieldName(String fieldName, Object object) {
try {
Field field = object.getClass().getDeclaredField(fieldName);
//设置对象的访问权限,保证对private的属性的访问
field.setAccessible(true);
return (String) field.get(object);
} catch (Exception e) {
return null;
}
}
获取全部:
/**
* 得到属性值
* @param obj
*/
public static void readAttributeValue(Object obj) {
String nameVlues = "";
//得到class
Class cls = obj.getClass();
//得到所有属性
Field[] fields = cls.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {//遍历
try {
//得到属性
Field field = fields[i];
//打开私有访问
field.setAccessible(true);
//获取属性
String name = field.getName();
//获取属性值
Object value = field.get(obj);
//一个个赋值
nameVlues += field.getName() + ":" + value + ",";
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
//获取最后一个逗号的位置
int lastIndex = nameVlues.lastIndexOf(",");
//不要最后一个逗号","
String result = nameVlues.substring(0, lastIndex);
System.out.println(result);
}
当然,上面的是简单的做法,主要针对String,也可以对Field进行区分
public void doField(Object object, Field field) throws InvocationTargetException, IllegalAccessException {
// 如果类型是String
if (field.getGenericType().toString().equals(
"class java.lang.String")) { // 如果type是类类型,则前面包含"class ",后面跟类名
// 拿到该属性的gettet方法
/**
* 这里需要说明一下:他是根据拼凑的字符来找你写的getter方法的
* 在Boolean值的时候是isXXX(默认使用ide生成getter的都是isXXX)
* 如果出现NoSuchMethod异常 就说明它找不到那个gettet方法 需要做个规范
*/
Method m = (Method) object.getClass().getMethod(
"get" + getMethodName(field.getName()));
String val = (String) m.invoke(object);// 调用getter方法获取属性值
if (val != null) {
System.out.println("String type:" + val);
}
}
// 如果类型是Integer
if (field.getGenericType().toString().equals(
"class java.lang.Integer")) {
Method m = (Method) object.getClass().getMethod(
"get" + getMethodName(field.getName()));
Integer val = (Integer) m.invoke(object);
if (val != null) {
System.out.println("Integer type:" + val);
}
}
// 如果类型是Double
if (field.getGenericType().toString().equals(
"class java.lang.Double")) {
Method m = (Method) object.getClass().getMethod(
"get" + getMethodName(field.getName()));
Double val = (Double) m.invoke(object);
if (val != null) {
System.out.println("Double type:" + val);
}
}
// 如果类型是Boolean 是封装类
if (field.getGenericType().toString().equals(
"class java.lang.Boolean")) {
Method m = (Method) object.getClass().getMethod(
field.getName());
Boolean val = (Boolean) m.invoke(object);
if (val != null) {
System.out.println("Boolean type:" + val);
}
}
// 如果类型是boolean 基本数据类型不一样 这里有点说名如果定义名是 isXXX的 那就全都是isXXX的
// 反射找不到getter的具体名
if (field.getGenericType().toString().equals("boolean")) {
Method m = (Method) object.getClass().getMethod(
field.getName());
Boolean val = (Boolean) m.invoke(object);
if (val != null) {
System.out.println("boolean type:" + val);
}
}
// 如果类型是Date
if (field.getGenericType().toString().equals(
"class java.util.Date")) {
Method m = (Method) object.getClass().getMethod(
"get" + getMethodName(field.getName()));
Date val = (Date) m.invoke(object);
if (val != null) {
System.out.println("Date type:" + val);
}
}
// 如果类型是Short
if (field.getGenericType().toString().equals(
"class java.lang.Short")) {
Method m = (Method) object.getClass().getMethod(
"get" + getMethodName(field.getName()));
Short val = (Short) m.invoke(object);
if (val != null) {
System.out.println("Short type:" + val);
}
}
// 如果还需要其他的类型请自己做扩展
}
// 把一个字符串的第一个字母大写、效率是最高的、
private static String getMethodName(String fildeName) throws Exception{
byte[] items = fildeName.getBytes();
items[0] = (byte) ((char) items[0] - 'a' + 'A');
return new String(items);
}
注意!
通过反射获取信息时,在父类字段为protected时,子类也可以访问的,但无法反射到
例如: A extends B ,那只能反射到A中的属性,无法拿到B当中的。
针对这种情况,可以进行递归父类去getDeclaredFields()
List fieldList = new ArrayList<>() ;
Class tempClass;
public void getFields(Object object){
tempClass = object.getClass();
while (tempClass != null) {//当父类为null的时候说明到达了最上层的父类(Object类).
fieldList.addAll(Arrays.asList(tempClass .getDeclaredFields()));
tempClass = tempClass.getSuperclass(); //得到父类,然后赋给自己
}
for (Field f : fieldList) {
Log.d("getAllFields","getFields---"+f.getName());
}
}
可以看到我们获取了Model和ParentModel的全部字段,不仅如此,还多出来了两个字段 shadow$_klass_ 和 shadow_monitor_,这个是Object中的字段.
shadow$_monitor_和shadow$_klass_是Android sdk21之后Object增加的两个字段。
如果你想屏蔽Object类的影响,可以为while循环再添加一个条件:
while (tmpClass !=null && !tmpClass.getName().toLowerCase().equals("java.lang.object") )
{
....
}
记得控制一下父类的级别层次,很多时候我们并不需要object 的属性
参考:
https://blog.csdn.net/qq_32452623/article/details/54025185