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

本文实例讲述了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程序设计有所帮助。

(0)

相关推荐

  • 通过反射注解批量插入数据到DB的实现方法

    批量导入思路 最近遇到一个需要批量导入数据问题.后来考虑运用反射做成一个工具类,思路是首先定义注解接口,在bean类上加注解,运行时通过反射获取传入Bean的注解,自动生成需要插入DB的SQL,根据设置的参数值批量提交.不需要写具体的SQL,也没有DAO的实现,这样一来批量导入的实现就和具体的数据库表彻底解耦.实际批量执行的SQL如下: insert into company_candidate(company_id,user_id,card_id,facebook_id,type,create

  • 使用反射机制控制Toast的显示时间

    本文为大家分享了使用反射机制控制Toast显示时间的具体代码,供大家参考,具体内容如下 1.Toast源码分析: Toast的默认view是在transient_notification.xml中定义的一个TextView,如果需要设置Toast的界面,可以通过setView方法实现:如果需要设置Toast默认显示的位置,可以通过setGravity或者setMargin方法进行设置,值得一提的是setMargin方法的参数范围是0-1即它是屏幕的百分比,如setMargin(0.1,0.1).

  • Java反射机制的精髓讲解

    1,什么是反射? java的反射,允许程序在运行时,创建一个对象,获取一个类的所有相关信息等. 2,Class类 要了解反射,就绕不开Class类. 我们平时开发的类,例如ClassA,一般会有一些属性,会有几个构造方法,也会有一些普通方法,我们还可以使用ClassA来创建对象,例如ClassA classA = new ClassA(). java程序在运行时,其实是很多类的很多个对象之间的协作.jvm如何管理这些类呢?它如何知道各个类的名称,每个类都有哪些属性和哪些方法呢? jvm会给每个类

  • 利用lambda表达式树优化反射详解

    前言 本节重点不讲反射机制,而是讲lambda表达式树来替代反射中常用的获取属性和方法,来达到相同的效果但却比反射高效. 每个人都知道,用反射调用一个方法或者对属性执行SetValue和GetValue操作的时候都会比直接调用慢很多,这其中设计到CLR中内部的处理,不做深究.然而,我们在某些情况下又无法不使用反射,比如:在一个ORM框架中,你要将一个DataRow转化为一个对象,但你又不清楚该对象有什么属性,这时候你就需要写一个通用的泛型方法来处理,以下代码写得有点恶心,但不妨碍理解意思: //

  • 详解Golang利用反射reflect动态调用方法

    编程语言中反射的概念 在计算机科学领域,反射是指一类应用,它们能够自描述和自控制.也就是说,这类应用通过采用某种机制来实现对自己行为的描述(self-representation)和监测(examination),并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义. 每种语言的反射模型都不同,并且有些语言根本不支持反射.Golang语言实现了反射,反射机制就是在运行时动态的调用对象的方法和属性,官方自带的reflect包就是反射相关的,只要包含这个包就可以使用. 多插一句,

  • ES6 如何改变JS内置行为的代理与反射

    代理(Proxy)可以拦截并改变 JS 引擎的底层操作,如数据读取.属性定义.函数构造等一系列操作.ES6 通过对这些底层内置对象的代理陷阱和反射函数,让开发者能进一步接近 JS 引擎的能力. 一.代理与反射的基本概念 什么是代理和反射呢? 代理是用来替代另一个对象(target),JS 通过new Proxy()创建一个目标对象的代理,该代理与该目标对象表面上可以被当作同一个对象来对待. 当目标对象上的进行一些特定的底层操作时,代理允许你拦截这些操作并且覆写它,而这原本只是 JS 引擎的内部能

  • 实例讲解Java基础之反射

    前期准备 编写一个真实类phone,实现list接口 public class Phone implements List { public double price; public String name; public Phone() { } public Phone(double price, String name) { this.price = price; this.name = name; } public double getPrice() { return price; } p

  • Kotlin中的反射机制深入讲解

    前言 Java中的反射机制,使得我们可以在运行期获取Java类的字节码文件中的构造函数,成员变量,成员函数等信息.这一特性使得反射机制被常常用在框架中,想要比较系统的了解Kotlin中的反射,先从Java的反射说起. Java中的反射 通常我们写好的.java源码文件,经过javac的编译,最终生成了.class字节码文件.这些字节码文件是与平台无关的,使用时通过Classloader去加载这些.class字节码文件,从而让程序按照我们编写好的业务逻辑运行.Java的反射主要是从这些.class

  • 实例讲解Java中动态代理和反射机制

    反射机制 Java语言提供的一种基础功能,通过反射,我们可以操作这个类或对象,比如获取这个类中的方法.属性和构造方法等. 动态代理:分为JDK动态代理.cglib动态代理(spring中的动态代理). 静态代理 预先(编译期间)确定了代理者与被代理者之间的关系,也就是说,若代理类在程序运行前就已经存在了,这种情况就叫静态代理 动态代理 代理类在程序运行时创建的代理方式.也就是说,代理类并不是在Java代码中定义的,而是在运行期间根据我们在Java代码中的"指示"动态生成的. 动态代理比

  • 基于Java反射的map自动装配JavaBean工具类设计示例代码

    前言 JavaBean是一个特殊的java类,本文将给大家详细介绍关于基于Java反射的map自动装配JavaBean工具类设计的相关内容,下面话不多说了,来一起看看详细的介绍吧 方法如下 我们平时在用Myabtis时不是常常需要用map来传递参数,大体是如下的步骤: public List<Role> findRoles(Map<String,Object> param); <select id="dindRoles" parameterType=&qu

随机推荐