java反射就是把Java类中的各个成员映射成一个个的Java对象,也就是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,那java反射怎么获取嵌套类的所有字段?下面来我们就来给大家讲解一下。
获取单个:
/** * 根据属性名获取属性值 * * @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()
ListfieldList = 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 的属性
反射机制可以操作字节码文件,大大提高系统的灵活性和扩展性,不过使用反射也要谨慎,会消耗一定的系统资源。最后大家如果想要了解更多java入门知识,敬请关注奇Q工具网。
推荐阅读: