您的位置:首页 > 移动开发 > Android开发

Android 注解和反射原理和实现学习(上)

2015-06-26 09:49 483 查看
注解:

Annotation其实就是代码里的特殊标记, 它用于替代配置文件,也就是说,传统方式通过配置文件告诉类如何运行,有了注解技术后,开发人员可以通过注解告诉类如何运行。注解是以'@注解名'在代码中存在的,根据注解参数的个数,我们可以将注解分为:标记注解、单值注解、完整注解三类。它们都不会直接影响到程序的语义,只是作为注解(标识)存在,我们可以通过反射机制编程实现对这些元数据(用来描述数据的数据)的访问。有三个最基本的注解,@Override: 限定重写父类方法, 该注解只能用于方法;@Deprecated:
用于表示某个程序元素(类, 方法等)已过时;@SuppressWarnings: 抑制编译器警告。注解属性的类型只能是如下类型:String类型、8大基本数据类型、Class类型、枚举类型、注解类型以及以上类型的一维数组。有如果一个注解只有一个属性,并且这个属性的名称为value的话,那么使用注解时可以省略value=部分,如@MyAnnotation(“xxx"),直接赋值。

元注解:

元注解也就是注解的注解,Java中提供了四种元注解,专门负责注解其他的注解,分别如下:

1.@Retention元注解,表示需要在什么级别保存该注解信息(生命周期)。 如果注解类型声明中不存在 Retention 注解,则保留策略默认为 RetentionPolicy.CLASS。可选的 RetentionPoicy参数包括:

RetentionPolicy.SOURCE: 停留在java源文件,编译器被丢掉。

RetentionPolicy.CLASS:停留在class文件中,但会被VM丢弃(默认)。

RetentionPolicy.RUNTIME:内存中的字节码,VM将在运行时也保留注解,因此可以通过反射机制读取注解的信息。



2.@Target说明了Annotation所修饰的对象范围:Annotation可被用于 packages、types(类、接口、枚举、Annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)。在Annotation类型的声明中使用了target可更加明晰其修饰的目标。只有元注解类型直接用于注解时,Target 元注释才有效。如果元注解类型用作另一种注解类型的成员,则无效。注释类型所适用的程序元素的种类。如果注释类型声明中不存在 Target
元注释,则声明的类型可以用在任一程序元素上。如果存在这样的元注释,则编译器强制实施指定的使用限制。

ElementType.CONSTRUCTOR: 构造器声明

ElementType.FIELD: 成员变量、对象、属性(包括enum实例)

ElementType.LOCAL_VARIABLE: 局部变量声明

ElementType.METHOD: 方法声明

ElementType.PACKAGE: 包声明

ElementType.PARAMETER: 参数声明

ElementType.TYPE: 类、接口(包括注解类型)或enum声明



3.@Documented将注解包含在JavaDoc中

某一类型的注释将通过 javadoc 和类似的默认工具进行文档化,应使用此类型来注释这些类型的声明,其注释会影响由其客户端注释的元素的使用。如果类型声明是用Documented 来注释的,则其注释将成为注释元素的公共 API 的一部分。

4.@Inheried允许子类继承父类中的注解,注释类型被自动继承。

如果在注释类型声明中存在 Inherited 元注释,并且用户在某一类声明中查询该注释类型,同时该类声明中没有此类型的注释,则将在该类的超类中自动查询该注释类型。此过程会重复进行,直到找到此类型的注释或到达了该类层次结构的顶层 (Object) 为止。如果没有超类具有该类型的注释,则查询将指示当前类没有这样的注释。如果使用注释类型注释类以外的任何事物,此元注释类型都是无效的。此元注释仅促成从超类继承注释,对已实现接口的注释无效。

反射:

利用反射机制在Java程序中,动态的去调用一些protected甚至是private的方法或类,这样可以很大程度上满足我们的一些比较特殊需求。在Java中的反射机制,被称为Reflection。它允许运行中的Java程序对自身进行检查,并能直接操作程序的内部属性或方法。Reflection机制允许程序在正在执行的过程中,利用Reflection APIs取得任何已知名称的类的内部信息,包括:package、 type parameters、 superclass、 implemented interfaces、
inner classes、 outer classes、 fields、 constructors、 methods、 modifiers等,并可以在执行的过程中,动态生成Instances、变更fields内容或唤起methods。简单的来说,反射机制就是允许编程人员在程序运行时来改变程序的结构或者变量的类型。通过这个特性,我们可以在运行时得知某个类的所有成员,包括其属性和方法,同时也能够调用这些方法。请注意反射机制的特殊之处就在于可以使用编译期间完全未知的类,也就是通过反射机制可以加载一个在运行时才得知名字的类,从而取得其内部的成员函数并调用。



Class 表示某个具体的类或接口

Object 每个类都使用Object 做为超类,所有对象都实现这个类的方法

Constructor 封装了Class的构造方法

Field 提供有关类或接口的属性信息,以及对它的动态访问权限

Method 提供类或者接口上的方法的信息

Modifier 封装了Class(method、fields)的修饰域

获取类的相关信息

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

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

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

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

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

Class<? extends E>  clazz = me.getClass();
String clazzName = clazz.getName();//获取类名
//获取构造函数
//获取某个确定的public构造函数,带一个int参数
Constructor<? extends E> constructor= clazz.getConstructor(int.class);
//获取某个确定的public构造函数,带一个int参数
Constructor<?>[]  constructors = clazz.getConstructors();
//获取某个确定的public或非public构造函数,带一个int参数
Constructor<? extends E>  constructorm = clazz.getDeclaredConstructor(int.class);
//获取某个确定的public或非public构造函数,带一个int参数
Constructor<?>[] constructorsm = clazz.getDeclaredConstructors();


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

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

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

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

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

说明:方法getDeclaredMethods()只能获取到由当前类定义的所有方法,不能获取从父类继承的方法。

方法getMethods() 不仅能获取到当前类定义的public方法,也能得到从父类继承和已经实现接口的public方法。

//获取方法
//获取public的方法 方法名  和方法参数
Method method = clazz.getMethod("name", String.class);
//获取public的所有方法
Method[] methods = clazz.getMethods();
//获取public或非public的方法 方法名  和方法参数
Method methodm = clazz.getDeclaredMethod("name", String.class);
//获取public或非public的所有方法
Method[] methodsm = clazz.getDeclaredMethods();

//获取方法名
method.getName();
//获取方法的修饰符、这里获取到的修饰符需要转换的
int modifiers = method.getModifiers();
String strModifiers = Modifier.toString(modifiers);
//获取方法的返回类型
String returnType = method.getReturnType().getName();
//获取方法的参数列表
Class<?>[] parameterTypes = method.getParameterTypes();
parameterTypes[0].getName();


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

Field getField(String name)根据变量名,返回一个具体的具有public属性的成员变量

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

Field getDeclaredField(String name)根据变量名,返回一个成员变量(不分public和非public属性)

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

//获取成员变量
Field field = clazz.getField("i");
clazz.getFields();
clazz.getDeclaredField("i");
clazz.getDeclaredFields();
//属性类型
field.getType();
//属性修饰符
field.getModifiers();
//属性名
String fieldName = field.getName();
Field fieldm = clazz.getField(fieldName);
//设置私有属性可以访问
fieldm.setAccessible(true);
//属性值
Object fieldValue = fieldm.get(me);
//
if (fieldValue != null) {
String fieldValuem= fieldValue.toString();
Log.d("", ""+fieldValuem);
}


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

类Class、Method、Constructor、Field都有一个public方法int getModifiers()。该方法返回一个int类型的数,表示被修饰对象( Class、 Method、 Constructor、 Field )的修饰类型的组合值。Modifier类中定义了若干特定的修饰域,每个修饰域都是一个固定的int数值,列表如下:



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

//获取方法的修饰符、这里获取到的修饰符需要转换的
int modifiers = method.getModifiers();
String strModifiers = Modifier.toString(modifiers);


代码学习

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

public class LoadMethod {

/**
* 在运行时加载指定的类,并调用指定的方法
* @param cName            Java的类名
* @param MethodName       方法名
* @param types            方法的参数类型
* @param params        方法的参数值
* @return
*/
public Object Load(String cName, String MethodName, String[] types, String[] params) {
Object retObject = null;
try {
// 加载指定的类
Class<?> clazz = Class.forName(cName);
// 利用newInstance()方法,获取构造方法的实例
// Class的newInstance方法只提供默认无参构造实例
// Constructor的newInstance方法提供带参的构造实例
Constructor<?> constructor = clazz.getConstructor();
Object obj = constructor.newInstance();
//如果是无参数的构造函数创建实例,用这个方法简单一些
//Object obj = clazz.newInstance();
//方法的参数类型
Class<?> paramTypes[] = this.getMethodTypesClass(types);
// 在指定类中获取指定的方法
Method meth = clazz.getMethod(MethodName, paramTypes);
//方法的参数值
Object argList[] = this.getMethodParamObject(types, params);
//调用指定的方法并获取返回值为Object类型
retObject = meth.invoke(obj, argList);
} catch (Exception e) {
System.err.println(e);
}
return retObject;
}

/***获取参数类型,返回值保存在Class[]中*/
private 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;
}

/***获取参数Object[]*/
private 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] = Integer.valueOf(params[i]);
}
else if(types[i].equals("float")||types[i].equals("Float")){
retObjects[i]= Float.valueOf(params[i]);
}
else if(types[i].equals("double")||types[i].equals("Double")){
retObjects[i]= Double.valueOf(params[i]);
}
else if(types[i].equals("boolean")||types[i].equals("Boolean")){
retObjects[i]= Boolean.valueOf(params[i]);
}
else{
retObjects[i] = params[i];
}
}
}
return retObjects;
}
}


这是Android 注解和反射原理和实现学习(上),接下来将会给出博文Android 注解和反射原理和实现学习(下)如何调用类中的private方法以及对LoadMethod.java的优化处理,欢迎大家学习。





















内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: