一 反射简述
JAVA是一个静态语言,但是通过使用反射,我们可以在程序运行的时候获取一个类的所有的方法,属性,并且实现调用。
二 反射的使用
1.我们首先创建一个学生类
package markorg.top.demo;
public class Student {
private int age;
public String name;
private String school;
public Student() {
System.out.println("默认的构造方法");
}
// 受保护的构造方法
protected Student(int age) {
System.out.println("受保护的构造方法" + age);
}
// 私有构造方法
private Student(int age, String name) {
System.out.println("受保护的构造方法" + "age: " + age + ",name: " + name);
}
// 完整的构造方法
public Student(int age, String name, String school) {
super();
this.age = age;
this.name = name;
this.school = school;
}
public void print(String str) {
System.out.println("hello student:" + str);
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSchool() {
return school;
}
public void setSchool(String school) {
this.school = school;
}
}
2.接下来,首先通过反射获取Student 类的Class,然后调用reflect api获取到类的构造方法,实现类的初始化
package markorg.top.demo;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class ReflectTest {
public static void main(String[] args) throws InstantiationException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
Student stu = new Student();
// 第一种方式获取student对象
Class stuClass = stu.getClass();// 这种方法是在已经创建的情况下获取,实际中不需要
System.out.println(stuClass.getName());
// 第二种方式获取student对象
Class stuClass2 = Student.class;
// 第三种方式获取student对象,常用的方法,需要注意的是Name需要包的完整路径名和类的名称
try {
Class stuClass3 = Class.forName("markorg.top.demo.Student");
System.out.println(stuClass == stuClass2);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
// 获取公有的构造方法
Constructor[] conArry = stuClass2.getConstructors();
System.out.println("公有构造");
for (Constructor con : conArry) {
System.out.println(con);
}
// 获取所有的构造方法
Constructor[] conAll = stuClass2.getDeclaredConstructors();
System.out.println("所有构造");
for (Constructor cons : conAll) {
System.out.println(cons);
}
Constructor ctr = stuClass2.getConstructor(null);
// 调用构造
Object obj = ctr.newInstance();
// 带参数的构造方法
Constructor ctr2 = stuClass2.getDeclaredConstructor(int.class);
// 调用构造
Object ob = ctr2.newInstance(20);
Constructor pri = stuClass2.getDeclaredConstructor(int.class, String.class);// 注意,这里只能是类型.class,不能直接他的包装类型。
// 调用构造
// 设置可以访问
pri.setAccessible(true);
Object ob3 = pri.newInstance(18, "tom");
}
}
3.获取类的属性,方法,并且调用方法
package markorg.top.demo;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class GetFieldTest {
public static void main(String[] args) {
try {
// 通过反射获取Class
Class stuClass = Class.forName("markorg.top.demo.Student");
// 获取所有公有字段
Field[] field = stuClass.getFields();
for (Field fd : field) {
System.out.println("公有字段:" + fd);
}
// 获取所有的字段
Field[] fields = stuClass.getDeclaredFields();
for (Field fds : fields) {
System.out.println("全部字段:" + fds);
}
// 获取私有字段并调用
Field fie = stuClass.getDeclaredField("school");
fie.setAccessible(true);
Object obb = stuClass.getConstructor().newInstance();
fie.set(obb, "苏州大学");
Student stt = (Student) obb;
System.out.println("学校名字:" + stt.getSchool());
// 获取所有的方法
Method[] method = stuClass.getMethods();
for (Method met : method) {
System.out.println("全部方法:" + met);
}
// 获取公有的某个方法,通过方法名来获取
Method pubmethod = stuClass.getMethod("print", String.class);
System.out.println("私有方法:" + pubmethod);
// pubmethod.setAccessible(true);如果是私有方法需要这个
pubmethod.invoke(obb, "jack");//通过invoke来进行调用
} catch (Exception e) {
e.printStackTrace();
System.out.println("反射异常");
}
}
}
三 反射总结
乍看起来,我们好像没必要使用反射,因为正常情况下,通过实例化类,就可以直接使用他的方法,而且,反射会降低程序的性能,但是,有时候,我们是不知道这个类的属性的,比如一些ORM框架中,需要数据库中的表来和类进行映射,但是我们一开始是不知道将要映射的表是什么样的,是不能提前创建对应的类,这时候我们可以可以通过查询数据库,动态的生成表对应的class并且通过java自编译器动态加载到内存,达到动态生成对象进行映射的作用。相关操作,我将在下一个章节进行介绍。