反射是什么
在Java中,反射(Reflection)指的是在程序运行期间可以拿到一个对象的基本信息(属性、方法、注解等),所以反射是为了解决在运行期间,对某个未知的对象去获取其信息,调用其方法
如何使用反射
获取类信息
这里先明确一点,Class对象是在JVM执行过程中动态加载的(使用到了才会去加载),除了八大基本类型,其它类都是class,当然也包括接口(interface)、自定义类等
在这里我们新建一个People类
import lombok.Data;
@Data
public class People {
private String name;
public void say(){
System.out.println("i'm people");
}
}
Man类继承People类
@Data
public class Man extends People{
public String name;
private String sex;
private int age;
public Man(){}
public Man(String name, String sex,int age) {
this.name = name;
this.sex = sex;
this.age = age;
}
public void say(){
System.out.println("i'm man");
}
public void myName(String name){
System.out.println("i'm " + name);
}
}
我们先以这个Man类来进行讲解,当JVM加载Man
类时,首先读取Man.class
文件到内存中,然后为Man
创建一个Class
对象,有三种方法可以根据类得到一个Class
对象
第一种:通过实例对象来获取Class对象
//实例化对象
Man man = new Man();
Class classMan = man.getClass();//运行结果:class Basics.Reflection.Man
第二种:通过一个类对象获取
Class man1 = Man.class;//运行结果:class Basics.Reflection.Man
第三种:若是知道一个类的完整名称,则可以通过静态方法Class.forName()
Class man3 = Class.forName("Basics.Reflection.Man");//运行结果:class Basics.Reflection.Man
第四种:通过类加载器去获取
ClassLoader loader = ClassLoader.getSystemClassLoader();
Class classMan = loader.loadClass("Basics.Reflection.Man");
System.out.println(classMan);//运行结果:class Basics.Reflection.Man
我们还可以通过反射获取类的各种信息,比如类名、父类信息等
获取类名
//通过Class获取类名
String className = man1.getSimpleName();
System.out.println(className);
获取父类
//获取父类
String superName = man1.getSuperclass().getSimpleName();
System.out.println(superName);//打印结果:People
//获取父类的父类
String superName = man1.getSuperclass().getSuperclass().getSimpleName();
System.out.println(superName);//打印结果:Object
还可以通过反射得到包路径
//获取包路径
String packageName = man1.getPackage().getName();
System.out.println(packageName);//打印结果:Basics.Reflection
通过反射还可以判断该Class是否为接口、是否为枚举、是否为列表等操作,功能实属强大
获取实现接口,这里我们用Integer来举例
Class integerClass = Integer.class;
Class[] interfaces = integerClass.getInterfaces();
for(Class interface1 : interfaces){
System.out.println(interface1);
}
//打印结果:interface java.lang.Comparable
注意:getInterfaces()
只返回当前类直接实现的接口类型,并不包括其父类实现的接口类型,若是获得父类的实现接口,可以先使用getSuperclass()
得到父类的class对象,再去调用getInterfaces()来得到其实现接口
获取类属性
对于一个Object
实例,我们获取到了它的Class对象,就可以得到它的一切信息,当然也包括属性
该属性信息是封装在一个Field对象里,Field包括
最主要的还是三个
name
,通过 getName() 返回,表示字段名称
type
,通过 getType() 返回,表示字段类型,也是一个Class实例,例如,String.class
modifiers
,通过 getModifiers() 返回,表示字段的修饰符,它是一个int,不同的bit表示不同的含义
根据属性名获取某个属性的field(限public,包括父类)
Man man = new Man();
Class man1 = Man.class;
Field remark = man1.getField("name");//这个name属性为Man.class的属性
System.out.println(remark.getName());//name
System.out.println(remark.getType());//class java.lang.String
System.out.println(remark.getModifiers());//1
根据属性名名获取当前类的某个field(包括private,不包括父类)
Man man = new Man();
Class man1 = Man.class;
Field remark = man1.getDeclaredField("sex");
System.out.println(remark.getName());//sex
System.out.println(remark.getType());//class java.lang.String
System.out.println(remark.getModifiers());//2
获取所有属性的field[](限public,包括父类)
Man man = new Man();
Class man1 = Man.class;
Field[] attribute = man1.getFields();
获取当前类的所有field[](包括private,不包括父类)
Man man = new Man();
Class man1 = Man.class;
Field[] attributes = man1.getDeclaredFields();
获取类方法
该方法信息是封装在Method对象里,我们来看看Method对象的属性
比较重要的有四个属性:
name
,通过 getName() 返回,表示方法名称
returnType
,通过 getReturnType() 返回,表示方法返回类型
parameterTypes
,通过 getParameterTypes() 返回,表示方法的参数类型,是一个class[]
modifiers
,通过 getModifiers() 返回,它是一个int,不同的bit表示不同的含义
获取类中单个方法(限public,包括父类)
Man man = new Man();
Class man1 = Man.class;
Method method = man1.getMethod("say");
//调用子类方法,子类没有此方法就去调用父类方法
method.invoke(man);
获取当前类的某个方法(包括private,不包括父类)
Man man = new Man();
Class man1 = Man.class;
Method method1 = man1.getDeclaredMethod("myName", String.class);
System.out.println(method1);
//直接调用private方法,会出现java.lang.IllegalAccessException
//需要加上下面这一句设置权限
method1.setAccessible(true);
//然后调用即可
method1.invoke(man,"ALiangXLogic");//打印结果:i'm ALiangXLogic
获取所有的方法(限public,包括父类)
Man man = new Man();
Class man1 = Man.class;
Method[] methods = man1.getMethods();
获取当前类的所有方法(包括private,不包括父类)
Man man = new Man();
Class man1 = Man.class;
Method[] methods = man1.getDeclaredMethods();
获取构造器
正常创建实例
Man man = new Man();
通过反射来创造实例,调用Class类中的newInstance(),局限于只能调用public无参构造参数,构造方法若带有参数又或者构造方法为private,则不能通过反射创造实例
class.newInstance();
通过调用反射得到的构造器创建实例,可以反射任何构造器(可带参数),可以反射私有构造器
Constructor.newInstance()
我们主要看看通过反射得到的构造器创建实例,得到的构造器封装在一个Constructor对象里,我们来看看Constructor内部的属性
里面有几个重要的属性我给大家指出来
declaringClass
,通过 getDeclaringClass() 返回,获取生明该构造函数的类
parameterTypes
,通过 Class<?>[] getParameterTypes() 返回,获取构造函数参数的类型
modifiers
,通过 getModifiers() 返回,它是一个int,不同的bit表示不同的含义
annotations
,通过 byte[] getAnnotationBytes() 返回,表示构造器上使用的注解
Parameter[] getParameters() 获取构造函数的参数
获取Constructor(限public)
Constructor constructor = Man.class.getConstructor(String.class,String.class,int.class);
Man con = (Man) constructor.newInstance("ALiangXLogic","male",18);
System.out.println(con);
获取某个Constructor
Constructor constructor = Man.class.getDeclaredConstructor(String.class,String.class,int.class);
//得到构造器就可以执行下面的方法了
获取所有的Constructor(限public)
Constructor[] constructors = Man.class.getConstructors();
获取所有Constructor
Constructor[] constructors = Man.class.getDeclaredConstructors();
获得注解
得到类注解
Man man = new Man();
Class man1 = Man.class;
Annotation[] annotations1 = man1.getDeclaredAnnotations();
for(Annotation annotation : annotations1){
System.out.println(annotation);
}
得到属性注解
Man man = new Man();
Class man1 = Man.class;
Annotation[] annotations2 = man1.getDeclaredField("sex").getAnnotations();
for(Annotation annotation : annotations2){
System.out.println(annotation);
}
完成:2021/4/03 20:08 ALiangXLogic
转载请标注原作者,谢谢你们的支持,能给个小心心吗?