java反射机制及在Abdroid的应用

来源:互联网 发布:mac os iso下载 编辑:程序博客网 时间:2024/05/22 19:02

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

     我们需要对象直接new就行,那么为什么要有java反射机制呢?
     java的反射机制就是增加程序的灵活性,避免将程序写死到代码里,
     例如: 实例化一个 person()对象,不使用反射,new person(); 如果想变成实例化其他类,那么必须修改源代码,并重新编译。(这是不是很烦,尤其是项目上线后更烦)
     使用反射: class.forName("person").newInstance();我们把一些后期会频繁改动的类用反射来加载,因为反射加载类只需要类的描述信息,而且这个类描述可以写到配置文件中,如 **.xml,用这个xml来管理, 这样如果想实例化其他类,只要修改配置文件的"类描述"就可以了,不需要重新修改代码并编译。有没有发现这也很好达到来解耦的效果。

     所以说利用反射机制,主要能增加程序的灵活性。如SpringMVC,struts中,请求的派发控制。当请求来到时,SpringMVC通过查询配置文件,找到该请求对应的action,然后通过反射实例化action,并调用响应method。
如果不想用反射也是可以的,不过你就只能把这些类的调用写死到代码里了,这肯定是个灾难,一来管理麻烦,偶和太高,二来代码量会非常大,三来代码里会频繁的出现判断的语句..........

     而且反射机制可以动态的去调用一些 protected 甚至是private 的方法或类,这样可以很大程度上满足我们的一些比较特殊需求。例子见:http://blog.csdn.net/wwww1988600/article/details/22884371(很简短的一个demo)

     既然反射机制这么好,那么我们在平时开发时都用这种方式好了?
     其实这样想是不对的,尽管反射非常强大,但也不能滥用。
     1 java反射需要将内存中的对象进行解析,涉及到与底层c语言的交互,速度会比较慢。
     2 使用反射技术要求程序必须在一个没有安全限制的环境中运行,如果一个程序必须在有安全限制的环境中运行,如Applet,那么这就是个问题了。
     3 由于反射允许代码执行一些在正常情况下不被允许的操作(比如访问私有的属性和方法),所以使用反射可能会导致意料之外的副作用--代码有功能上的错误,降低可移植性。反射代码破坏了抽象性,因此当平台发生改变的时候,代码的行为就有可能也随着变化。

     所以大多情况下我们是不需要用反射的,而反射机制一般框架中使用较多,因为框架要适用更多的情况,对灵活性要求较高。

     在Android开发中用反射机制可以干什么?

     在android中Google很多的类的某些方法不让第三方应用去调用,通过java反射机制能把这些隐藏方法获取出来并调用,三方应用上我们就很方便的去用这些方法。 
     例如我们需要安全的杀死某个应用的服务和进程调用ActivityManager.forceStopPackage()方法很方便 
可是你如果直接调用的话会发现报错来了,这是为什么呢?看源码明明有这个方法的,源码如下:

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. /** 
  2.  * @see #forceStopPackageAsUser(String, int) 
  3.  * @hide 
  4.  */  
  5. public void forceStopPackage(String packageName) {  
  6.     forceStopPackageAsUser(packageName, UserHandle.myUserId());  
  7. }  
     我们发现在方法得上面有个@hide的注解,它的作用是使这个方法或类在生成SDK时不可见,因此由此注释的东西,你在编译期是不可见的。这就出现了一些问题。一些明明可以访问的东西编译期却无法访问了!这使得你的程序有些本来可以完成的功能无法编译通过。当然隐藏了这些API是为了防止第三方应用打破其他应用程序,停止服务,消除他们的警报等等。
     对于这个问题,第一种方法就是自己去掉Android源码中的"@hide"标记,然后重新编译生成一个SDK。有些人一看到源码要重新编译就头疼了,其实没有想得那么复杂,如果实在不想重新编译源码的话,我们可以用反射来实现。

     利用反射的实现如下

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. ActivityManager am = (ActivityManager)this.getSystemService(Context.ACTIVITY_SERVICE);  
  2. Method m = null;  
  3. try {  
  4.     //拿到ActivityManager这个类  
  5.      Class c = Class.forName("android.app.ActivityManager");  
  6.     //根据方法名和参数,返回一个具体的具有public属性的方法  
  7.      m = c.getMethod("forceStopPackage", Class.forName("java.lang.String") );  
  8.      m.invoke(am, "com.tencent.mobileqq");  
  9. catch (IException e) {  
  10.       e.printStackTrace();  
  11. }  
     这段代码一执行我们就会杀死QQ进程了。
     不过你在运行后会发现,报异常了,看一下异常:
     Caused by: java.lang.SecurityException: Permission Denial: forceStopPackage() from pid=32341, uid=10202 requires android.permission.FORCE_STOP_PACKAGES
意思就是我们没有权限在我们的应用关闭另一个一个应用。所以我们就需要申请权限,<uses-permission android:name ="android.permission.FORCE_STOP_PACKAGES"/>
加上这个权限发现AndroidMainifest.xml提示报错“Permission is only granted to system apps”,晕!只有系统app能申请这权限,这是属于系统隐藏的权限,那么我们怎么在自己的应用里去调用这些权限呢?
[html] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     package="com.acer.shadow.apps"  
  4.     android:versionCode="1"  
  5.     android:versionName="1.0"  
  6.     android:sharedUserId="android.uid.system">     
  7.     <uses-permission android:name ="android.permission.FORCE_STOP_PACKAGES"/>  

     我们加上了 android:sharedUserId="android.uid.system"这句就能调用系统的一些隐藏权限,可是要求我们的App必须经过签名后才能正常调用。签名的方式很多,我们签名后就发现可以正常使用了。


转自:http://blog.csdn.net/gjnm820/article/details/52223577

0 0
原创粉丝点击