android java echo,Android基础-Java反射

一般情况下,我们使用某个类时必须知道它是什么类,是用来做什么的,并且能够获得此类的引用。于是我们直接对这个类进行实例化,之后使用这个类对象进行操作。

反射则是一开始并不知道我们要初始化的类的对象是什么,自然也无法使用 new 关键字来创建对象了。这时候,我们使用JDK提供的反射API进行反射调用。反射就是在运行状态中,对于任意一个类,都能够知道这个类的所有方法和属性。对于任意一个对象都能够调用它的任意方法和属性,并且能改变它的属性。是 Java 被视为动态语言的关键。

Java 的反射主要提供了以下功能:

在运行时构造任意一个类的对象

在运行时获取或者修改任意一个类所具有的成员变量和方法

在运行时调用任意一个对象的方法(属性)

Class

反射始于Class,Class是一个类,封装了当前对象所对应的类的信息。一个类中有属性,方法,构造器等。比如说有一个 Student 类,一个 Animal 类,这些都是不同的类。现在需要一个类,它的作用是用来描述这些类,比如一个普通的类应该有构造方法,成员属性,方法等。那么这个能描述类的类就是Class。

Class类是一个对象照镜子的结果,对象可以看到自己有哪些方法,属性,构造器,实现了哪些接口等等。对于每个类而言,JRE 都为其保留一个不变的 Class 类型的对象。一个 Class 对象包含了特定某个类的有关信息。对象只能由系统建立对象,一个类(而不是一个对象)在JVM中只会有一个 Class 实例,不管这个类被 new 了多少次。

获得 Class 对象

通过类名获取:类名.class

Class fruitClazz = Fruit.class;

通过对象获取:对象.getClass()

Fruit fruit = new Fruit();

Class extends Fruit> fruitClazz = fruit.getClass();

通过全类名获取:Class.forName(全类名),classLoader.loadClass(全类名)

// 通过静态方法

try {

Class> fruitClazz = Class.forName("com.example.Fruit");

} catch (ClassNotFoundException e) {

e.printStackTrace();

}

// 通过ClassLoader

try {

ClassLoader classLoader = getClassLoader();

Class> fruitClazz = classLoader.loadClass("com.example.Fruit");

} catch (ClassNotFoundException e) {

e.printStackTrace();

}

判断是否为某个类的实例

一般的,我们使用 instanceof 关键字来判断是否为某个类的实例。同时为我们也可以借助反射中 Class 对象的 isInstance() 方法来判断是否为某个类的实例,它是一个 native 方法。

public boolean isInstance(Object obj);

判断是否为某个类的类型:

public boolean isAssignableFrom(Class> cls);

创建实例

通过反射来生成对象实例主要有两种方式:

使用 Class 对象的 newInstance() 方法来创建 Class 对象对应类的实例。

Class fruitClazz = Fruit.class;

Fruit fruit = fruitClazz.newInstance();

先通过 Class 对象获取指定的 Constructor 对象,再调用 Constructor 对象的 newInstance()方法来创建实例。这种方法可以用指定的构造器来构造类的实例。

Class fruitClazz = Fruit.class;

// 获取构造参数为 String 类型的构造器

Constructor constructor = fruitClazz.getConstructor(String.class);

// 使用构造器创建实例

Fruit fruit = constructor.newInstance("name");

获取构造器信息

获得类的所有公共构造函数

public Constructor>[] getConstructors()

获得使用特殊的参数类型的public构造函数(包括父类)

public Constructor getConstructor(Class>... parameterTypes)

获得类的所有构造函数(与接入级别无关)

public Constructor>[] getDeclaredConstructors()

获得使用特定参数类型的构造函数(包括私有)

public Constructor getDeclaredConstructor(Class>... parameterTypes)

获取类的成员变量

获得命名的公共字段

public Field getField(String name)

获得类的所有公共字段

public Field[] getFields()

获得类声明的命名的字段

public native Field getDeclaredField(String name)

获得类声明的所有字段

public native Field[] getDeclaredFields();

调用方法

获得类的所有公共方法

public Method[] getMethods()

使用特定的参数类型,获得命名的公共方法

public Method getMethod(String name, Class>... parameterTypes)

获得类声明的所有方法

public Method[] getDeclaredMethods()

使用特定的参数类型,获得类声明的命名的方法

public Method getDeclaredMethod(String name, Class>... parameterTypes)

当我们从类中获取了一个方法后,我们就可以使用 invoke() 方法来调用这个方法:

public native Object invoke( Object obj, Object... args)

利用反射创建数组

数组在 Java 里是比较特殊的一种类型,它可以赋值给一个 Object Reference 其中的 Array 类为 java.lang.reflect.Array 类。我们通过 Array.newInstance()创建数组对象,它的原型是:

public static Object newInstance(Class> componentType,int length);

反射获取真实类型

当我们对一个泛型类进行反射时,需要得到泛型中的真实数据类型,来完成如json反序列化的操作。此时需要通过 Type 体系来完成。Type 接口包含了一个实现类(Class) 和四个实现接口,它们分别是:

TypeVariable 泛型类型变量,可以获得泛型上下限等信息

public class TypeStudy {

public K mKey;

public V mValue;

public static void main(String[] args) throws NoSuchFieldException {

// 通过反射获取字段

Field keyField = TypeStudy.class.getDeclaredField("mKey");

Field valueField = TypeStudy.class.getDeclaredField("mValue");

// 强转为TypeVariable

TypeVariable keyType = (TypeVariable) keyField.getGenericType();

TypeVariable valueType = (TypeVariable) valueField.getGenericType();

// 获取泛型变量的名称

String keyName = keyType.getName();

String valueName = valueType.getName();

System.out.println("KeyName:" + keyName);

System.out.println("ValueName:" + valueName +"\n");

// 获取泛型声明信息

GenericDeclaration keyDeclaration = keyType.getGenericDeclaration();

GenericDeclaration valueDeclaration = valueType.getGenericDeclaration();

System.out.println("KeyDeclaration:" + keyDeclaration);

System.out.println("ValueDeclaration:" + valueDeclaration +"\n");

// 获取边界

Type[] keyBounds = keyType.getBounds();

Type[] valueBounds = valueType.getBounds();

for (Type keyBound : keyBounds) {

System.out.println("KeyBound:" + keyBound);

}

for (Type valueBound : valueBounds) {

System.out.println("ValueBound:" + valueBound);

}

}

}

9f7019682b0d

输出结果

ParameterizedType 具体的泛型类型,可以获得元数据中泛型签名类型(泛型真实类型)

public class TypeStudy{

public Map map;

public static void main(String[] args) throws NoSuchFieldException {

Field mapField = TypeStudy.class.getDeclaredField("map");

Type type = mapField.getGenericType();

System.out.println("Type: " + type + "\n");

ParameterizedType parameterizedType = (ParameterizedType) mapField.getGenericType();

Type ownerType = parameterizedType.getOwnerType();

System.out.println("OwnerType: " + ownerType+ "\n");

Type rawType = parameterizedType.getRawType();

System.out.println("RawType: " + rawType+ "\n");

Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();

for (Type actualTypeArgument : actualTypeArguments) {

System.out.println("ActualTypeArgument: " + actualTypeArgument);

}

}

9f7019682b0d

输出结果

GenericArrayType 当需要描述的是泛型类的数组时,比如List[],Map[],此接口会作为 Type 的实现

public class TypeStudy{

List[] lists;

public static void main(String[] args) throws NoSuchFieldException {

Field field = TypeStudy.class.getDeclaredField("lists");

GenericArrayType genericType = (GenericArrayType) field.getGenericType();

Type genericComponentType = genericType.getGenericComponentType();

System.out.println(genericComponentType);

}

9f7019682b0d

输出结果

WildcardType 通配符泛型,获取上下限信息

public class TypeStudy{

List extends Number> numbers;

List super String> strs;

public static void main(String[] args) throws NoSuchFieldException {

Field numbersField = TypeStudy.class.getDeclaredField("numbers");

Field strsField = TypeStudy.class.getDeclaredField("strs");

// 先拿到泛型类型

ParameterizedType numbersType = (ParameterizedType) numbersField.getGenericType();

ParameterizedType strsType = (ParameterizedType) strsField.getGenericType();

// 再从泛型里拿到通配符类型

WildcardType numbersWildcardType = (WildcardType) numbersType.getActualTypeArguments()[0];

WildcardType strsWildcardType = (WildcardType) strsType.getActualTypeArguments()[0];

System.out.println(numbersWildcardType.getUpperBounds()[0]);

System.out.println(strsWildcardType.getLowerBounds()[0] + "\n");

System.out.println(numbersWildcardType);

System.out.println(strsWildcardType);

}

9f7019682b0d

输出结果

Gson反序列化

public class Response {

T data;

int code;

String msg;

public Response(T data, int code, String msg) {

this.data = data;

this.code = code;

this.msg = msg;

}

@Override

public String toString() {

return "Response{" +

"data=" + data +

", code=" + code +

", msg='" + msg + '\'' +

'}';

}

}

public class Data {

String result;

public Data(String result) {

this.result = result;

}

@Override

public String toString() {

return "Data{" +

"result='" + result + '\'' +

'}';

}

}

public class TypeStudy {

public static void main(String[] args) {

Gson gson = new Gson();

Data data = new Data("i am result");

Response response = new Response<>(data, 200, "ok");

// 序列化数据

String json = gson.toJson(response);

System.out.println("json: " + json);

// 反序列化数据

Response resp = gson.fromJson(json, new TypeToken>() {

}.getType());

System.out.println(resp.data.result);

}

对于经常进行网络请求的 coder 来说,上面的代码肯定不会陌生。可是 TypeToken 为什么要被定义称抽象类呢?这是因为只有抽象类或者接口在使用时需要创建对应的实现类,此时确定泛型类型,编译器才能将泛型 signature 信息记录到 Class 元数据中。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值