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

作者:white_fisher 时间:2023-10-08 06:33:51 

本文实例讲述了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 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。

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

更多java相关内容感兴趣的读者可查看本站专题:《Java面向对象程序设计入门与进阶教程》、《Java数据结构与算法教程》、《Java操作DOM节点技巧总结》、《Java文件与目录操作技巧汇总》和《Java缓存操作技巧汇总》

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

来源:https://blog.csdn.net/soul_code/article/details/50466935

标签:Java,反射机制
0
投稿

猜你喜欢

  • 详解java中的阻塞队列

    2021-11-26 12:24:44
  • Android软键盘挡住输入框的终极解决方案

    2022-04-30 01:16:47
  • Android集成zxing扫码框架功能

    2021-09-27 02:37:17
  • springboot项目配置多个kafka的示例代码

    2023-11-23 23:15:29
  • RocketMQ生产者调用start发送消息原理示例

    2022-07-05 20:13:04
  • 解决在Unity中使用FairyGUI遇到的坑

    2023-10-27 13:04:24
  • 基于hibernate框架在eclipse下的配置方法(必看篇)

    2022-11-09 20:30:26
  • WinForm实现状态栏跑马灯效果的方法示例

    2023-07-16 19:37:33
  • Android开发中软键盘的显示和隐藏

    2023-10-03 06:00:20
  • 轻松学习C#的装箱与拆箱

    2021-07-01 12:11:51
  • SpringBoot项目中分页插件PageHelper无效的问题及解决方法

    2021-07-08 23:25:55
  • 第一次编写Java流布局图形界面

    2023-10-13 08:27:11
  • Android gradle打包并自动上传的方法

    2022-01-23 06:50:37
  • Netty分布式Future与Promise执行回调相关逻辑剖析

    2021-08-18 23:33:50
  • C#实现根据银行卡卡号判断银行名

    2021-08-21 07:14:00
  • 浅析Spring Security登录验证流程源码

    2023-03-22 01:46:44
  • javac -encoding 用法详解

    2022-06-28 08:58:08
  • MyBatis动态SQL特性详解

    2022-10-03 03:21:50
  • Android调用系统的发邮件功能的小例子

    2022-09-09 04:23:11
  • Java给JFrame窗口设置热键的方法实现

    2022-01-24 13:32:20
  • asp之家 软件编程 m.aspxhome.com