当前位置: 代码迷 >> Android >> Java反射及其在Android中的应用学习小结
  详细解决方案

Java反射及其在Android中的应用学习小结

热度:94   发布时间:2016-04-27 23:22:26.0
Java反射及其在Android中的应用学习总结

一. Java反射机制

Reflection 是Java被视为动态(或准动态)语言的一个关键性质。这个机制允许程序在运行时透过Reflection APIs取得任何一个已知名称的class的内部信息,包括其modifiers(诸如public, static 等等)、superclass(例如Object)、实现之interfaces(例如Serializable),也包括fields和methods的所有信息,并可于运行时改变fields内容或调用methods(包括被声明为private的field和method)。


二. 打印一个类的信息Demo


可以写一个Utils类来打印一个类的信息: 

ReflectUtils.java

package com.example.test;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.Method;import java.lang.reflect.Modifier;import java.lang.reflect.Type;public class ReflectUtils {	// 要打印的类	private Class classTobePrint;//	单例模式	private static ReflectUtils reflectUtils;		private ReflectUtils(){ }		public static ReflectUtils getInstance(){		if ( reflectUtils == null ) {			synchronized (ReflectUtils.class) {				if ( reflectUtils == null ) {					reflectUtils = new ReflectUtils();				}			}		}		return reflectUtils;	}		public ReflectUtils setClass(Class<?> c){		this.classTobePrint = c;		return reflectUtils;	}		public ReflectUtils setClass(String className) throws ClassNotFoundException {		this.classTobePrint = getClass(className);		return reflectUtils;	}//	打印输出类的所有信息	public void  listAllInfo() throws ClassNotFoundException {				if ( classTobePrint == null ) {			return ;		}				// 要打印的类		Class cc = classTobePrint;		// 输出父类名		getSuperClassName(cc);		// 输出接口名		getInterfaceInfo(cc);		// 输出构造函数		getConstructInfo(cc.getDeclaredConstructors());		// 输出域		getFildInfo(cc.getDeclaredFields());		// 输出方法		getMethodsInfo(cc.getDeclaredMethods());		// 输出内部类		getInerclassInfo(cc.getDeclaredClasses());		// 输出类加载器		getClassLoaderInfo(cc);		//		复位classTobeTest		classTobePrint = null;	}	/**	 * 输出父类名	 */	public void getSuperClassName(Class<?> c) {		System.out.println("\n父类"); //		Class<?> superClass = c.getSuperclass();//		System.out.println(superClass.getName());		Type t = c.getGenericSuperclass();  		if (t==null) {			System.out.println("无父类");		}	    System.out.println(t);	}	/**	 * 取得类实现的接口,因为接口类也属于Class,所以得到接口中的方法也是一样的方法得到哈	 */	public void getInterfaceInfo(Class<?> c) {		Class<?> interfaces[] = c.getInterfaces();		System.out.println("\n接口");		if (interfaces.length == 0) {			System.out.println("无接口");			return;		}		for (Class<?> class1 : interfaces) {			System.out.println(class1.getName());		}	}	/**	 * 输出类的包名 传入类 , 如 传入 User.class	 */	public void getPackageName(Class<?> c) {		System.out.println("\n包名");		System.out.println(c.getPackage());	}	/**	 * 输出类的完整类名 传入类, 如 传入 User.class	 */	public void getName(Class<?> c) {		System.out.println("\n完整类名");		System.out.println(c.getName());	}	/**	 * 输出对象的类的包名 传入对象	 */	public void getPackageName(Object object) {		System.out.println("\n包名");		System.out.println(object.getClass().getPackage());	}	/**	 * 输出对象的类的完整类名 传入对象	 */	public void getName(Object object) {		System.out.println("\n完整类名");		System.out.println(object.getClass().getName());	}	/**	 * 得到一个类的类型 传入完整类名,如 "cn.lee.demo.Person"	 * 	 * @throws ClassNotFoundException	 */	public Class<?> getClass(String className) throws ClassNotFoundException {		Class<?> c = Class.forName(className);		return c;	}	/**	 * 输出构造函数	 */	public void getConstructInfo(			@SuppressWarnings("rawtypes") Constructor[] cons) {		System.out.println("\n构造函数");		if (cons.length == 0) {			System.out.println("无构造函数");			return;		}		for (Constructor<?> con : cons) {			// 打印修饰符			int mo = con.getModifiers();			System.out.print(Modifier.toString(mo));			// 打印构造函数名			System.out.print(" " + con.getName());			// 输出参数;			getParmsInfo(con.getParameterTypes());			System.out.println();		}	}	/**	 * 输出所有域 (成员) 传入 Field[] fields = class1.getDeclaredFields();	 */	public void getFildInfo(Field[] fields) {		System.out.println("\n域(成员)");		if (fields.length == 0) {			System.out.println("无域(成员)");			return;		}		for (Field field : fields) {			int m = field.getModifiers();			System.out.print(Modifier.toString(m) + " ");			System.out.print(field.getType() + " ");			System.out.println(field.getName());		}	}	/**	 * 输出所有方法 传入Method[] methods = class1.getDeclaredMethods();	 */	public void getMethodsInfo(Method[] method) {		System.out.println("\n方法");		if (method.length == 0) {			System.out.println("无方法");			return;		}		for (Method mt : method) {			int m = mt.getModifiers();			// 修饰符			System.out.print(Modifier.toString(m) + " ");			// 输出返回类型			System.out.print(mt.getReturnType());			System.out.print(" " + mt.getName());			getParmsInfo(mt.getParameterTypes());		}	}	/**	 * 输出方法里的参数的信息	 */	public void getParmsInfo(@SuppressWarnings("rawtypes") Class[] parm) {		System.out.print(" (");		for (Class<?> c : parm) {			System.out.print(c.getName() + "   ");		}		System.out.print(")");		System.out.println();	}	/**	 * 输出内部类	 */	public void getInerclassInfo(			@SuppressWarnings("rawtypes") Class[] innerClass) {		System.out.println("\n内部类");		if (innerClass.length == 0) {			System.out.println("无内部类");			return;		}		for (@SuppressWarnings("rawtypes")		Class c : innerClass) {			System.out.println(c.getName() + "{");			getMethodsInfo(c.getDeclaredMethods());			System.out.println("}");		}	}	/**	 * 输出类加载器的信息 * 在java中有三种类类加载器。[这段资料网上截取]	 * 	 * 1)Bootstrap ClassLoader 此加载器采用c++编写,一般开发中很少见。	 * 	 * 2)Extension ClassLoader 用来进行扩展类的加载,一般对应的是jre\lib\ext目录中的类	 * 	 * 3)AppClassLoader 加载classpath指定的类,是最常用的加载器。同时也是java中默认的加载器。	 * 	 */	public void getClassLoaderInfo(Class<?> c) {		System.out.println("\n类加载器");		System.out.println(c.getClassLoader().getClass().getName());	}}


在android中执行

ReflectUtils.getInstance().setClass("android.util.Log").listAllInfo();

得到的打印结果:

08-18 22:14:56.890: I/System.out(1208): 父类08-18 22:14:56.930: I/System.out(1208): class java.lang.Object08-18 22:14:56.930: I/System.out(1208): 接口08-18 22:14:56.930: I/System.out(1208): 无接口08-18 22:14:56.930: I/System.out(1208): 构造函数08-18 22:14:56.930: I/System.out(1208): private android.util.Log ()08-18 22:14:56.930: I/System.out(1208): 域(成员)08-18 22:14:56.930: I/System.out(1208): public static final int ASSERT08-18 22:14:56.930: I/System.out(1208): public static final int DEBUG08-18 22:14:56.940: I/System.out(1208): public static final int ERROR08-18 22:14:56.940: I/System.out(1208): public static final int INFO08-18 22:14:56.940: I/System.out(1208): public static final int LOG_ID_EVENTS08-18 22:14:56.940: I/System.out(1208): public static final int LOG_ID_MAIN08-18 22:14:56.940: I/System.out(1208): public static final int LOG_ID_RADIO08-18 22:14:56.940: I/System.out(1208): public static final int LOG_ID_SYSTEM08-18 22:14:56.940: I/System.out(1208): public static final int VERBOSE08-18 22:14:56.940: I/System.out(1208): public static final int WARN08-18 22:14:56.950: I/System.out(1208): private static interface android.util.Log$TerribleFailureHandler sWtfHandler08-18 22:14:56.950: I/System.out(1208): 方法08-18 22:14:56.950: I/System.out(1208): public static int d (java.lang.String   java.lang.String   )08-18 22:14:56.960: I/System.out(1208): public static int d (java.lang.String   java.lang.String   java.lang.Throwable   )08-18 22:14:56.960: I/System.out(1208): public static int e (java.lang.String   java.lang.String   )08-18 22:14:56.960: I/System.out(1208): public static int e (java.lang.String   java.lang.String   java.lang.Throwable   )08-18 22:14:56.960: I/System.out(1208): public static class java.lang.String getStackTraceString (java.lang.Throwable   )08-18 22:14:56.960: I/System.out(1208): public static int i (java.lang.String   java.lang.String   )08-18 22:14:56.960: I/System.out(1208): public static int i (java.lang.String   java.lang.String   java.lang.Throwable   )08-18 22:14:56.960: I/System.out(1208): public static native boolean isLoggable (java.lang.String   int   )08-18 22:14:56.970: I/System.out(1208): public static int println (int   java.lang.String   java.lang.String   )08-18 22:14:56.970: I/System.out(1208): public static native int println_native (int   int   java.lang.String   java.lang.String   )08-18 22:14:56.970: I/System.out(1208): public static interface android.util.Log$TerribleFailureHandler setWtfHandler (android.util.Log$TerribleFailureHandler   )08-18 22:14:56.970: I/System.out(1208): public static int v (java.lang.String   java.lang.String   )08-18 22:14:56.980: I/System.out(1208): public static int v (java.lang.String   java.lang.String   java.lang.Throwable   )08-18 22:14:56.980: I/System.out(1208): public static int w (java.lang.String   java.lang.String   )08-18 22:14:56.980: I/System.out(1208): public static int w (java.lang.String   java.lang.String   java.lang.Throwable   )08-18 22:14:56.980: I/System.out(1208): public static int w (java.lang.String   java.lang.Throwable   )08-18 22:14:56.980: I/System.out(1208): static int wtf (int   java.lang.String   java.lang.String   java.lang.Throwable   boolean   )08-18 22:14:56.980: I/System.out(1208): public static int wtf (java.lang.String   java.lang.String   )08-18 22:14:56.980: I/System.out(1208): public static int wtf (java.lang.String   java.lang.String   java.lang.Throwable   )08-18 22:14:56.980: I/System.out(1208): public static int wtf (java.lang.String   java.lang.Throwable   )08-18 22:14:56.980: I/System.out(1208): public static int wtfStack (java.lang.String   java.lang.String   )08-18 22:14:56.980: I/System.out(1208): 内部类08-18 22:14:56.980: I/System.out(1208): android.util.Log$TerribleFailureHandler{08-18 22:14:56.990: I/System.out(1208): 方法08-18 22:14:57.000: I/System.out(1208): public abstract void onTerribleFailure (java.lang.String   android.util.Log$TerribleFailure   )08-18 22:14:57.000: I/System.out(1208): }08-18 22:14:57.000: I/System.out(1208): android.util.Log$TerribleFailure{08-18 22:14:57.000: I/System.out(1208): 方法08-18 22:14:57.000: I/System.out(1208): 无方法08-18 22:14:57.000: I/System.out(1208): }08-18 22:14:57.010: I/System.out(1208): 类加载器08-18 22:14:57.010: I/System.out(1208): java.lang.BootClassLoader

三. Java反射操作域和方法的Demo

先写一个要被进行演示操作的类User.java

package com.yjq.reflect;import java.io.Serializable;import com.yjq.reflect.UserDescribtion.Sex;public class User implements Serializable{	private int id;		private String name;		private Sex sex;		public User(){		super();	}	public User(int _id,String _name,Sex _sex){		this.id=_id;		this.name=_name;		this.sex=_sex;	}	public int getId() {		return id;	}	public void setId(int id) {		this.id = id;	}	public String getName() {		return name;	}	public void setName(String name) {		this.name = name;	}	public Sex getSex() {		return sex;	}	public void setSex(Sex sex) {		this.sex = sex;	}	@Override	public String toString() {		return "User [id=" + id + ", name=" + name + ", sex=" + sex + "]";	}	public void test(){ testMethod(1,"hello");}		private void testMethod(int i,String s){ 		System.out.println("private method in user "+i+s);		}public enum Sex {		MALE("男"), FEMALE("女");		// 枚举对象的属性		private String sexDescribtion;		// 枚举对象构造函数		private Sex(String sx) {			this.sexDescribtion = sx;		}}}
Demo:

// 通过Java反射调用方法	private void callMethodsDemo() throws ClassNotFoundException,			NoSuchMethodException, SecurityException, IllegalAccessException,			IllegalArgumentException, InvocationTargetException,			InstantiationException {		Class<?> class1 = null;		class1 = Class.forName("com.yjq.reflect.User");		System.out.println("\nDemo: \n调用无参方法testMethod():");		Method method = class1.getDeclaredMethod("testMethod", new Class[]{int.class, String.class});//				.getMethod("test");   getMethod只能调用public的方法		method.setAccessible(true);		method.invoke(class1.newInstance(),23,"hello23");				System.out.println("调用有参方法setId(int):");          method = class1.getMethod("setId",int.class);          User user = (User)class1.newInstance();        method.invoke(user,100);         System.out.println(user);	}	// 通过Java反射操作域(成员)	private void setFieldsDemo() throws InstantiationException,			IllegalAccessException, ClassNotFoundException,			NoSuchFieldException, SecurityException {		Class<?> class1 = null;		class1 = Class.forName("com.yjq.reflect.User");		Object obj = class1.newInstance(); // 须有无参构造函数		Field userNameField = class1.getDeclaredField("name");		userNameField.setAccessible(true);		userNameField.set(obj, "==Myname==");		System.out.println("Demo: 通过Java反射操作域(成员): 修改属性之后得到属性变量的值:"				+ userNameField.get(obj));	}	// 通过java反射创建对象	private void getInstanceDemo() throws InstantiationException,			IllegalAccessException, IllegalArgumentException,			InvocationTargetException, ClassNotFoundException {		User user1 = null;		User user2 = null;		Class<?> class1 = Class.forName("com.yjq.reflect.User");		// 得到一系列构造函数集合		Constructor<?>[] constructors = class1.getConstructors();		user1 = (User) constructors[0].newInstance();		user1.setId(112031);		user1.setName("leeFeng");		user2 = (User) constructors[1].newInstance(12432, "Mali", Sex.FEMALE);		System.out.println("Demo:通过java反射创建对象");		System.out.println(user1);		System.out.println(user2);	}

四. Java反射在android中的应用

摘自:http://mysuperbaby.iteye.com/blog/1458966

在Android中,可以从下面两点考虑来使用Java反射(Java Reflection)机制,从而达到意想不到的效果。这里也将展示Google是怎样在自己的应用中来使用Java反射机制的。

 

1. 同时兼容新老版本的SDK

Android往往会在新版本中引入一些新的API来替代老的API,这些新的API在性能或者易用性上比老的API更好。但为了兼容性,新老API往往是共存的。

在这种情况下,你的应用如果调用了新的API,是没办法在安装老版本Android的设备上运行的,但如果使用老的API,又没办法在安装新版本Android的设备上体现新API的性能。

这时候,就可以使用Java反射机制,从而实现一个apk,如果安装在老版本Android的设备上,则调用老的API;安装在新版本Android的设备上,则调用新的API。

下面是来自Google的一段代码:

Java代码  收藏代码
  1. public class SharedPreferencesCompat {  
  2.   
  3.     private static final Method sApplyMethod = findApplyMethod();  
  4.   
  5.     private static Method findApplyMethod() {  
  6.         try {  
  7.             return SharedPreferences.Editor.class.getMethod("apply"new Class[0]);  
  8.         } catch (NoSuchMethodException e) {  
  9.             return null;  
  10.         }  
  11.     }  
  12.   
  13.     public static void apply(SharedPreferences.Editor editor) {  
  14.         if (sApplyMethod != null) {  
  15.             try {  
  16.                 sApplyMethod.invoke(editor, new Object[0]);  
  17.                 return;  
  18.             } catch (IllegalAccessException e) {  
  19.             } catch (InvocationTargetException e) {  
  20.             }  
  21.         }  
  22.         editor.commit();  
  23.     }  
  24. }  

 

2. 使用私有的API

如果在Eclipse上开发应用,必须调用对应的Android SDK的标准API,即在开发文档中说明的API。调用非标准的即私有的API,是编译不过的。

但Android实际上有很多API,[email protected]@[email protected]??用这些API,则只有在编译整个系统image的时候才能编译过,而在Eclipse上是编译不过的。所以,这些API往往会被手机开发商的本地应用调用,则第三方的应用是没办法调用的。

这种情况下,可以使用Java反射机制来调用这些私有的API。一旦编译通过生成了apk,就能正常在手机上运行,因为这样的API的实现已经在手机系统中只是没有公开出来。

下面是来自Google的一段代码:

Java代码  收藏代码
  1. private static final String AMR_INPUT_STREAM_CLASS = "android.media.AmrInputStream";  
  2.   
  3. private static Class<?> getAmrInputStreamClass() throws ClassNotFoundException {  
  4.     return Class.forName(AMR_INPUT_STREAM_CLASS);  
  5. }  
  6.   
  7. private static InputStream createAmrInputStream(InputStream in) {  
  8.     try {  
  9.         Class<?> clazz = getAmrInputStreamClass();  
  10.         Constructor<?> constructor = clazz.getConstructor(new Class[] { InputStream.class });  
  11.         return (InputStream)constructor.newInstance(new Object[] { in });  
  12.     }   
  13.     ...  
  14. }  

 3.补充:SharedPreferences数据文件存储到sd卡上?

SharedPreference原则上只能保存在当前应用程序私有的shared_prefs目录中,不过可以利用反射技术改变系统内定的文件保存路径。try {    Field field = ContextWrapper.class.getDeclaredField("mBase");    field.setAccessible(true);    Object obj = field.get(this);    field = obj.getClass().getDeclaredField("mPreferencesDir");    field.setAccessible(true);    File file = new File("/sdcard/");    field.set(obj, file);    SharedPreferences mySharedPreferences = getSharedPreferences("config", Activity.MODE_PRIVATE);    SharedPreferences.Editor editor = mySharedPreferences.edit();    editor.putString("name", "nancy");    editor.commit();} catch (Exception e) { }



版权声明:本文为博主原创文章,未经博主允许不得转载。

  相关解决方案