java反射怎么获取嵌套类的所有字段?相关实例

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工具网。

推荐阅读:

java出现异常程序会终止吗?Java异常怎么处理?

qt如何显示视频?qt单行输入框怎么创建?

JAVA写程序时主类的名字和什么要相等?JAVA怎么写程序?