该学习笔记是根据《黑马程序员Java零基础视频教程》和《黑马程序员JavaWeb全套基础教程,java web从入门到项目实战(IDEA版javaweb)》总结出来的。
一. 反射机制简单介绍
- 反射就是加载类,并允许以编程的方式解剖类中的各种成分(成员变量、成员方法、构造方法)。换句话说:反射允许对成员变量、成员方法和构造方法的信息进行编程访问。
- 获取字节码文件对象(获取Class对象)的三种方式
public class Test {
public static void main(String[] args) throws ClassNotFoundException {
// 第一种方式 Class.forName(全类名)最为常用。多用于配置文件,将全类名定义在配置文件中,读取文件,加载类。
Class clazz1 = Class.forName("com.itheima.demo7.Student");
System.out.println(clazz1);
// 第二种方式 类名.class 一般是当做参数进行传递
Class clazz2 = Student.class;
System.out.println(clazz2);
System.out.println(clazz1==clazz2); //这两种方式获取的对象是一模一样的
// 第三种方式 对象.getClass() 当我们已经有了这个类的对象时,才可以使用
Student stu = new Student();
Class clazz3 = stu.getClass();
System.out.println(clazz3);
System.out.println(clazz1==clazz3);
// 以上三种方式获取的CLass对象是一模一样的。
}
}
class Student{
String name;
int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
}
/*
输出:
class com.itheima.demo7.Student
class com.itheima.demo7.Student
true
class com.itheima.demo7.Student
true
*/
二. Java代码在计算机中经历的阶段
- 第一步:首先编写java代码Student.java,该代码中存在成员变量、成员方法、构造方法;
- 第二步:利用工具
javac
将Student.java代码编译成计算机能理解的机器语言,此过程生成一个字节码文件"Student.class"。无论是java代码还是class文件,它都存放于硬盘上,并没有进内存。 - 第三步:利用类加载器ClassLoader将硬盘上的字节码文件"Student.class"加载到JVM内存中,并生成一个CLass对象来描述字节码文件"Student.class"。该Class对象中有成员变量、构造方法、成员方法,我们将Class对象的成员变量封装为Filed对象;将构造方法封装为Constructor对象;将成员方法封装为Method对象。由于成员变量、成员方法、构造方法的数量通常不唯一,因此我们得到的是
成员变量对象的数组(Filed对象的数组)、构造方法对象的数组(Constructor对象的数组)、成员方法对象的数组(Method对象的数组)
。 - 第四步:创建Student对象,运行代码。
- 注意点:同一个字节码文件(
*.class
)在一次程序运行过程中,只会被加载一次,无论通过那种方式获取的Class对象都是同一个。
三. 利用反射获取构造方法
public class Test {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
// 获取class字节码文件的对象
Class clazz1 = Class.forName("com.itheima.demo7.Student");
// 获取public修饰的构造方法
Constructor[] cons = clazz1.getConstructors();
System.out.println(Arrays.toString(cons));
// 获取所有的构造方法
Constructor[] dcs = clazz1.getDeclaredConstructors();
System.out.println(Arrays.toString(dcs));
// 获取单个public修饰的构造方法
Constructor dc1 = clazz1.getDeclaredConstructor(); //获取空参的构造方法
System.out.println(dc1);
Constructor dc2 = clazz1.getDeclaredConstructor(String.class,int.class);
System.out.println(dc2);
}
}
class Student{
private String name;
private int age;
public Student() {
}
public Student(String name) {
this.name = name;
}
protected Student(int age){
this.age = age;
}
private Student(String name, int age){
this.name = name;
this.age = age;
}
}
/*输出:
[public com.itheima.demo7.Student(java.lang.String), public com.itheima.demo7.Student()]
[private com.itheima.demo7.Student(java.lang.String,int), protected com.itheima.demo7.Student(int), public com.itheima.demo7.Student(java.lang.String), public com.itheima.demo7.Student()]
public com.itheima.demo7.Student()
private com.itheima.demo7.Student(java.lang.String,int)
*/
四. 利用反射获取成员变量
public class Test {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, NoSuchFieldException {
// 获取class字节码文件的对象
Class clazz1 = Class.forName("com.itheima.demo7.Student");
// 获取public修饰的成员变量
Field[] fs = clazz1.getFields();
System.out.println(Arrays.toString(fs));
// 获取所有的成员变量
Field[] dfs = clazz1.getDeclaredFields();
System.out.println(Arrays.toString(dfs));
// 获取单个public修饰的成员变量
Field gender = clazz1.getField("gender");
System.out.println(gender);
// 获取单个成员变量
Field name = clazz1.getDeclaredField("name");
System.out.println(name);
}
}
class Student{
private String name;
private int age;
public String gender;
public Student() {
}
public Student(String name, int age, String gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
}
/*输出:
[public java.lang.String com.itheima.demo7.Student.gender]
[private java.lang.String com.itheima.demo7.Student.name, private int com.itheima.demo7.Student.age, public java.lang.String com.itheima.demo7.Student.gender]
public java.lang.String com.itheima.demo7.Student.gender
private java.lang.String com.itheima.demo7.Student.name
*/
五. 利用反射获取成员方法
和上面的代码类似,就不写代码了,太累了。