Java基础之反射
发布日期:2021-05-06 23:31:42 浏览次数:5 分类:技术文章

本文共 5231 字,大约阅读时间需要 17 分钟。

一、概述

在运行状态中,对于任何一个类都能知道这个类中的所有属性、方法;对于任意一个对象,都能调用它的属性、方法;这种动态获取信息以及动态调用对象方法的功能,称之为反射。

二、通过反射查看类信息

1.获取Class对象

类被加载后,会生成一个对应的Class对象。通过Class对象,就能访问到JVM中的这个类。获取Class对象,概括分为3中方式:

//通过静态方法forName实现        class = Class.forName(com.xxx.xxx.Person);        //通过class属性        class = Person.class;        //通过对象的getClass方法        Person person = new Person();        Class
class = person.getClass();

2.获取Class对象的属性、方法、构造函数

a.获取class对象的成员变量

Field[] allFields = class1.getDeclaredFields();//获取class对象所有属性        Field ageField = class1.getDeclaredField("age");//获取指定属性                Field[] PublicFields = class1.getFields();//获取public属性        Field desField = class1.getField("age");//获取指定的public属性

b.获取class对象方法

Method[] methods = class1.getDeclaredMethods();//获取所有方法        Method declaredMethod = class1.getDeclaredMethod("info", String.class);//返回带指定形参列表的方法        Method[] allMethods = class1.getMethods();//返回所有public方法        Method method = class1.getMethod("info", String.class);//返回带指定形参列表的pulic方法

c.获取class对象构造函数

Constructor
[] allConstructors = class1.getDeclaredConstructors();//返回所有构造方法 Constructor
constructor = class1.getDeclaredConstructor(String.class);//获取指定声明的构造方法 Constructor
[] publicConstructors = class1.getConstructors();//返回所有public构造方法 Constructor
publiconstructor = class1.getConstructor(String.class);//返回指定的public构造方法

d.其他方法

Annotation[] annotations = (Annotation[]) class1.getAnnotations();//获取class对象所有注解        Annotation annotation = (Annotation) class1.getAnnotation(Deprecated.class);//获取指定注解        Type genericSuperclass = class1.getGenericSuperclass();//获取class对象的直接超类type        Type[] genericInterfaces = class1.getGenericInterfaces();//获取class对象所有接口的type结婚

3.获取class对象的信息

boolean primitive = class1.isPrimitive();//是否是基础类型        boolean array = class1.isArray();//是否是集合类        boolean annotation = class1.isAnnotation();//是否是注解类        boolean anInterface = class1.isInterface();//是否是接口类        boolean anEnum = class1.isEnum();//是否是枚举类        boolean anonymousClass = class1.isAnonymousClass();//是否是匿名内部类        boolean annotationPresent = class1.isAnnotationPresent(Deprecated.class);//是否被某个注解类修饰        String name = class1.getName();//获取class的name,包括包路径        Package aPackage = class1.getPackage();//获取包信息        String simpleName = class1.getSimpleName();//获取class类名        int modifiers = class1.getModifiers();//获取访问权限        Class
[] declaredClasses = class1.getDeclaredClasses();//内部类 Class
declaringClass = class1.getDeclaringClass();//外部类

三、通过反射生成并操作对象

1.生成类的实例对象

//调用newInstance()生成        Object obj = class1.newInstance();        //通过构造方法在调用newInstance()生成        Constructor
constructor = class1.getDeclaredConstructor(String.class); Object obj = constructor.newInstance("hello");

2.调用类的方法

Object obj = class1.newInstance();//生成新的对象        Method method = class1.getDeclaredMethod("setAge", int.class);//获取与该方法对应的Method对象        method.invoke(obj,11);//调用指定函数并传参

通过Method的invoke方法来调用对应方法时,程序必须要有调用该方法的权限。如果需要调用某个对象的private方法,可先调用setAcccessible(boolean flag);true代表Method在使用时取消访问权限检查,false表示启用访问权限检查。

3.访问成员变量值

Object obj = class1.newInstance();//生成新的对象        Field field = class1.getField("age");//获取age变量        field.setInt(obj,10);//将age设置10        field.getInt(obj);//取出age

四、反射结合泛型

1.泛型和Class类

在反射中使用泛型,可以避免反射生成的对象需要强制类型转换。

//工厂类public class ObjectFactory {       public static 
T getInstance(Class
cls){ try { return cls.newInstance(); } catch (InstantiationException |IllegalAccessException e) { e.printStackTrace(); return null; } }}

此时传入String.class,T便代表String,返回的对象是String类型,避免了强制类型转换

String instance = ObjectFactory.getInstance(String.class);

2.使用反射获取泛型信息

通过类对应的Class对象,可以获取到所有的Field,并获得Field类型:

//获取field对象f的类型Class
a = f.getType();

如果Field类型是有泛型限制的类型,如Map<String,Integer>,就不灵了。只能先获取Field类型,再把type对象强制转换为ParameterizedType(代表被参数化的类型,即增加了泛型限制的类型)对象,ParameterizedType提供了getRawType()(返回没有泛型信息的原始类型)和getActualTypeArguments()(返回泛型参数的类型)

public class GenericTest {       private Map
score; public static void main(String []args) throws Exception { Class
clazz = GenericTest.class; Field f = clazz.getDeclaredField("score"); //直接使用getType取出Field类型,只对普通类型的Field有效 Class
a = f.getType(); System.out.println("score类型为"+a); //获取Field实例f的泛型类型 Type gType = f.getGenericType(); //如果gType类型时ParameterizedType if (gType instanceof ParameterizedType){ ParameterizedType pType = (ParameterizedType) gType; //获取原始类型 Type rType = pType.getRawType(); System.out.println("原始类型时"+rType); //获取泛型类型的泛型参数 Type[] tArgs = pType.getActualTypeArguments(); for (int i = 0; i < tArgs.length; i++) { System.out.println(i+"个泛型类型是:"+tArgs[i]); } }else { System.out.println("获取泛型类型出错"); } }}

以上输出结果:

score类型为interface java.util.Map
原始类型时interface java.util.Map
0个泛型类型是:class java.lang.String
1个泛型类型是:class java.lang.Integer

使用场景

1.逆向编码,如反编译

2.与注解相结合的框架,如Retrofit
3.单纯的反射机制应用框架,如EventBus
4.动态生成类框架,如Gson

上一篇:Java注解学习笔记
下一篇:Java基础之泛型

发表评论

最新留言

表示我来过!
[***.240.166.169]2025年03月14日 17时12分01秒