zoukankan      html  css  js  c++  java
  • 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 = new ReflectUtils();
    	
    	private ReflectUtils(){ }
    	
    	public static ReflectUtils getInstance(){
    		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(" 父类"); // 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(" 接口"); 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(" 包名"); System.out.println(c.getPackage()); } /** * 输出类的完整类名 传入类, 如 传入 User.class */ public void getName(Class<?> c) { System.out.println(" 完整类名"); System.out.println(c.getName()); } /** * 输出对象的类的包名 传入对象 */ public void getPackageName(Object object) { System.out.println(" 包名"); System.out.println(object.getClass().getPackage()); } /** * 输出对象的类的完整类名 传入对象 */ public void getName(Object object) { System.out.println(" 完整类名"); 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(" 构造函数"); 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(" 域(成员)"); 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(" 方法"); 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(" 内部类"); 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 用来进行扩展类的载入。一般相应的是jrelibext文件夹中的类 * * 3)AppClassLoader 载入classpath指定的类。是最经常使用的载入器。同一时候也是java中默认的载入器。

    * */ public void getClassLoaderInfo(Class<?

    > c) { System.out.println(" 类载入器"); 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.Object
    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): 构造函数
    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 ASSERT
    08-18 22:14:56.930: I/System.out(1208): public static final int DEBUG
    08-18 22:14:56.940: I/System.out(1208): public static final int ERROR
    08-18 22:14:56.940: I/System.out(1208): public static final int INFO
    08-18 22:14:56.940: I/System.out(1208): public static final int LOG_ID_EVENTS
    08-18 22:14:56.940: I/System.out(1208): public static final int LOG_ID_MAIN
    08-18 22:14:56.940: I/System.out(1208): public static final int LOG_ID_RADIO
    08-18 22:14:56.940: I/System.out(1208): public static final int LOG_ID_SYSTEM
    08-18 22:14:56.940: I/System.out(1208): public static final int VERBOSE
    08-18 22:14:56.940: I/System.out(1208): public static final int WARN
    08-18 22:14:56.950: I/System.out(1208): private static interface android.util.Log$TerribleFailureHandler sWtfHandler
    08-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("
    Demo: 
    调用无參方法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,是被@hide标注的。

    被@hide注解的类和方法就是私有API。

    假设一个应用想调用这些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) { }



  • 相关阅读:
    java.sql.SQLException: The server time zone value 'Öйú±ê׼ʱ¼ä'...解决
    Dos命令查看端口占用及关闭教程
    IDEA中Tomcat启动出现乱码
    ORA-12514:TNS:监听程序当前无法识别连接描述符中请求的服务
    MySQL 面试问题分析总结
    深入Cpython (编写一个Cpython 模块)
    使用docker构建简约高效的镜像
    深入理解C
    ELK 起航
    jquery
  • 原文地址:https://www.cnblogs.com/lytwajue/p/7207486.html
Copyright © 2011-2022 走看看