Java高级特性之反射学习总结

79 阅读4分钟
  • 一、 什么是反射?
  • 二、反射能做什么?

一、 什么是反射?

用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体、或对其fields设值、或唤起其methods。

如果你是一个Android Developer,前辈们都会教导你尽量少用反射,效率太低,太慢。“射”嘛,射的太快就不好了,所以反射虽然慢点,但是偶尔射一下还是很”爽”的。

二、反射能做什么?

1、新建类的实例

我们知道所有的类都继承子顶级父类Object,而Object中有hashCode()、equals()、clone()、toString()、getClass()等。其中getClass()返回一个Class 对象。我们这里就需要使用的Class对象,注意C是大写,我们可以通过一下方式来获取Class对象

  1. Class.forName(“类名字符串”) (注意:类名字符串必须是全称,包名+类名)
  2. 类名.class
  3. 实例对象.getClass()

在Class类中有一个非常重要的方法

public T newInstance() throws InstantiationException, IllegalAccessException { 
       return newInstanceImpl(); 
   } 
 
private native T newInstanceImpl() throws IllegalAccessException, InstantiationException;  

查看Api可以看到调用newInstace方法可以返回当前class对应的实例对象。接下来看一个小的Demo

public class Reflection { 
 
    public static void main(String[] args) { 
 
        // 普通创建类的实例 
 
        People p1 = new People(); 
        System.out.println(p1.getName()); 
        // 利用反射获取类的实例 
        Class clazz = People.class; 
        // 常用方式,注意括号中需要放类的全路径名 
        // Class clazz = Class.forName("reflection.People"); 
        // Class clazz = p1.getClass(); 
        try { 
            People p2 = (People) clazz.newInstance(); 
            System.out.println(p2.getName()); 
        } catch (Exception e) { 
            e.printStackTrace(); 
        } 
 
    } 
 
} 
 
class People { 
 
    private String name = "张三"; 
    private int age; 
 
    public String getName() { 
        return name; 
    } 
 
    public void setName(String name) { 
        this.name = name; 
    } 
 
    public int getAge() { 
        return age; 
    } 
 
    public void setAge(int age) { 
        this.age = age; 
    } 
 
}  

输入结果:

张三 
 张三  

2、获取成员变量和方法

在讲之前我们先来看这样一个小按理,JSON数据转JavaBaen对象,在不用解析库的情况下,一般我们会这样做

private void analysisDate(JSONObject response) throws JSONException { 
        int announceid = response.getInt("announceid"); 
        String title = response.getString("title"); 
        String hits = response.getString("hits"); 
        String addtime = response.getString("addtime"); 
        NewsNotifyItem newsNotifyItem = new NewsNotifyItem(announceid, 
                title, hits, addtime); 
    } 
}  

每当我们需要解析额时候,都需要根据不同javabean来进行相应的解析,我们每次进行的操作都是一样的,只是解析的数据不同而已,结合上篇帖子讲到的泛型,这里我们就可以再利用反射来自己做一个Json解析工具。

下面是我写的一个JsonObject对象转JavaBean的一个工具类,需要注意的是,JSON的key需要和字段名保持一致,先说下思路

①首先通过反射获取JavaBean中的所有字段值的名称

②拼接出set方法

③由于字段名和Json的key值相同,利用自动名获取Json中的值并填充的实例对象中

public class Json2BeanUtils { 
 
    public static <T> T jsonToBean(JSONObject response, Class<T> clazz) { 
        try { 
            // 创建类的实例 
            Object object = Class.forName(clazz.getName()).newInstance()
            // 获取类中的所有成员变量 
            Field[] fields = object.getClass().getDeclaredFields()
            for (int i = 0; i < fields.length; i++) { 
                //设置权限 
                fields[i].setAccessible(true)
                // 获取字段的名称 
                String fieldName = fields[i].getName()
                // 过滤掉UID 
                if (fieldName.endsWith("serialVersionUID")) { 
                    continue
                } 
                // 获取字段的类型 
                String fieldType = fields[i].getGenericType().toString()
                // 拼接出JavaBean中的set方法 这里有一个坑 后面讲解 
                String methodName = "set" 
                        + fieldName.substring(0, 1).toUpperCase() 
                        + fieldName.substring(1)
                try { 
                    // 判断变量类型 
                    if (fieldType.endsWith("class java.lang.String")) { 
                        // 获取到set方法 
                        Method m = object.getClass().getMethod(methodName, 
                                String.class)
                        String value = null
                        try { 
                            // 从JsonObj中取出相应的值 
                            value = response.getString(fieldName)
                        } catch (Exception e) { 
                            e.printStackTrace()
                            value = ""
                        } 
                        if (TextUtils.isEmpty(value)) { 
                            value = ""
                        } else if (value.endsWith("null")) { 
                            value = ""
                        } 
                        // 赋值 
                        m.invoke(object, value)
                    } else if (fieldType.endsWith("int") 
                            || fieldType.endsWith("class java.lang.Integer")) { 
                        // int 类型 
                        System.out.println()
                        Method m = object.getClass().getMethod(methodName, 
                                int.class)
                        int value = -1
                        try { 
                            value = response.getInt(fieldName)
                        } catch (Exception e) { 
                            e.printStackTrace()
                            value = -1
                        } 
                        m.invoke(object, value)
 
                    } else if (fieldType.endsWith("boolean") 
                            || fieldType 
                                    .endsWith("fieldType:class java.lang.Boolean")) { 
                        // boolean 类型 
                        Method m = object.getClass().getMethod(methodName, 
                                boolean.class)
                        boolean value = false
                        try { 
                            value = response.getBoolean(fieldName)
                        } catch (Exception e) { 
                            e.printStackTrace()
                            value = false
                        } 
                        m.invoke(object, value)
                    } else if (fieldType.endsWith("double") 
                            || fieldType 
                                    .endsWith("fieldType:class java.lang.Double")) { 
                        // double 类型 
                        Method m = object.getClass().getMethod(methodName, 
                                double.class)
                        double value = -1D
                        try { 
                            value = response.getDouble(fieldName)
                        } catch (Exception e) { 
                            e.printStackTrace()
                            value = -1D
                        } 
                        m.invoke(object, value)
                    } else if (fieldType.endsWith("char")) { 
                        // char类型 JSONObject 没有char 
                        Method m = object.getClass().getMethod(methodName, 
                                String.class)
                        String value = ""
                        try { 
                            value = response.getString(fieldName)
                        } catch (Exception e) { 
                            e.printStackTrace()
                            value = ""
                        } 
                        m.invoke(object, value)
                    } else if (fieldType.endsWith("float") 
                            || fieldType 
                                    .endsWith("fieldType:class java.lang.Float")) { 
                        // float类型 
                        Method m = object.getClass().getMethod(methodName, 
                                double.class)
                        double value = -1D
                        try { 
                            value = response.getDouble(fieldName)
                        } catch (Exception e) { 
                            e.printStackTrace()
                            value = -1D
                        } 
                        m.invoke(object, value)
 
                    } else if (fieldType.endsWith("short") 
                            || fieldType 
                                    .endsWith("fieldType:class java.lang.Short")) { 
                        // short 
                        Method m = object.getClass().getMethod(methodName, 
                                short.class)
                        int value = -1
                        try { 
                            value = response.getInt(fieldName)
                        } catch (Exception e) { 
                            e.printStackTrace()
                            value = -1
                        } 
                        m.invoke(object, value)
                    } else if (fieldType.endsWith("byte") 
                            || fieldType 
                                    .endsWith("fieldType:class java.lang.Byte")) { 
                        Method m = object.getClass().getMethod(methodName, 
                                byte.class)
                        int value = -1
                        try { 
                            value = response.getInt(fieldName)
                        } catch (Exception e) { 
                            e.printStackTrace()
                            value = -1
                        } 
                        m.invoke(object, value)
                    } else if (fieldType.endsWith("long") 
                            || fieldType 
                                    .endsWith("fieldType:class java.lang.Long")) { 
                        Method m = object.getClass().getMethod(methodName, 
                                long.class)
                        Long value = -1L
                        try { 
                            value = response.getLong(fieldName)
                        } catch (Exception e) { 
                            e.printStackTrace()
                            value = -1L
                        } 
                        m.invoke(object, value)
                    }   
                } catch (Exception e) { 
                    // TODO: handle exception 
                } 
            } 
            return (T) object
        } catch (Exception e) { 
            e.printStackTrace()
        } 
 
        return null
    } 
 
}  

这里需要注意一个坑,先来看一段代码

class People { 
 
    private String name; 
    private int age; 
    private String mSex; 
 
    public String getName() { 
        return name; 
    } 
 
    public void setName(String name) { 
        this.name = name; 
    } 
 
    public int getAge() { 
        return age; 
    } 
 
    public void setAge(int age) { 
        this.age = age; 
    } 
 
    public String getmSex() { 
        return mSex; 
    } 
    // 这里就出了问题   
    public void setmSex(String mSex) { 
        this.mSex = mSex; 
    } 
 
}  

当我们自动生成get set方法时,会将字段的首字母大写,我们在上面拼接set 方法时,也是基于这样的规则来拼装的。但是 当我们的字段名为 aAbbb 时,则生成的get set 方法则不会大写。解决方案也很简单,注意字段命名或者在拼接时对第二个自动进行大小写判断。这样我们自己写的Json解析工具就搞定, 以后每次解析只需一行代码即可OK。