反射作为java语言非常重要的特性之一,在开发的过程中可以为我们提供极大的便利。在J2EE中,java反射得到了大量的应用,尤其是在一些主流框架中,如Spring中反射就发挥了极大的作用。那将java作为开发语言的Android,我们能否利用java反射这一重要特性,帮助我们更加灵活、高效的进行开发呢?答案是肯定的。

我们先来了解一下反射(Reflection)到底是什么?

官方一点的解释:JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

个人认为反射的精髓在于两个字—动态。我们在实际编程解决问题的时候,往往会遇到这种情况,就是程序运行的时候应该去实例化哪个类,只有在运行时才知道,因此不能够在编译阶段就做出决定。Java反射就可以帮助我们在运行时决定应该实例化哪个类。因此,java反射的强大就在于它能够在程序运行时实例化对象,这是同我们平时用new实例化对象最根本的区别。

说了这么多,对于反射可能还是会感到有些模糊,一般java初学者都会对反射感到难于理解。遇到这种情况,最好的方法就是在实际项目中去利用它,在实战中理解反射的强大,感受它带给我们的便利。说实话笔者在写这篇博客之前对于反射的理解也是非常表面的,直到最近review之前写的Android项目,发现当年的我还是太年轻,囧……写的代码质量实在是太低了,项目中充斥着大量的重复代码,原因就是当时不会用反射,导致大量代码冗余。但是利用反射后,我竟发现代码量少了1/3, 而且代码整体也比原先的整洁、优雅了很多~

先来简单了解一下我这个Android项目的business吧。这个app是一款为服务于广大高考考生的一个错题本。用户可以用他利用摄像头对错题进行捕获,用户可以自定义每个科目的分类,按照分类保存到本地。并可以查看每个分类的错题墙;摇一摇随机要出原来的错题;错题云备份。下面看一下这款应用的几个截图,马上就可以看到反射在Android项目中的实际应用了。

如图一所示是app首页,用户可以点击想要收集错题的科目,然后应用跳转到图二所示的界面。用户可以点击“+”来添加错题分类,这时应用就会跳转到图三所示的界面。


图一 App首页 图二 分类展示界面 图三 添加分类界面

在做这个项目的时候,每个错题的分类管理我是利用SQLite实现的,而所有的数据库操作我全部使用一个Adapter类来进行封装的。在进入到图二、图三所示界面的时候就会分别实例化我这个定义好的Adapter类进行查询和插入操作,之前的代码是这样的:

private PhysicsDBAdapter dbAdapter;
/*取得数据库对象*/dbAdapter = new PhysicsDBAdapter(this);dbAdapter.open();
/*查询物理科目的所有分类信息*/final Image[] image = dbAdapter.queryAllImage();Text[] text = dbAdapter.queryAllText();cn.swu.SQLite.Date[] date = dbAdapter.queryAllDate();Id[] id = dbAdapter.queryAllId();

/*插入新的分类信息*/dbAdapter.insert(CategoryInfo);
但是这样做就会有一个问题,使用new的方式来实例化,在编译阶段就必须知道这个类是什么。所以在进入图二、图三界面的时候就只能实例化,调用固定的Adapter类。针对例子中给出的“物理”科目实例化相对应的PhysicsDBAdapter类,但是当我要点击其他科目的时候,又要实例化其他的Adapter类,比如BiologyDBAdapter、ChemistryDBAdapter…这样图二、图三中的代码就不能很好地得到重用,就必须为每个科目单独写图二、图三对应的代码,这样就会出现大量的重复代码,当然这是非常horrible& stupid的。那么有什么办法,可以让我们写图二、三对应代码的时候动态的去实例化数据库管理的Adapter类呢?有一个很好地解决方法就是利用JAVA的反射机制。利用反射可以在写图二、三对应代码的时候。动态的实例化,而不用像之前那样,傻傻的一个一个去new了,利用JAVA反射重构项目的代码如下:

/*取得数据库对象*/try {Class dbAdapter = Class.forName(className);/*当要实例化的类构造函数含有参数的时候需要得到构造参数的实例(stackoverflow上面找到的答案)*/Constructor<?> constructor = dbAdapter.getConstructor(Context.class);Object obj = constructor.newInstance(this);Method method = dbAdapter.getMethod("open", null);Object o = method.invoke(obj, null);} catch (InstantiationException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (SecurityException e) {e.printStackTrace();} catch (NoSuchMethodException e) {e.printStackTrace();} catch (IllegalArgumentException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();}
/*查询物理科目的所有分类信息*/try {Class dbAdapter = Class.forName(className);Constructor<?> constructor = dbAdapter.getConstructor(Context.class);Object obj = constructor.newInstance(this);Method method0 = dbAdapter.getMethod("queryAllImage", null);Method method1 = dbAdapter.getMethod("queryAllText", null);Method method2 = dbAdapter.getMethod("queryAllId", null);Method method3 = dbAdapter.getMethod("queryAllDate", null);image = (Image[]) method0.invoke(obj, null);text = (Text[]) method1.invoke(obj, null);id = (Id[]) method2.invoke(obj, null);date = (cn.swu.SQLite.Date[]) method3.invoke(obj, null);} catch (InstantiationException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (SecurityException e) {e.printStackTrace();} catch (NoSuchMethodException e) {e.printStackTrace();} catch (IllegalArgumentException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();}
/*插入新增一个分类*/try {Class dbAdapter = Class.forName(className);Constructor<?> constructor = dbAdapter.getConstructor(Context.class);Object obj = constructor.newInstance(this);Class[] param = new Class[1];/*CategoryInfo类中定义了一个分类信息的全部内容,id,Name,Image,text.将其作为参数传入insert方法中*/param[0] = CategoryInfo.class;Method method = dbAdapter.getMethod("insert", param);method.invoke(obj, categoryInfo);} catch (InstantiationException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (SecurityException e) {e.printStackTrace();} catch (NoSuchMethodException e) {e.printStackTrace();} catch (IllegalArgumentException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();}

重构后发现项目的代码少了1/3而且更加清晰,更加优雅了~(^o^)~

最后说点个人小小的心得体会,其实有的时候,只顾埋头写代码,并没有多大的提高。反而更应该多抽出点时间,去review一下原来写的代码,重构一下,让它变得更加简洁、优雅。多想一想用另一种方式去实现,有意识的去用一些设计模式,这对个人水平的提高会更有裨益。



更多相关文章

  1. Android之Notification的多种用法实例
  2. Android(安卓)系统复习面试系列(二)反射原理和 Android(安卓)类加
  3. java后台程序员转android 《三》之 集成腾讯云 云直播 直播推流
  4. Android(安卓)复杂的列表视图新写法 MultiType
  5. Android中集成支付宝
  6. Android(安卓)JNI和NDK学习(08)--JNI实例一 传递基本类型数据
  7. Android(安卓)Dex VS Class:实例图解剖析两种格式文件结构、优劣
  8. Android(安卓)“退一步”的布局加载优化
  9. 火线扫描Android静态代码

随机推荐

  1. ImageView.setScalType参数详解
  2. Android接入OpenCv实现人脸识别
  3. android 通过wifi 获取经纬度和获取渠道
  4. 疯狂Android讲义目录结构
  5. Android定制出厂默认输入法
  6. Android下获取手机屏幕大小
  7. 实现能定点移动的seekbar
  8. 判断Android系统时间是否是24小时制
  9. Android之快捷方式一——通过应用程序创
  10. android adb am命令