首页 > 开发 > Java > 正文

Java高级特性之反射机制实例详解

2024-07-14 08:42:13
字体:
来源:转载
供稿:网友

本文实例讲述了Java高级特性之反射机制。分享给大家供大家参考,具体如下:

老规矩我们还是先提出几个问题,一门技术必然要能解决一定的问题,才有去学习掌握它的价值

  • 一、 什么是反射?
  • 二、反射能做什么?

一、 什么是反射?

用在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    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。

今天反射就暂时讲到这里。其实反射的作用远不于此,这里只是使用了反射的冰山一角,结合注解和泛型,反射可以做的事更多,但是还是和开头讲的一样,反射用起来虽然很爽,但是不能乱射,和频繁的射,“射”的太多。“性”能会出问题!(o(∩_∩)o )。

希望本文所述对大家java程序设计有所帮助。


注:相关教程知识阅读请移步到JAVA教程频道。
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表