反射和动态加载的灵活运用,可以减小项目开发的难度,提升项目的可维护性,是需要仔细研究的。

转自:http://blog.csdn.net/hyx1990/article/details/7584789

[置顶] Android:在任意位置获取应用程序Context

3649人阅读 评论(3) 收藏 举报 android application security include classloader import

1.在任意位置获取应用程序Context

Android程序中访问资源时需要提供Context,一般来说只有在各种component中(Activity, Provider等等)才能方便的使用api来获取Context;喜欢编程的人都知道,编写工具类可以有效的实现代码复用,而在Android下某些工具类的编写很让人困惑,例如:我们要在工具类中获取SharedPreferences,那就需要Context的支持。

为了解决这写由Context带来的麻烦,我们可以自定义一个Application类来实现这种功能。

import android.app.Application;

public class ContextUtil extends Application {
private static ContextUtil instance;

public static ContextUtil getInstance() {
return instance;
}

@Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
instance = this;
}
}

然后在manifest中<application>中加入Android:name="mypackage.ContextUtil",这样我们就可以在任何一个类下面获取Context,例如:Context c=ContextUtil.getInstance();

2.context注意事项:

在android中context可以作很多操作,但是最主要的功能加载和访问资源。在android中有两种context,一种是 application context,一种是activity context,通常我们在各种类和方法间传递的是activity context。
比如一个activity的onCreate:
protected void onCreate(Bundle state) {
super.onCreate(state);

TextView label = new TextView(this); //传递context给view control
label.setText("Leaks are bad");

setContentView(label);
}
把activity context传递给view,意味着view拥有一个指向activity的引用,进而引用activity占有的资源:view hierachy, resource等。
这样如果context发生内存泄露的话,就会泄露很多内存。
这里泄露的意思是gc没有办法回收activity的内存。

Leaking an entire activity是很容易的一件事。

屏幕旋转的时候,系统会销毁当前的activity,保存状态信息,再创建一个新的。

比如我们写了一个应用程序,它需要加载一个很大的图片,我们不希望每次旋转屏 幕的时候都销毁这个图片,重新加载。实现这个要求的简单想法就是定义一个静态的Drawable,这样Activity 类创建销毁它始终保存在内存中。
实现类似:
public class myactivity extends Activity {
private static Drawable sBackground;
protected void onCreate(Bundle state) {
super.onCreate(state);

TextView label = new TextView(this);
label.setText("Leaks are bad");

if (sBackground == null) {
sBackground = getDrawable(R.drawable.large_bitmap);
}
label.setBackgroundDrawable(sBackground);//drawable attached to a view

setContentView(label);
}
}
这段程序看起来很简单,但是却问题很大。当屏幕旋转的时候会有leak(即gc没法销毁activity)。
我们刚才说过,屏幕旋转的时候系统会销毁当前的activity。但是当drawable和view关联后,drawable保存了view的 reference,即sBackground保存了label的引用,而label保存了activity的引用。既然drawable不能销毁,它所 引用和间接引用的都不能销毁,这样系统就没有办法销毁当前的activity,于是造成了内存泄露。gc对这种类型的内存泄露是无能为力的。

避免这种内存泄露的方法是避免activity中的任何对象的生命周期长过activity,避免由于对象对 activity的引用导致activity不能正常被销毁。我们可以使用application context。application context伴随application的一生,与activity的生命周期无关。application context可以通过Context.getApplicationContext或者Activity.getApplication方法获取

避免context相关的内存泄露,记住以下几点:
1. 不要让生命周期长的对象引用activity context,即保证引用activity的对象要与activity本身生命周期是一样的
2. 对于生命周期长的对象,可以使用application context
3. 避免非静态的内部类,尽量使用静态类,避免生命周期问题,注意内部类对外部对象引用导致的生命周期变化

3.获取别的包的Context

Android中有Context的概念,想必大家都知道。Context可以做很多事情,打开activity、发送广播、打开本包下文件夹和数据库、获取classLoader、获取资源等等。如果我们得到了一个包的Context对象,那我们基本上可以做这个包自己能做的大部分事情。

Context有个createPackageContext方法,可以创建另外一个包的上下文,这个实例不同于它本身的Context实例,但是功能是一样的。


这个方法有两个参数:
1。packageName 包名,要得到Context的包名
2。flags 标志位,有CONTEXT_INCLUDE_CODE和CONTEXT_IGNORE_SECURITY两个选项。 CONTEXT_INCLUDE_CODE的意思是包括代码,也就是说可以执行这个包里面的代码。CONTEXT_IGNORE_SECURITY的意思是忽略安全警告,如果不加这个标志的话,有些功能是用不了的,会出现安全警告。


下面给个小例子,执行另外一个包里面的某个类的方法。
另外一个包的包名是chroya.demo,类名Main,方法名print,代码如下:

Java代码
  1. package chroya.demo;
  2. import android.app.Activity;
  3. import android.os.Bundle;
  4. import android.util.Log;
  5. class Main extends Activity {
  6. @Override
  7. public void onCreate(Bundle savedInstanceState) {
  8. super.onCreate(savedInstanceState);
  9. }
  10. public void print(String msg) {
  11. Log.d("Main", "msg:"+ msg);
  12. }
  13. }
[java] view plain copy print ?
  1. packagechroya.demo;
  2. importandroid.app.Activity;
  3. importandroid.os.Bundle;
  4. importandroid.util.Log;
  5. classMainextendsActivity{
  6. @Override
  7. publicvoidonCreate(BundlesavedInstanceState){
  8. super.onCreate(savedInstanceState);
  9. }
  10. publicvoidprint(Stringmsg){
  11. Log.d("Main","msg:"+msg);
  12. }
  13. }

本包的调用Main的print方法的代码块如下:

Java代码
  1. Context c = createPackageContext("chroya.demo", Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
  2. //载入这个类
  3. Class clazz = c.getClassLoader().loadClass("chroya.demo.Main");
  4. //新建一个实例
  5. Object owner = clazz.newInstance();
  6. //获取print方法,传入参数并执行
  7. Object obj = clazz.getMethod("print", String.class).invoke(owner,"Hello");
[java] view plain copy print ?
  1. Contextc=createPackageContext("chroya.demo",Context.CONTEXT_INCLUDE_CODE|Context.CONTEXT_IGNORE_SECURITY);
  2. //载入这个类
  3. Classclazz=c.getClassLoader().loadClass("chroya.demo.Main");
  4. //新建一个实例
  5. Objectowner=clazz.newInstance();
  6. //获取print方法,传入参数并执行
  7. Objectobj=clazz.getMethod("print",String.class).invoke(owner,"Hello");

ok,这样,我们就调用了chroya.demo包的Main类的print方法,执行结果,打印出了Hello。

转自:

http://blog.sina.com.cn/s/blog_9564cb6e0101i2nq.html

Android反射机制实现与原理(转)

(2012-07-05 19:37:46) 转载
标签:

it

分类:android
本文介绍 Android反射机制实现与原理 ,在介绍之前,要和Java进行比较,所以先看下Java中的反射相关知识先,如下:

一、反射的概念及在Java中的类反射

  反射主要是指程序可以访问、检测和修改它本身状态或行为的一种能力。在计算机科学领域,反射是一类应用,它们能够自描述和自控制。这类应用通过某种机制来实现对自己行为的描述和检测,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。

  在Java中的反射机制,被称为Reflection。(大家看到这个单词,第一个想法应该就是去开发文档中搜一下了。)它允许运行中的Java程序对自身进行检查,并能直接操作程序的内部属性或方法。Reflection机制允许程序在正在执行的过程中,利用ReflectionAPIs取得任何已知名称的类的内部信息,包括:packagetypeparameterssuperclassimplementedinterfacesinnerclassesouterclassesfieldsconstructorsmethodsmodifiers等,并可以在执行的过程中,动态生成Instances、变更fields内容或唤起methods

  好,了解这些,那我们就知道了,我们可以利用反射机制在Java程序中,动态的去调用一些protected甚至是private的方法或类,这样可以很大程度上满足我们的一些比较特殊需求。你当然会问,反射机制在Android平台下有何用处呢?

  我们在进行Android程序的开发时,为了方便调试程序,并快速定位程序的错误点,会从网上下载到对应版本的AndroidSDK的源码(这里给大家提供一个2.3.3版本的下载链接)。你会发现很多类或方法中经常加上了“@hide”注释标记,它的作用是使这个方法或类在生成SDK时不可见,那么我们的程序可能无法编译通过,而且在最终发布的时候,就可能存在一些问题。

  那么,对于这个问题,第一种方法就是自己去掉Android源码中的"@hide"标记,然后重新编译生成一个SDK。另一种方法就是使用Java反射机制了,可以利用这种反射机制访问存在访问权限的方法或修改其域。

  废话半天,该入正题了,在进入正题之前,先给上一个反射测试类的代码,该代码中定义了我们需要进行反射的类,该类并没有实际的用途,仅供做为测试类。提示:本文提供的代码,并不是Android平台下的代码,而是一个普通的Java程序,仅仅是对Java反射机制的Demo程序,所以大家不要放在Android下编译啊,否则出现问题,别追究我的责任啦!

ReflectionTest.java package crazypebble.reflectiontest;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.Serializable;


public class ReflectionTest extends Object implements ActionListener,Serializable{

// 成员变量
private int bInt;
public Integer bInteger = new Integer( 4 );
public String strB = " crazypebble " ;
private String strA;

// 构造函数
public ReflectionTest() {

}

protected ReflectionTest( int id, String name) {

}

// 成员方法
public int abc( int id, String name) {
System.out.println(
" crazypebble ---> " + id + " - " + name);
return 0 ;
}

protected static void edf() {

}

@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated methodstub

}

}

二、反射机制中需要使用到的类

  我把需要使用的类列在下表中,其中对我们特别有用的类,通过着重标记显示出来,并将在后面的使用中逐步解释:

三、Class

  首先向大家说明一点,Class本身就是一个类,Class是该类的名称。看以下下面这个类的定义:

  publicclassMyButtonextendsButton{...}

  注意到上面的class的首字母是小写,它表示的是一种类类型,但是我们的Class是一个类,相当于上面定义的MyButton类。所以,千万不要把这里的Class做为一个类类型来理解。明白这一点,我们继续。

  Class类是整个Java反射机制的源头,Class类本身表示Java对象的类型,我们可通过一个Object对象的getClass()方法取得一个对象的类型,此函数返回的就是一个Class类。获取Class对象的方法有很多种:

  在平时的使用,要注意对这几种方法的灵活运用,尤其是对Class.forName()方法的使用。因为在很多开发中,会直接通过类的名称取得Class类的对象。


四、获取类的相关信息

1、获取构造方法

  Class类提供了四个public方法,用于获取某个类的构造方法。

    ConstructorgetConstructor(Class[]params)根据构造函数的参数,返回一个具体的具有public属性的构造函数

    ConstructorgetConstructors()返回所有具有public属性的构造函数数组

    ConstructorgetDeclaredConstructor(Class[]params)根据构造函数的参数,返回一个具体的构造函数(不分public和非public属性)

    ConstructorgetDeclaredConstructors() 返回该类中所有的构造函数数组(不分public和非public属性)

  由于Java语言是一种面向对象的语言,具有多态的性质,那么我们可以通过构造方法的参数列表的不同,来调用不同的构造方法去创建类的实例。同样,获取不同的构造方法的信息,也需要提供与之对应的参数类型信息;因此,就产生了以上四种不同的获取构造方法的方式。

get_Reflection_Constructors()
public static void get_Reflection_Constructors(ReflectionTest r){

Class temp
= r.getClass();
String className
= temp.getName(); // 获取指定类的类名

try {
Constructor[] theConstructors
= temp.getDeclaredConstructors(); // 获取指定类的公有构造方法

for ( int i = 0 ;i < theConstructors.length;i ++ ) {
int mod = theConstructors[i].getModifiers(); // 输出修饰域和方法名称
System.out.print(Modifier.toString(mod) + " " + className + " ( " );

Class[] parameterTypes
= theConstructors[i].getParameterTypes(); // 获取指定构造方法的参数的集合
for ( int j = 0 ;j < parameterTypes.length;j ++ ) { // 输出打印参数列表
System.out.print(parameterTypes[j].getName());
if (parameterTypes.length > j + 1 ){
System.out.print(
" , " );
}
}
System.out.println(
" ) " );
}
}
catch (Exception e) {
e.printStackTrace();
}
}

2、获取类的成员方法

  与获取构造方法的方式相同,存在四种获取成员方法的方式。

    MethodgetMethod(Stringname,Class[]params) 根据方法名和参数,返回一个具体的具有public属性的方法

    Method[]getMethods() 返回所有具有public属性的方法数组

    MethodgetDeclaredMethod(Stringname,Class[]params) 根据方法名和参数,返回一个具体的方法(不分public和非public属性)

    Method[]getDeclaredMethods() 返回该类中的所有的方法数组(不分public和非public属性)

get_Reflection_Method()
public static void get_Reflection_Method(ReflectionTest r) {

Class temp
= r.getClass();
String className
= temp.getName();


// Method[] methods =temp.getDeclaredMethods();
Method[] methods = temp.getMethods();

for ( int i = 0 ;i < methods.length;i ++ ) {

// 打印输出方法的修饰域
int mod = methods[i].getModifiers();
System.out.print(Modifier.toString(mod)
+ " " );

// 输出方法的返回类型
System.out.print(methods[i].getReturnType().getName());

// 获取输出的方法名
System.out.print( " " + methods[i].getName() + " ( " );

// 打印输出方法的参数列表
Class[] parameterTypes = methods[i].getParameterTypes();
for ( int j = 0 ;j < parameterTypes.length;j ++ ) {
System.out.print(parameterTypes[j].getName());
if (parameterTypes.length > j + 1 ){
System.out.print(
" , " );
}
}
System.out.println(
" ) " );
}
}

  在获取类的成员方法时,有一个地方值得大家注意,就是getMethods()方法和getDeclaredMethods()方法。

    getMethods():用于获取类的所有的public修饰域的成员方法,包括从父类继承的public方法和实现接口的public方法;

    getDeclaredMethods():用于获取在当前类中定义的所有的成员方法和实现的接口方法,不包括从父类继承的方法。

  大家可以查考一下开发文档的解释:

getMethods()-ReturnsanarraycontainingMethodobjectsforallpublicmethodsfortheclassCrepresentedbythisClass.

        MethodsmaybedeclaredinC,theinterfacesitimplementsorinthesuperclassesofC.

        Theelementsinthereturnedarrayareinnoparticularorder.

getDeclaredMethods()-ReturnsaMethodobjectwhichrepresentsthemethodmatchingthespecifiednameandparametertypes

            thatisdeclaredbytheclassrepresentedbythisClass.

  因此在示例代码的方法get_Reflection_Method(...)中,ReflectionTest类继承了Object类,实现了actionPerformed方法,并定义如下成员方法:

    

  通过这两个语句执行后的结果不同:

  aMethod[]methods=temp.getDeclaredMethods()执行后结果如下:

    

  bMethod[]methods=temp.getMethods()执行后,结果如下:

     

3、获取类的成员变量(成员属性)

  存在四种获取成员属性的方法

    FieldgetField(Stringname) 根据变量名,返回一个具体的具有public属性的成员变量

    Field[]getFields() 返回具有public属性的成员变量的数组

    FieldgetDeclaredField(Stringname) 根据变量名,返回一个成员变量(不分public和非public属性)

    Field[]getDelcaredField() 返回所有成员变量组成的数组(不分public和非public属性)

get_Reflection_Field_Value()
public static void get_Reflection_Field_Value(ReflectionTest r){

Class temp
= r.getClass(); // 获取Class类的对象的方法之一

try {
System.out.println(
" public属性 " );
Field[] fb
= temp.getFields();
for ( int i = 0 ;i < fb.length; i ++ ){

Class cl
= fb[i].getType(); // 属性的类型

int md = fb[i].getModifiers(); // 属性的修饰域

Field f
= temp.getField(fb[i].getName()); // 属性的值
f.setAccessible( true );
Object value
= (Object)f.get(r);

// 判断属性是否被初始化
if (value == null ){
System.out.println(Modifier.toString(md)
+ " " + cl + " : " + fb[i].getName());
}
else {
System.out.println(Modifier.toString(md)
+ " " + cl + " : " + fb[i].getName() + " = " + value.toString());
}
}

System.out.println(
" public& 非public 属性 " );
Field[] fa
= temp.getDeclaredFields();
for ( int i = 0 ;i < fa.length; i ++ ){

Class cl
= fa[i].getType(); // 属性的类型

int md = fa[i].getModifiers(); // 属性的修饰域

Field f
= temp.getDeclaredField(fa[i].getName()); // 属性的值
f.setAccessible( true ); // Very Important
Object value = (Object) f.get(r);

if (value == null ){
System.out.println(Modifier.toString(md)
+ " " + cl + " : " + fa[i].getName());
}
else {
System.out.println(Modifier.toString(md)
+ " " + cl + " : " + fa[i].getName() + " = " + value.toString());
}
}
}
catch (Exception e) {
e.printStackTrace();
}
}

4、获取类、属性、方法的修饰域

  类ClassMethodConstructorField都有一个public方法intgetModifiers()。该方法返回一个int类型的数,表示被修饰对象(ClassMethodConstructorField)的修饰类型的组合值。

  在开发文档中,可以查阅到,Modifier类中定义了若干特定的修饰域,每个修饰域都是一个固定的int数值,列表如下:

    

  该类不仅提供了若干用于判断是否拥有某中修饰域的方法booleanisXXXXX(intmodifiers),还提供一个StringtoString(intmodifier)方法,用于将一个表示修饰域组合值的int数转换成描述修饰域的字符串。

    

五、如何调用类中的private方法

  在介绍之前,先放一个代码吧,这段代码是参考其他文章的代码拷贝过来的,代码不算长,但是动态调用类的成员方法的过程讲解的通俗易懂。

LoadMethod.java package crazypebble.reflectiontest;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;


public class LoadMethod {


public Object Load(String cName, String MethodName,String[] types, String[] params) {

Object retObject
= null ;

try {
// 加载指定的类
Class cls = Class.forName(cName); // 获取Class类的对象的方法之二

// 利用newInstance()方法,获取构造方法的实例
// Class的newInstance方法只提供默认无参构造实例
// Constructor的newInstance方法提供带参的构造实例
Constructor ct = cls.getConstructor( null );
Object obj
= ct.newInstance( null );
// Object obj = cls.newInstance();

// 构建 方法的参数类型
Class paramTypes[] = this .getMethodTypesClass(types);

// 在指定类中获取指定的方法
Method meth = cls.getMethod(MethodName, paramTypes);

// 构建 方法的参数值
Object argList[] = this .getMethodParamObject(types, params);

// 调用指定的方法并获取返回值为Object类型
retObject = meth.invoke(obj, argList);

}
catch (Exception e) {
System.err.println(e);
}

return retObject;
}


public Class[] getMethodTypesClass(String[] types){
Class[] cs
= new Class[types.length];

for ( int i = 0 ;i < cs.length; i ++ ){
if (types[i] != null || ! types[i].trim().equals( "" )){
if (types[i].equals( " int " ) || types[i].equals( " Integer " )){
cs[i]
= Integer.TYPE;
}
else if (types[i].equals( " float " ) || types[i].equals( " Float " )){
cs[i]
= Float.TYPE;
}
else if (types[i].equals( " double " ) || types[i].equals( " Double " )){
cs[i]
= Double.TYPE;
}
else if (types[i].equals( " boolean " ) || types[i].equals( " Boolean " )){
cs[i]
= Boolean.TYPE;
}
else {
cs[i]
= String. class ;
}
}
}
return cs;
}


public Object[] getMethodParamObject(String[] types,String[] params) {

Object[] retObjects
= new Object[params.length];

for ( int i = 0 ;i < retObjects.length;i ++ ) {
if ( ! params[i].trim().equals( "" ) || params[i] != null ){
if (types[i].equals( " int " ) || types[i].equals( " Integer " )){
retObjects[i]
= new Integer(params[i]);
}
else if (types[i].equals( " float " ) || types[i].equals( " Float " )){
retObjects[i]
= new Float(params[i]);
}
else if (types[i].equals( " double " ) || types[i].equals( " Double " )){
retObjects[i]
= new Double(params[i]);
}
else if (types[i].equals( " boolean " ) || types[i].equals( " Boolean " )){
retObjects[i]
= new Boolean(params[i]);
}
else {
retObjects[i]
= params[i];
}
}
}

return retObjects;
}
}

  要调用一个类的方法,首先需要一个该类的实例(当然,如果该类是static,就不需要实例了,至于原因,你懂得!)。

1、创建一个类的实例

  在得到一个类的Class对象之后,我们可以利用类Constructor去实例化该对象。Constructor支持泛型,也就是它本身应该是Constructor<T>。这个类有一个public成员函数:TnewInstance(Object...args),其中args为对应的参数,我们通过Constructor的这个方法来创建类的对象实例。

  在代码LoadMethod.javaLoadMethodEx.java中,分别给出了两种实例化Class类的方法:一种是利用Constructor类调用newInstance()方法;另一种就是利用Class类本身的newInstance()方法创建一个实例。两种方法实现的效果是一样的。

// 利用newInstance()方法,获取构造方法的实例

// Class的newInstance方法,仅提供默认无参的实例化方法,类似于无参的构造方法

// Constructor的newInstance方法,提供了带参数的实例化方法,类似于含参的构造方法

Constructor ct
= cls.getConstructor( null );

Object obj
= ct.newInstance( null );

Object obj
= cls.newInstance();

2、行为

  Method类中包含着类的成员方法的信息。在Method类中有一个public成员函数:Objectinvoke(Objectreceiver,Object...args),参数receiver指明了调用对象,参数args指明了该方法所需要接收的参数。由于我们是在运行时动态的调用类的方法,无法提前知道该类的参数类型和返回值类型,所以传入的参数的类型是Object,返回的类型也是Object。(因为Object类是所有其他类的父类)

  如果某一个方法是Java类的静态方法,那么Objectreceiver参数可以传入null,因为静态方法从不属于对象。

3、属性

  对类的成员变量进行读写,在Field类中有两个public方法:

    Objectget(Objectobject),该方法可用于获取某成员变量的值

    Voidset(Objectobject,Objectvalue),该方法设置某成员变量的值

  其中,Object参数是需要传入的对象;如果成员变量是静态属性,在object可传入null

六、对LoadMethod.java的优化处理

  在上一节中给出的LoadMethod.java中,类LoadMethod对固定参数类型的方法进行了调用,并且参数类型是通过一个String[]数组传入,然后经过方法getMethodTypesClass()解析之后,才得到了参数的具体的类型。同时在getMethodTypesClass()getMethodParamObject()方法中,通过对传入的字符串参数进行过滤后,再处理那些可以匹配中的参数类型,其他不能匹配的参数都做为String对象来处理。如果我们调用的方法所需要的参数不是简单类型的变量,而是自定义的类对象,或者List列表,再如果我们只知道类名和方法名,不知道方法的参数类型,那我们该如何处理这些情况呢?

  因此,我对LoadMethod类进行了一定的优化处理。先附上代码:

LoadMethodEx.java package crazypebble.reflectiontest;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;


public class LoadMethodEx {


public Object Load(String cName, String MethodName,Object[] params) {

Object retObject
= null ;

try {
// 加载指定的类
Class cls = Class.forName(cName); // 获取Class类的对象的方法之二

// 利用newInstance()方法,获取构造方法的实例
// Class的newInstance方法只提供默认无参构造实例
// Constructor的newInstance方法提供带参的构造实例
Constructor ct = cls.getConstructor( null );
Object obj
= ct.newInstance( null );
// Object obj = cls.newInstance();

// 根据方法名获取指定方法的参数类型列表
Class paramTypes[] = this .getParamTypes(cls, MethodName);

// 获取指定方法
Method meth = cls.getMethod(MethodName, paramTypes);
meth.setAccessible(
true );

// 调用指定的方法并获取返回值为Object类型
retObject = meth.invoke(obj, params);

}
catch (Exception e) {
System.err.println(e);
}

return retObject;
}


public Class[] getParamTypes(Class cls, String mName){
Class[] cs
= null ;


Method[] mtd
= cls.getDeclaredMethods();
for ( int i = 0 ;i < mtd.length; i ++ ){
if ( ! mtd[i].getName().equals(mName)) { // 不是我们需要的参数,则进入下一次循环
continue ;
}

cs
= mtd[i].getParameterTypes();
}
return cs;
}
}

我们通过前面几节的一系列分析,只要我们知道了一个类的类名(包括其包的路径),那我们就可以通过Class类的一系列方法,得到该类的成员变量、构造方法、成员方法、以及成员方法的参数类型和返回类型、还有修饰域等信息。

  如果我们已经知道某个类名和需要动态调用的方法名,怎样才能不用传入方法的参数类型就可以调用该方法呢?

在已知类名的情况下,我们可以打印输出该类的所有信息,当然包括类的成员方法;然后通过给定的方法名,对打印输出的方法名进行筛选,找到我们需要的方法;再通过该方法的Method对象,得到该方法的参数类型、参数数量、和返回类型。那么我们在外部动态调用该方法时,就不需要关心该类需要传入的参数类型了,只需要传入类名、方法名、参数值的信息即可。笔者实现了一个类LoadMethodEx,先从两个类的同一个方法需要的参数方面做一个对比:

    

    

  1、LoadMethodEx类,少了一个参数(方法参数类型列表),本文直接从类LoadMethod内部获取该参数类型列表,不需要用户传入该信息,好处其实也不言而喻了。

  2、方法的参数值:类LoadMethod是将所有的方法参数都做为一个String来传入,在传入再进行解析;而本文则直接使用Object类型做为参数类型,因为invoke(Objectobj,Object...args)方法本身所需要的参数类型就是Object,避免了不必要的参数类型变换。

  在调用LoadMethodLoad()方法时,用户只需要知道类名、方法名,并且将已经初始化的参数先向上转型为Object,然后传递给Load()方法即可。方法的返回值为Object,这个肯定是由用户根据自己的需要,再转换成自己所需的类型。

执行结果 属性:
public 属性
public class java.lang.Integer : bInteger = 4
public class java.lang.String : strB = crazypebble
public & 非public 属性
private int :bInt = 0
public class java.lang.Integer : bInteger = 4
public class java.lang.String : strB = crazypebble
private class java.lang.String : strA

构造方法:
public crazypebble.reflectiontest.ReflectionTest()
protected crazypebble.reflectiontest.ReflectionTest( int ,java.lang.String)

父类
/ 接口:
父类: java.lang.Object
接口0: java.awt.event.ActionListener
接口1: java.io.Serializable

成员方法:
public int abc( int ,java.lang.String)
public void actionPerformed(java.awt.event.ActionEvent)
public final native void wait( long )
public final void wait()
public final void wait( long , int )
public boolean equals(java.lang.Object)
public java.lang.StringtoString()
public native int hashCode()
public final native java.lang.ClassgetClass()
public final native void notify()
public final native void notifyAll()

反射机制调用方法:LoadMethod
crazypebble
---> 1 - hello,android - 1 !

反射机制调用方法:LoadMethodEx
crazypebble
---> 2 - hello,android - 2 ?
返回结果:
0

七、总结

  关于反射机制,其实还有一个比较敏感的话题,就是反射机制带来我们的安全性问题。由于我在这方面研究的不是很深入,所以讲不好。大家有空可以跟踪一下在本文最后提供的两个链接,里面有一些介绍。

  我们介绍了Java的反射机制,但是在Android平台下,反射机制具体有没有什么用途呢?答案是肯定的。推荐大家看一篇文章《利用Java反射技术阻止通过按钮关闭对话框》,这篇文章为CSDN推荐为精品文章,所以还是很值得一看的。我特地从CSDN转载过来供大家一起学习。

  原链接:http://blog.csdn.net/nokiaguy/archive/2010/07/27/5770263.aspx

  转载链接:http://www.cnblogs.com/crazypebble/archive/2011/04/13/2014297.html

程序实现的源码:

AndroidReflection package crazypebble.androidreflection;

import java.lang.reflect.Field;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class MainActivity extends Activity {

private static Button btnHandler = null ;
private static Button btnShowing = null ;
AlertDialog alertDialog
= null ;

@Override
public void onCreate(Bundle savedInstanceState){
super .onCreate(savedInstanceState);
setContentView(R.layout.main);

btnHandler
= (Button)findViewById(R.id.btn_mHandler);
btnHandler.setOnClickListener(
new ButtonListener());

btnShowing
= (Button)findViewById(R.id.btn_mShowing);
btnShowing.setOnClickListener(
new ButtonListener());

alertDialog
= new AlertDialog.Builder( this )
.setTitle(
" abc " )
.setMessage(
" Content " )
.setIcon(R.drawable.icon)
.setPositiveButton(
" 确定 " , new PositiveClickListener())
.setNegativeButton(
" 取消 " , new NegativeClickListener())
.create();
}

private class ButtonListener implements OnClickListener {

@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_mHandler:
modify_mHandler();
alertDialog.show();
break ;
case R.id.btn_mShowing:
alertDialog.show();
break ;
default :
break ;
}
}
}

private class PositiveClickListener implements android.content.DialogInterface.OnClickListener{

@Override
public void onClick(DialogInterface dialog, int which) {
// 方法二时启用
modify_dismissDialog( false );
}
}

private class NegativeClickListener implements android.content.DialogInterface.OnClickListener{

@Override
public void onClick(DialogInterface dialog, int which) {
// 方法一时启用
// dialog.dismiss();

// 方法二时启用
modify_dismissDialog( true );
}
}


public void modify_mHandler() {
try {
Field field
= alertDialog.getClass().getDeclaredField( " mAlert " );
field.setAccessible(
true );
// 获取mAlert变量的值
Object obj = field.get(alertDialog);
field
= obj.getClass().getDeclaredField( " mHandler " );
field.setAccessible(
true );
// 修改mHandler变量的值,使用新的ButtonHandler类
field.set(obj, new MyButtonHandler(alertDialog));

}
catch (Exception e) {
e.printStackTrace();
}
}


public void modify_dismissDialog( boolean flag) {
try {
Field field
= alertDialog.getClass().getSuperclass().getDeclaredField( " mShowing " );
field.setAccessible(
true );
// 将mShowing变量设为false,表示对话框已经关闭
field.set(alertDialog,flag);
alertDialog.dismiss();
}
catch (Exception e) {
e.printStackTrace();
}
}
}

MyButtonHandler.java package crazypebble.androidreflection;

import java.lang.ref.WeakReference;

import android.content.DialogInterface;
import android.os.Handler;
import android.os.Message;

public class MyButtonHandler extends Handler{

// Button clicks have Message.whatas the BUTTON{1,2,3} constant
private static final int MSG_DISMISS_DIALOG = 1 ;

private WeakReference < DialogInterface > mDialog;

public MyButtonHandler(DialogInterfacedialog) {
mDialog
= new WeakReference < DialogInterface > (dialog);
}

@Override
public void handleMessage(Message msg) {
switch (msg.what) {

case DialogInterface.BUTTON_POSITIVE:
case DialogInterface.BUTTON_NEGATIVE:
case DialogInterface.BUTTON_NEUTRAL:
((DialogInterface.OnClickListener) msg.obj).onClick(mDialog.get(),msg.what);
break ;
}
}
}

  看完上面这篇文章之后,希望大家明确一点的是:反射机制通过voidsetAccessible(booleanflag)方法可以得到一个类的private的方法和属性,使用这些private的方法和属性,已经可以做一些超越限制的事情了。所以在使程,还需谨慎啊!

  希望本言语对大伙有所帮助!!!


更多相关文章

  1. Android(安卓)9.0 Bluetooth源码分析(三)蓝牙配对流程
  2. Android中文API(114)——TabWidget
  3. Android中动态刷新从服务器上获取的数据
  4. android sdk 下载失败解决方法
  5. android Button字体设置颜色
  6. Android(安卓)IllegalArgumentException: Cannot draw recycled
  7. Android(安卓)签名打包出现的错误的解决方法以及代码中获取应用
  8. Android(安卓)SDK 离线安装方法
  9. 杂乱之android的AlertDialog应用

随机推荐

  1. android Eclipse开发问题汇总
  2. 【精华】Android应用程序框架分析
  3. 二十三、Android源代码是这样搞到的(图解
  4. android clipChildren与clipToPadding
  5. 国外的通过Binder类创建Bound Service例
  6. [转]Android(安卓)应用开发中国大学生挑
  7. Android(安卓)Q 不叫 Q,正式命名为 Androi
  8. android shape 使用小结
  9. Android开发注意点小记
  10. 安卓布局:线性布局(Linearlayout)和相对布