目录
一、反射的应用场景(简单了解)
二、反射的定义
三、关于反射的四个重要的类
四、反射的使用
1.Class获取一个class对象的方式
方式一:forName():
方式二:封装类.Class:
方式三:对象.getClass:
三种方式的使用场景
2.Constructor获取类的构造方法
3.Field获取类的字段(成员变量)
4.Method获取类的成员方法
一、反射的应用场景(简单了解)
在刚学习java时,或者还没有进行实际的项目开发时,反射运用的情况相对较少。
不过也是必须掌握的知识点,而且它也并不难。
学完之后,要运用时,回来复习复习,就差不多了。
反射的主要用途有:
1. 在日常的第三方应用开发过程中,经常会遇到某个类的某个成员变量、方法或是属性是私有的或是只对系统应用开放,这时候就可以利用Java的反射机制通过反射来获取所需的私有成员或是方法 。
2. 反射最重要的用途就是开发各种通用框架,比如在spring中,我们将所有的类Bean交给spring容器管理,无 论是XML配置Bean还是注解配置,当我们从容器中获取Bean来依赖注入时,容器会读取配置,而配置中给的 就是类的信息,spring根据这些信息,需要创建那些Bean,spring就动态的创建这些类。
二、反射的定义
Java的反射(reflection)机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法。
他就相当于一个魔镜,在运行状态下,给他照一个类,就能在镜子中看到他所有的内容,包括private修饰的字段、方法等。
这种动态获取信息以及动态调用对象方法的功能称为java语言的反射(reflection)机制。
看定义有点复杂,但是说了这么多,反射实际上就是:
可以获取一个封装类中的任何字段、构造方法、成员方法的一个机制。
如图(*/ω\*):
三、关于反射的四个重要的类
要想使用反射需要铺垫很多东西,才能懂,要使用反射,掌握这些知识是必要的,先不急,慢慢来。
简单看看下面的这四个类,这类四中的有很多关于反射的成员方法,等一下会介绍的奥,留有印象就行。
四、反射的使用
以,使用反射获取Student类的属性和方法为例。
一下是Student类的定义:
package Test1;
/**
* Created with IntelliJ IDEA
* Description:
* User:34398
* Date:2024-05-04
* Time:10:33
*/
public class Student {
public String Happy;
private String name;
private int age;
private Student(String happy) {//私有的有参数构造方法
this.Happy = happy;
}
public Student() {
}//无参构造方法
public Student(String name, int age) {//有参构造方法
this.name = name;
this.age = age;
}
private String setHappys(String happy){//私有含参数,成员方法
this.Happy=happy;
System.out.println("爱好:"+this.Happy);
return happy;
}
private void printfName() {//私有成员方法
System.out.println("名字:" + this.name);
}
public void printfAge() {//公有成员方法
System.out.println("年龄:" + this.age);
}
//一下是获取字段的方法
public String getHappy() {
return Happy;
}
public void setHappy(String happy) {
Happy = happy;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {//重写一下toString
return "Student{" +
"Happy='" + Happy + '\'' +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
1.Class获取一个class对象的方式
获取一个class对象的方式有三种。
方式一:forName():
代码中的clazz1就是我们获取到的class对象了。
值得注意的是:
forName()中的全类名,不需要自己写,因为有时候路径名很长,自己写容易错。
我们可以用idea进行拷贝。
具体做法:
打开idea,右键Student类,选择Copy Path/Reference,点击:
然后进入这个界面,在点击Copy Reference,粘贴到forName()的参数列表中即可:
方式二:封装类.Class:
此时,clazz2也是Student的class对象。
方式三:对象.getClass:
注意,class对象只会存在一个,不会创建多个!
上述代码中的clazz1/clazz2/clazz3实际上指向的都是一个class对象:
三种方式的使用场景
第一种方式用的最多,一般都用forName()
第二种方式,一般当做一个参数进行传递
第三种方式,在有封装类的对象时,才可以用
2.Constructor获取类的构造方法
Class类中的方法有很多,关于获取构造方法的方法就有4个。
不过好消息是,不用特意去记,因为他们的规律性极强!
助记技巧:
getConstructors()有个s,是复数形式,返回所有的公有构造方法(数组形式)
getDeclaredConstructors()多了个单词,declared,意思是声明,就是告诉编译器,他连private修饰的构造方法也要放进来!
getDeclaredConstructor()和getConstructor()不带有s,是单数,所以返回一个构造方法。
如果记住了这四个方法,下面获取字段和成员方法的方法基本上也就记住了。
下面是代码实操,获取类的构造方法:
1.获取所有公有构造方法:
执行结果:
2.获取所有构造方法,包括私有的:
执行结果:
此时,Student类中的所有构造方法,都在这里了。
3.获取单个构造方法:
注意:
获取单个构造方法时,
依照传入的参数个数,类型,顺序来判断具体获取到那个构造方法!
执行结果:
小细节:
如果是要获取有参构造方法,参数要与类中的一直,顺序也不能改变,并且要在类型后面点一个class,获取字节码文件。
例如:
String.class
int.class
获取这些构造方法有什么用呢?
用处可多了,可以得到他们的访问修饰权限符、构造方法的参数等等。
idea对方法的提示和填入参数的提示,底层就是用这个实现的。
4.获取访问修饰权限符
注意:
访问权限修饰符的类型使用int型表示的,具体参照表格(了解即可):
执行结果:
1正好就是public
5.获取构造方法的参数类型
执行结果:
6.用获取的构造方法创建封装类的对象
没错,既然我们可以获取封装类的构造方法,那么就可实例化一个封装类的对象.
在Constructor类中调用newInstance(构造方法的参数)方法即可:
助记技巧:
记住newInstance是一个创建对象的方法也很容易,在英文中,new就是创建的意思,
instance就是对象的意思。
执行结果:
竟然报错了!
原因是:
此constructor2是一个私有的构造方法,
虽然我们可以通过getDecclaredConstructor()获取这个构造方法,
但是却不能直接用。
解决办法:
constructor2.setAccssible(true)——临时取消权限校验
即可。
运行结果:
3.Field获取类的字段(成员变量)
执行结果:
其他的比如,所有字段/访问权限修饰符/数据类型等,
格式和获取构造方法的方式可以说一模一样,这里就不多演示了,都是写重复的方式,所以说反射其实并不难。
比如获取name的类型:
执行结果:
另外,Field还有特有的方法,可以获取并且修改成员变量记录的值(在new了一个封装类的对象后)
运行结果:
4.Method获取类的成员方法
其实写完前三个,这个就没有什么好写的了几乎就是十以内的加减法,换着数字考你。
值得注意的是,Method类拥有独属于自己的方法,例如:
获取方法抛出的异常,
获取方法的返回值,
调用获取的方法等等。
执行结果:
以上就是这篇文章的全部内容,自己动手试试,这块内容还是很看实践的。如果可以独立把代码敲出来,说明你就掌握的差不多了。
关于反射这块内容如果还有不清楚的,小编很推荐看一下B站的黑马程序员,讲的很细节,基本都是嚼碎了,喂给你的。
B站链接:java进阶教程进阶教程