这里我们对反射的基础知识不会介绍,主要内容是相对深入一些的知识点和需要注意的点,以及给出一些使用上的示例,如果对基础知识需要了解的可以参考这边文章,Java高级特性——反射,如果侵权请联系我删除。
定义
反射就是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;并且能改变它的属性。
Java反射机制主要提供了以下功能:
- 在运行时构造任意一个类的对象
- 在运行时获取或者修改任意一个类所具有的成员变量和方法
- 在运行时调用任意一个对象的方法(属性)
Class获取方式
反射始于Class,Class是一个类,封装了当前对象所对应的类的信息。没有Class我们是实现不了反射的。
- 不执行静态块和动态构造块
Class<?> clz = String.class;
- 执行静态块、不执行动态构造块
try {
Class<?> clz1 = Class.forName("com.hot.lib.annotation.CoolBoy");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
- 静态块和动态构造块均会执行
CoolBoy coolBoy = new CoolBoy();
coolBoy.getClass();
判断是否为某个类的实例
一般地,我们用 instanceof 关键字来判断是否为某个类的实例。同时我们也可以借助反射中 Class 对象的isInstance() 方法来判断是否为某个类的实例,它是一个 native 方法:
public native boolean isInstance(Object obj);
判断是否为某个类的类型
public boolean isAssignableFrom(Class<?> cls)
获取属性、方法、构造函数、注解的共通点
带有Declared修饰的可以获取当前类中的方法、属性,不区分private和public;
没有Declared修饰的只能获取public及从父类继承public的方法、属性。
方法和属性
class CoolBoy {
private String str;
public static String staticStr;
}
public class ReflectDemo {
public static void main(String[] args) {
CoolBoy coolBoy = new CoolBoy();
Class<?> clz = coolBoy.getClass();
try {
Field str = clz.getField("str");
//因为str是private 所以要设置访问权限
str.setAccessible(true);
//set的第一个参数是需要传入我们的对象,即str属性所在的对象
str.set(coolBoy, "private");
Field string = clz.getField("staticStr");
//因为staticStr是静态的 所以我们不需要传入对应对象 可以传入null
string.set(null, "static");
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
数组
数组在Java里是比较特殊的一种类型,它可以赋值给一个Object Reference 其中的Array类为
java.lang.reflect.Array类。我们通过Array.newInstance()创建数组对象,例如:
//public static Object newInstance(Class<?> componentType, int length);
String[] strs = (String[]) Array.newInstance(String[].class.getComponentType(),10);
泛型
当我们对一个泛型类进行反射时,需要的到泛型中的真实数据类型,来完成如json反序列化的操作。此时需要通过 Type 体系来完成。 Type 接口包含了一个实现类(Class)和四个实现接口,他们分别是:
TypeVariable 泛型类型变量。可以泛型上下限等信息。
public class TestType<K extends Comparable & Serializable, V> {
K key;
V value;
public static void main(String[] args) throws Exception {
// 获取字段的类型
Field fk = TestType.class.getDeclaredField("key");
Field fv = TestType.class.getDeclaredField("value");
// getGenericType() 表示由此Field对象表示的字段的声明类型
TypeVariable keyType = (TypeVariable) fk.getGenericType();
TypeVariable valueType = (TypeVariable) fv.getGenericType();
// getName 方法
System.out.println(keyType.getName()); // K
System.out.println(valueType.getName()); // V
// getGenericDeclaration 获取声明该类型变量实体
System.out.println(keyType.getGenericDeclaration()); // class com.test.TestType
System.out.println(valueType.getGenericDeclaration()); // class com.test.TestType
// getBounds 方法
System.out.println("K 的上界:"); // 有两个
for (Type type : keyType.getBounds()) { // interface java.lang.Comparable
System.out.println(type); // interface java.io.Serializable
}
System.out.println("V 的上界:"); // 没明确声明上界的, 默认上界是 Object
for (Type type : valueType.getBounds()) { // class java.lang.Object
System.out.println(type);
}
}
}
ParameterizedType 具体的泛型类型,可以获得元数据中泛型签名类型(泛型真实类型)
public class TestType {
Map<String, String> map;
public static void main(String[] args) throws Exception {
Field f = TestType.class.getDeclaredField("map");
System.out.println(f.getGenericType()); // java.util.Map<java.lang.String, java.lang.String>
System.out.println(f.getGenericType() instanceof ParameterizedType); // true
ParameterizedType pType = (ParameterizedType) f.getGenericType();
System.out.println(pType.getRawType()); // interface java.util.Map
for (Type type : pType.getActualTypeArguments()) {
System.out.println(type); // 打印两遍: class java.lang.String
}
System.out.println(pType.getOwnerType()); // null
}
}
GenericArrayType 当需要描述的类型是泛型类的数组时,组成数组的元素中有范型则实现了该接口;比如List[],Map[],此接口会作为Type的实现。
public class TestType<T> {
List<String>[] lists;
public static void main(String[] args) throws Exception {
Field f = TestType.class.getDeclaredField("lists");
GenericArrayType genericType = (GenericArrayType) f.getGenericType();
System.out.println(genericType.getGenericComponentType()); //java.util.List<java.lang.String>
}
}
WildcardType 通配符泛型,获得上下限信息。
public class TestType {
private List<? extends Number> a; // // a没有下界, 取下界会抛出ArrayIndexOutOfBoundsException
private List<? super String> b;
public static void main(String[] args) throws Exception {
Field fieldA = TestType.class.getDeclaredField("a");
Field fieldB = TestType.class.getDeclaredField("b");
// 先拿到范型类型
Assert.that(fieldA.getGenericType() instanceof ParameterizedType, "");
Assert.that(fieldB.getGenericType() instanceof ParameterizedType, "");
ParameterizedType pTypeA = (ParameterizedType) fieldA.getGenericType();
ParameterizedType pTypeB = (ParameterizedType) fieldB.getGenericType();
// 再从范型里拿到通配符类型
Assert.that(pTypeA.getActualTypeArguments()[0] instanceof WildcardType, "");
Assert.that(pTypeB.getActualTypeArguments()[0] instanceof WildcardType, "");
WildcardType wTypeA = (WildcardType) pTypeA.getActualTypeArguments()[0];
WildcardType wTypeB = (WildcardType) pTypeB.getActualTypeArguments()[0];
// 方法测试
System.out.println(wTypeA.getUpperBounds()[0]); // class java.lang.Number
System.out.println(wTypeB.getLowerBounds()[0]); // class java.lang.String
// 看看通配符类型到底是什么, 打印结果为: ? extends java.lang.Number
System.out.println(wTypeA);
}
}
泛型实际使用中的问题
我们实际开发中都会存在对后台数据统一解析的处理,我们一般都会统一一个Response,例如:
static class Response<T> {
T data;
int code;
String message;
@Override
public String toString() {
return "Response{" +
"data=" + data +
", code=" + code +
", message='" + message + '\'' +
'}';
}
public Response(T data, int code, String message) {
this.data = data;
this.code = code;
this.message = message;
}
}
static class Data {
String result;
public Data(String result) {
this.result = result;
}
@Override
public String toString() {
return "Data{" +
"result=" + result +
'}';
}
}
下面我进行解析处理
public static void main(String[] args) {
Response<Data> dataResponse = new Response(new Data("数据"), 1, "成功");
Gson gson = new Gson();
String json = gson.toJson(dataResponse);
System.out.println(json);
//反序列化......
/**
* 有花括号: 代表是匿名内部类,创建一个匿名内部类的实例对象
* 没花括号:创建实例对象
*/
Type type = new TypeRefrence<Response<Data>>(){}.getType();
System.out.println(type);
Response<Data> response = gson.fromJson(json, type);
System.out.println(response.data.getClass());
}
这里我们注意这里
Type type = new TypeRefrence<Response<Data>>(){}.getType();
TypeRefrence是Gson提供的类,用来获取泛型类型的,而这里我们可以看到上面这实际上是一个匿名内部类,如果我们将其改为下面这种形式
Type type = new TypeRefrence<Response<Data>>().getType();
这样代码还能编译通过吗?答案是否定的,因为没有了泛型的类型信息。
因为只有定义为抽象类或者接口,这样在使用时,需要创建对应的实现类,此时确定泛型类型,编译才能够将泛型signature信息记录到Class元数据中。 这就是因为泛型擦除后,我们还可以通过反射取到泛型类型的原因。所以这里我们要注意。
其实我们也可以自己实现一个TypeRefrence,代码如下
class TypeRefrence<T> {
private Type type;
//注意这里我们的访问权限是protected 这样不在一个包下的时候 就必须要创建内部类 不能直接实例化
protected TypeRefrence() {
Type genericSuperclass = getClass().getGenericSuperclass();
ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
//因为我们这里只有一个泛型 所以我们直接取第一个
type = actualTypeArguments[0];
}
public Type getType() {
return type;
}
}
自动获取View id 示例
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ViewAnnotation {
@IdRes int value();
}
public static void getId(Activity activity) {
Field[] declaredFields = activity.getClass().getDeclaredFields();
for (Field filed : declaredFields) {
//该字段是否被ViewAnnotation注解声明
if (filed.isAnnotationPresent(ViewAnnotation.class)) {
ViewAnnotation viewAnnotation = filed.getAnnotation(ViewAnnotation.class);
//获取注解中的id
int id = viewAnnotation.value();
View view = activity.findViewById(id);
//设置访问权限
filed.setAccessible(true);
try {
//反射设置属性的值
filed.set(activity, view);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
自动获取Intent传递的参数
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Autowired {
String value() default "";
}
public static void injectAutowired(Activity activity) {
Class<? extends Activity> cls = activity.getClass();
//获得数据
Intent intent = activity.getIntent();
Bundle extras = intent.getExtras();
if (extras == null) {
return;
}
//获得此类所有的成员
Field[] declaredFields = cls.getDeclaredFields();
for (Field field : declaredFields) {
if (field.isAnnotationPresent(Autowired.class)) {
Autowired autowired = field.getAnnotation(Autowired.class);
//获得key
String key = TextUtils.isEmpty(autowired.value()) ? field.getName() : autowired.value();
if (extras.containsKey(key)) {
Object obj = extras.get(key);
// todo Parcelable数组类型不能直接设置,其他的都可以.
//获得数组单个元素类型
Class<?> componentType = field.getType().getComponentType();
//当前属性是数组并且是 Parcelable(子类)数组
if (field.getType().isArray() &&
Parcelable.class.isAssignableFrom(componentType)) {
Object[] objs = (Object[]) obj;
//创建对应类型的数组并由objs拷贝
Object[] objects = Arrays.copyOf(objs, objs.length, (Class<? extends Object[]>) field.getType());
obj = objects;
}
field.setAccessible(true);
try {
field.set(activity, obj);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
}