疯狂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 jsonToBean(JSONObject response, Class 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。