什么是反射
Java的反射指的是在程序运行状态中,对于任何一个类,我们都能够知道这个类有哪些方法和属性。并且对于每一个对象,我们都能够对它的属性和方法进行调用。 我们把这种动态调用对象属性和对象方法的功能称为反射机制。
反射的三种方式
所谓的反射其实是根据类的字节码文件来获取属性和方法的,也就是.class文件,所以我们就是通过Class对象来获取这些属性和方法。
而反射一共有三种方式来来获取属性和方法。
1. 第一种方式:
Class<?> getClass() 返回此Object的运行时类
这个方法是来自Object的方法,Class继承了Object,所以我们可以直接使用这个方法。
//创建一个对象
Student student =new Student();
//获取对象的Class属性
Class c = student.getClass();
//获取类名称
System.out.println(c.getName());
2.第二种方式
第二种方式获取和第一种方式类似,可以直接通过类名直接获取class文件
Class c1 = Student.class;
//获取类名称
System.out.println(c1.getName());
3.第三种方式
通过类的全路径名获取Class对象,但是这样获取,需要抛出一个ClassNotFoundException异常,如果在指定路径下找不到该类,就会抛出异常。
public static void main(String[] args)throws ClassNotFoundException {
Class c2 = Class.forName("demo.demo.Student");
//获取类名称
System.out.println(c2.getName());
}
一般会选择第三种方式获取类的class文件。
通过反射获取类的构造方法、方法以及属性
1.获取构造方法
可以通过Class的四个方法来获得类的构造方法
getConstructors() (获得所有公用的构造方法)
getConstructor() (获得公有的 & 无参的构造方法)
getDeclaredConstructors () (获得所有的构造方法)
getDeclaredConstructor() (获得私有 & 有参的构造方法)
需要抛出一个NoSuchMethodException异常,当没找到相应构造方法是抛出。
具体使用方法如下所示:
public static void main(String[] args)throws ClassNotFoundException, NoSuchMethodException {
//加载Class对象
Class c = Class.forName("demo.demo.Student");
System.out.println("获得所有公用的构造方法!");
//获得所有的公用构造方法
Constructor[] constructors = c.getConstructors();
for (Constructor constructor: constructors
) {
System.out.println(constructor);
}
System.out.println("获得所有的构造方法!");
//获得所有的构造方法
Constructor[] constructors1 = c.getDeclaredConstructors();
for (Constructor constructor: constructors1
){
System.out.println(constructor);
}
System.out.println("获得所有的公有 & 无参的构造方法");
//获得所有的公有 & 无参的构造方法
//传入null参数,获取无参的构造方法
Constructor constructor2 = c.getConstructor(null);
System.out.println(constructor2);
System.out.println("获取所有的公有 & 有参的构造方法");
//获取所有的公有 & 有参的构造方法
//按照构造方法参数顺序,依次传入构造方法参数的类型,获取公有的有参构造方法
Constructor constructor3 = c.getConstructor(new Class[]{int.class,String.class,String.class});
System.out.println(constructor3);
System.out.println("获取所有的私有 & 有参的构造方法");
//获取所有的私有 & 有参的构造方法
//方式与获取公有有参方法的方式类似,只是使用的类方法不一样
Constructor constructor4 = c.getDeclaredConstructor(new Class[]{String.class});
System.out.println(constructor4);
}
运行结果如下所示:
2.获取类属性
获取类属性可以通过两个方法获取:
getField (获取公用字段)
getDeclaredField (获取私有字段,公用字段)
并且有一点需要注意的是,在获取私有字段赋值使用的过程中,需要进行暴力反射。
也就是需要暂时的关闭Java的权限检查机制,不再检查私有属性的访问权限,可以让我们给私有属性赋值。
使用 Filed.setAccessible(true) 方法来设置。
https://www.cnblogs.com/fanguangdexiaoyuer/p/6548171.html(关于setAccessible方法更详细内容)
使用这两个方法需要抛出一个 NoSuchFieldException 异常,在类中找不到相应的字段时抛出。
具体使用方法如下:
public static void main(String[] args)throws ClassNotFoundException, NoSuchMethodException, NoSuchFieldException, IllegalAccessException, InvocationTargetException, InstantiationException {
//加载Class对象
Class c = Class.forName("demo.demo.Student");
System.out.println("获取所有的公有字段!");
Field[] fields = c.getFields();
for (Field field : fields) {
System.out.println(field);
}
System.out.println("获取所有的字段(公有,私有)!");
Field[] fields1 = c.getDeclaredFields();
for (Field field : fields1) {
System.out.println(field);
}
System.out.println("获取公有字段并赋值使用!");
//获取指定公有字段
Field field = c.getField("name");
//获取一个公有构造方法,并且使用newInstance方法实例化。
Object obj = c.getConstructor().newInstance();
//为属性设置值
field.set(obj,"kk");
Student student = (Student)obj;
System.out.println(student.getName());
System.out.println("获取私有字段并赋值使用!");
//获取指定私有字段
Field field1 = c.getDeclaredField("address");
//获取一个公有构造方法,并且使用newInstance方法实例化。
Object obj1 = c.getConstructor().newInstance();
//暴力反射,关闭Java 语言访问控制检查的能力,禁用安全检查,也就是暂时关闭私有权限的访问权限。
field1.setAccessible(true);
//为属性设置值
field1.set(obj1,"kkAddress");
Student student1 = (Student)obj1;
System.out.println(student1.getAddress());
}
运行结果如下所示:
3.获取指定方法并使用
获取类的方法可以通过两个方法来获取
getMethod(获取公有方法)
getDeclaredMethod(获取公有方法、私有方法、受保护方法)
先定义几个不同类型的方法:
public void method() {
System.out.println("公用无参方法");
}
public void method(String name) {
System.out.println("公用有参方法");
}
protected void method2(String name) {
System.out.println("受保护有参方法");
}
private void method1() {
System.out.println("私有无参方法");
}
public void OutStudent(int age,String name,String address){
System.out.println("公用有参方法");
System.out.println("学生信息:" + age + name + address);
}
然后具体使用方法如下:
//加载Class对象
Class c = Class.forName("demo.demo.Student");
System.err.println("获取所有的public修饰的方法");
Method[] methods = c.getMethods();
for (Method method : methods) {
System.out.println(method);
}
Thread.sleep(1000);
System.err.println("获取所有的方法");
Method[] methods1 = c.getDeclaredMethods();
for (Method method:methods1
) {
System.out.println(method);
}
Thread.sleep(1000);
System.err.println("获取指定方法(不带参)并使用");
Method method = c.getDeclaredMethod("method");
System.out.println(method);
Thread.sleep(1000);
System.err.println("获取指定方法(带参)并使用");
Method method1 = c.getMethod("method",String.class);
System.out.println(method1);
Thread.sleep(1000);
System.err.println("获取指定方法(多个参数)并使用");
Method method2 = c.getDeclaredMethod("OutStudent",int.class, String.class, String.class);
//获取构造方法,实例化一个对象
Object object = c.getConstructor().newInstance();
//给指定方法传值
//使用invoke调用指定方法
method2.invoke(object,18,"kk","address");
运行结果如下所示:
网友评论