一、反射的概念
Java的反射(reflection)机制是指在程序的运行状态中,可以构造任意一个类的对象,可以得到任意一个对象所属的类的信息,可以调用任意一个类的成员变量和方法,可以获取任意一个对象的属性和方法。这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制。
二、Class类
Class是JDK定义的类,它提供了很多方法,通过调用Class类的成员方法可以获取Class对象中的信息(.class文件中的类信息)。由于Class对象代表的是.class文件(类),因此可以说所有的类实际上都是Class类的实例,所有的对象都可以转变为Class类型表示。
Class类本身没有定义任何的构造方法,所以如果要使用Class类,必须通过以下三种方式进行实例化。若已知具体的类,通过类的 class 属性获取,该方法最为安全可靠,程序 性能最高。
实例化Class对象的三种方式:
(1)根据全限定类名获取:Class.forName(“全限定类名”)。
(2)根据类名获取:类名.class;根据对象获取:对象.getClass();
(3)根据对象获取:对象.getClass();
public class MyReflectDemo1 {
public static void main(String[] args) throws Exception {
//第一种 全类名:包名 + 类名(常用)
Class clazz1 = Class.forName("com.example.demo1.Student");
//第二种(参数使用)
Class clazz2 = Student.class;
//第三种(已经有对象的情况下)
Student student = new Student();
Class clazz3 = student.getClass();
//对比
System.out.println(clazz1 == clazz2);//true
System.out.println(clazz1 == clazz3);//true
System.out.println(clazz2 == clazz3);//true
}
}
public class Student {
private String name;
private String age;
public Student() {
}
public Student(String name, String age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age='" + age + '\'' +
'}';
}
}
三、作用
1、获取类中的构造器
//对应的Student类
public 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 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;
}
}
先获取相应类的字节码文件
Class clazz = Class.forName("com.example.demo2.Student");
获取所有的 public 修饰的构造方法
Constructor[] constructors = clazz.getConstructors();
for (Constructor con : constructors){
System.out.println(con);
}
获取所有构造方法
Constructor[] declaredConstructors = clazz.getDeclaredConstructors();
for (Constructor con2 : declaredConstructors){
System.out.println(con2);
}
获取单个指定构造方法 getConstructor()只能获取公共的
Constructor declaredConstructor = clazz.getDeclaredConstructor();
Constructor declaredConstructor1 = clazz.getDeclaredConstructor(String.class);
Constructor declaredConstructor2 = clazz.getDeclaredConstructor(String.class, int.class);
//参数对应的是构造器中的参数累心那个字节码
获取权限修饰符 但返回的是数字
int modifiers = declaredConstructor2.getModifiers();
获取私有的参数 这样可以在创建对象的时候展现出相应的形参,但是无法直接使用
Parameter[] parameters = declaredConstructor2.getParameters();
for (Parameter para : parameters){
System.out.println(para);
}
创建对象时,会给出提示,即使是私有的构造器。
创建实例对象
//暴力反射,表示临时取消权限的校验。因为该构造器为私有的,不能被调用
declaredConstructor2.setAccessible(true);
Student stu = (Student) declaredConstructor2.newInstance("张三", 4);
System.out.println(stu);
2、获取类中的成员变量
//对应的Student类 要注意权限修饰符
public 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 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;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
}
先获取相应类的字节码文件
Class clazz = Class.forName("com.example.demo3.Student");
获取所有的成员变量
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields){
System.out.println(field);
}
获取单个的成员变量 getField()只能获取公共的
Field gender = clazz.getField("gender");
获取成员变量的修饰符
//获取私有的成员变量
Field name = clazz.getDeclaredField("name");
//获取成员变量的修饰符
int modifiers = name.getModifiers();
//获取成员变量的修饰符名字
String name1 = name.getName();
//获取成员变量的数据类型
Class type = name.getType();
//获取成员变量记录的值
Student student = new Student("张三", 23, "男");
//取消访问权限 否则private报错
name.setAccessible(true);
String stuName = (String) name.get(student);
name.set(student,"lisi");
3、获取类中的方法
student类
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
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;
}
public void sleep(){
System.out.println("睡觉");
}
private void eat(String something) throws IOException,ClassNotFoundException {
System.out.println("在吃" + something);
}
private void eat(String something,int a){
System.out.println("在吃" + something);
}
}
获取方法
//获取所有方法对象 getMethods()获取的是所有的公共方法,包括在父类中的
Method[] methods = clazz.getMethods();
for (Method method : methods){
System.out.println(method);
}
//获取所有方法,包括私有,但不包括父类中的方法
Method[] methods1 = clazz.getDeclaredMethods();
for (Method method : methods1) {
System.out.println(method);
}
//获取指定单一的方法
Method method = clazz.getDeclaredMethod("eat", String.class);
System.out.println(method);
获取方法的各种修饰
//获取方法的修饰符
Method method = clazz.getDeclaredMethod("eat", String.class);
int modifiers = method.getModifiers();
System.out.println(modifiers);
//获取方法的名字
String name = method.getName();
System.out.println(name);
//获取方法的参数
Parameter[] parameters = method.getParameters();
for (Parameter parameter : parameters) {
System.out.println(parameter);
}
//获取方法抛出的异常
Class<?>[] exceptionTypes = method.getExceptionTypes();
for (Class<?> exceptionType : exceptionTypes) {
System.out.println(exceptionType);
}
调用方法,并且获取方法的放回值
这时候要在Student类中修改eat的方法为:
private String eat(String something) throws IOException,ClassNotFoundException { System.out.println("在吃" + something); return "肥料"; }
获取方法的返回值
Object invoke(Object obj,Object ...args)
- 参数一:用obj对象调用该方法
- 参数二:调用方法的传递参数(没有不写)
Student student = new Student();
method.setAccessible(true);
String result = (String) method.invoke(student, "炸鸡");
System.out.println(result);//在吃炸鸡 肥料