反射、注解、与依赖注入
- 参考资料
- 反射、注解、与依赖注入总结
反射(Reflection)
概念
为获取反射类和对象的信息,提供了类和接口。
作用
反射允许编程访问字段、方法以及构造函数的信息,并且使用反射得到的字段、方法和构造函数去操作对象潜在的副本(Class对象)
类和方法
一、获取对象的三种方式
- 第一种 知道类的名称,直接获取class对象
Class<?> class1 = LoginActivity.class
- 第二种 如果已经得到某个对象,可以通过该对象获取Class对象
LoginActivity activity = new LoginActivity();
Class<?> cls2 = activity.getClass();
- 第三种 如果你在编译期获取不到目标类型,但是你知道它的完整类路径,那么你可以通过如下的形式来获取 Class 对象,这样获取可能会抛出异常 ClassNotFoundException。
try {
Class<?> cls3 = Class.forName("com.sun.study.ui.activity.LoginActivity");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
二、反射的相关方法示例
- 方法
getName():获得类的完整名字。
newInstance():通过类的不带参数的构造方法创建这个类的一个对象。
getFields():获得类的public类型的属性。
getDeclaredFields():获得类的所有属性。
getMethods():获得类的public类型的方法。
getDeclaredMethods():获得类的所有方法。
getMethod(String name, Class[] parameterTypes):获得类的特定方法。
getModifiers()和Modifier.toString():获得属修饰符,例如private,public,static等
getReturnType():获得方法的返回类型
getParameterTypes():获得方法的参数类型
getConstructors():获得类的public类型的构造方法。
getConstructor(Class[] parameterTypes):获得类的特定构造方法。
getSuperclass():获取某类的父类
getInterfaces():获取某类实现关示例
- 示例1:获得类的所有方法(Method)信息
private void getMethodsInfo() {
Class<ReflectionActivity> cls = ReflectionActivity.class;
Method[] methods = cls.getDeclaredMethods();
if (methods == null) return;
StringBuilder sb = new StringBuilder();
for (Method method:methods) {
sb.append(Modifier.toString(method.getModifiers())).append(" ");
sb.append(method.getReturnType()).append(" ");
sb.append(method.getName()).append("(");
Class[] parameters = method.getParameterTypes();
if (parameters != null) {
for (int i=0; i<parameters.length; i++) {
Class paramCls = parameters[i];
sb.append(paramCls.getSimpleName());
if (i < parameters.length - 1) sb.append(", ");
}
}
sb.append(")\n\n");
}
tvInfo.setText(sb.toString());
}
- 示例2:获得类的所有属性(Field)信息,并修改类型Int属性i的值
private void modifyFieldValue() {
Class<ReflectionActivity> cls = ReflectionActivity.class;
Field[] fields = cls.getDeclaredFields();
if (fields == null) return;
StringBuilder sb = new StringBuilder();
sb.append("获得类的所有属性信息:\n\n");
for (Field field:fields) {
sb.append(Modifier.toString(field.getModifiers())).append(" ");
sb.append(field.getType().getSimpleName()).append(" ");
sb.append(field.getName()).append(";");
sb.append("\n\n");
}
try {
sb.append("属性i的默认值:i = ");
Field f = cls.getDeclaredField("i");
sb.append(f.getInt("i")).append("\n\n");
f.set("i", 100);
sb.append("属性i修改后的值:i = ");
sb.append(f.getInt("i")).append("\n\n");
} catch (Exception e) {
e.printStackTrace();
}
tvInfo.setText(sb.toString());
toolbar.setSubtitle("修改类型Int属性i的值");
}
注解(Annotations)
概念
也叫原数据,一种代码级别的说明。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。
作用
- 标记作用,用于告诉编译器一些信息,让编译器能够实现基本的编译检查,如@Override、Deprecated
- 编译时动态处理,动态生成代码,如Butter Knife、Dagger 2
- 运行时动态处理,获得注解信息,如Retrofit
注解的分类
第一种分法
- 基本内置注解,是指Java自带的几个Annotation,如@Override、Deprecated、@SuppressWarnings等
- 元注解(meta-annotation),是指负责注解其他注解的注解,JDK 1.5及以后版本定义了4个标准的元注解类型,如下:
1、@Target
2、@Retention
3、@Documented
4、@Inherited
- 自定义注解,根据需要可以自定义注解,自定义注解需要用到上面的meta-annotation
第二种分法,根据作用域分类
- 源码时注解(RetentionPolicy.SOURCE)
- 编译时注解(RetentionPolicy.CLASS)
- 运行时注解(RetentionPolicy.RUNTIME)
注解相关知识点
元注解相关信息
- @Target:指Annotation所修饰的对象范围,通过ElementType取值有8种,如下
TYPE:类、接口(包括注解类型)或枚举
FIELD:属性
METHOD:方法
PARAMETER:参数
CONSTRUCTOR:构造函数
LOCAL_VARIABLE:局部变量
ANNOTATION_TYPE:注解类型
PACKAGE:包
- @Retention:指Annotation被保留的时间长短,通过RetentionPolicy取值有3种,如下:
SOURCE:在源文件中有效(即源文件保留)
CLASS:在class文件中有效(即class保留)
RUNTIME:在运行时有效(即运行时保留)
@Documented:是一个标记注解,用于描述其它类型的注解应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化。
- @Inherited:也是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的
注解定义格式
public @interface 注解名 { 定义体 }
注解参数可支持的数据类型:
8种基本数据类型 int、float、boolean、byte、double、char、long、short
String、Class、enum、Annotation
以上所有类型的数组
注意:自定义注解如果只有一个参数成员,最好把定义体参数名称设为"value",如@Target
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
ElementType[] value();
}

浙公网安备 33010602011771号