一、Java反射概述
Java反射机制指的是在Java程序运行状态中,对于任何一个类,都可以获得这个类的所有属性和方法;对于给定的一个对象,都能够调用它的任意一个属性和方法。这种动态获取类的内容以及动态调用对象的方法称为反射机制。
Java的反射机制允许编程人员在对类未知的情况下,获取类相关信息的方式变得更加多样灵活,调用类中相应方法,是Java增加其灵活性与动态性的一种机制。
二、Java反射的使用
1、想要使用Java反射,就必须先获取类的字节码文件对象,而获取字节码文件对象的方式有如下三种:
(1)Class.forName("类的全路径");
(2)对象.getClass(); 其中包括 this.getClass()
(3)类型.class;
2、通过Java反射获取构造方法并调用
2.1、创建一个Student实体类,用于反射调用
package com.reflex.pojo;
public class Student {
//无参数的公开构造方法
public Student(){
System.out.println("Student类的无参数的公开构造方法被调用");
}
//带有一个参数的公开构造方法
public Student(String name){
System.out.println("Student类带有一个参数的公开构造方法被调用,name="+name);
}
//带有两个参数的公开构造方法
public Student(String name, Integer age){
System.out.println("Student类带有两个参数的公开构造方法被调用,name="+name+" age="+age);
}
//带有一个参数的私有构造方法
private Student(Integer age){
System.out.println("Student类带有一个参数的私有构造方法被调用,age="+age);
}
}
2.2、获取构造方法的测试类
package com.reflex.program;
import java.lang.reflect.Constructor;
public class MyConstructor {
public static void main(String[] args) throws Exception{
System.out.println("------------------获取无参的公开构造方法------------------");
//1、获取类的字节码文件对象
Class<?> clazz = Class.forName("com.reflex.pojo.Student");
//2、获取无参数的公开构造方法
Constructor<?> constructor = clazz.getConstructor();
//3、创建对象实例并调用无参数的公开构造方法
constructor.newInstance();
System.out.println("------------------带有一个参数的公开构造方法------------------");
//1、获取类的字节码文件对象
Class<?> clazzForOne = Class.forName("com.reflex.pojo.Student");
//2、获取带有一个参数的公开构造方法
Constructor<?> constructorForOne = clazzForOne.getConstructor(String.class);
//3、创建对象实例并调用带有一个参数的公开构造方法
constructorForOne.newInstance("张三");
System.out.println("------------------带有两个参数的公开构造方法------------------");
//1、获取类的字节码文件对象
Class<?> clazzForTwo = Class.forName("com.reflex.pojo.Student");
//2、获取带有两个参数的公开构造方法
Constructor<?> constructorForTwo = clazzForTwo.getConstructor(String.class,Integer.class);
//3、创建对象实例并调用带有两个参数的公开构造方法
constructorForTwo.newInstance("李四",18);
System.out.println("------------------带有一个参数的私有构造方法------------------");
//1、获取类的字节码文件对象
Class<?> clazzForPrivate = Class.forName("com.reflex.pojo.Student");
//2、获取带有一个参数的私有构造方法 (注意:获取私有构造方法的方法名称是 getDeclaredConstructor)
Constructor<?> constructorForPrivate = clazzForPrivate.getDeclaredConstructor(Integer.class);
//3、设置带有一个参数的私有构造方法的访问权限
constructorForPrivate.setAccessible(true);
//4、创建对象实例并调用带有一个参数的私有构造方法
constructorForPrivate.newInstance(18);
}
}
2.3、测试输出结果如下:
------------------获取无参的公开构造方法------------------
Student类的无参数的公开构造方法被调用
------------------带有一个参数的公开构造方法------------------
Student类带有一个参数的公开构造方法被调用,name=张三
------------------带有两个参数的公开构造方法------------------
Student类带有两个参数的公开构造方法被调用,name=李四 age=18
------------------带有一个参数的私有构造方法------------------
Student类带有一个参数的私有构造方法被调用,age=18
3、通过Java反射获取方法并调用
3.1、创建一个Student实体类,用于反射调用
package com.reflex.pojo;
public class Student {
//无参数的公开构造方法
public Student(){}
//无参数的showMessage方法
public void showMessage(){
System.out.println("Student类无参数的showMessage方法被调用");
}
//带有一个参数的showName方法
public void showName(String name){
System.out.println("Student类带有一个参数的showName方法被调用,name="+name);
}
//带有两个参数的showNameAndAge方法
public void showNameAndAge(String name, Integer age){
System.out.println("Student类带有两个参数的showNameAndAge方法被调用,name="+name+" age="+age);
}
//带有一个参数的私有showAge方法
private void showAge(Integer age){
System.out.println("Student类带有一个参数的私有showAge方法被调用,age="+age);
}
//Student类的main方法
public static void main(String[] args) {
System.out.println("Student类的main方法被调用");
}
}
3.2、获取方法的测试类
package com.reflex.program;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class MyMethod {
public static void main(String[] args) throws Exception{
System.out.println("------------------获取无参的showMessage方法------------------");
//1、获取类的字节码文件对象
Class<?> clazz = Class.forName("com.reflex.pojo.Student");
//2、获取无参数的公开构造方法
Constructor<?> constructor = clazz.getConstructor();
//3、创建对象实例并调用无参数的公开构造方法
Object object = constructor.newInstance();
//4、获取无参数的showMessage方法
Method showMessage = clazz.getMethod("showMessage");
//5、调用showMessage方法
showMessage.invoke(object);
System.out.println("------------------获取带有一个参数的showName方法------------------");
//1、获取类的字节码文件对象
Class<?> clazzForOne = Class.forName("com.reflex.pojo.Student");
/*
* Constructor<?> constructorForOne = clazzForOne.getConstructor();
* Object object = constructorForOne.newInstance();
* 等价于
* Object object = clazzForOne.newInstance();
*/
//2、创建对象实例并调用无参的构造方法
Object objectForOne = clazzForOne.newInstance();
//3、获取带有一个参数的showName方法 (第一个参数为方法名,后面的参数为参数的字节码)
Method showName = clazzForOne.getMethod("showName",String.class);
//4、调用showName方法 (第一个参数为调用该方法的对象,后面的参数为方法的实参)
showName.invoke(objectForOne,"张三");
System.out.println("------------------获取带有两个参数的showNameAndAge方法------------------");
//1、获取类的字节码文件对象
Class<?> clazzForTwo = Class.forName("com.reflex.pojo.Student");
//2、创建对象实例并调用无参的构造方法
Object objectForTwo = clazzForTwo.newInstance();
//3、获取带有两个参数的showNameAndAge方法
Method showNameAndAge = clazzForTwo.getMethod("showNameAndAge",String.class,Integer.class);
//4、调用showNameAndAge方法
showNameAndAge.invoke(objectForTwo,"张三",18);
System.out.println("------------------获取带有一个参数的私有showAge方法------------------");
//1、获取类的字节码文件对象
Class<?> clazzForPrivate = Class.forName("com.reflex.pojo.Student");
//2、创建对象实例并调用无参的构造方法
Object objectForPrivate = clazzForPrivate.newInstance();
//3、获取带有一个参数的私有showAge方法 (注意:获取私有方法的方法名称是 getDeclaredMethod)
Method showAge = clazzForPrivate.getDeclaredMethod("showAge",Integer.class);
//4、设置带有一个参数的私有showAge方法的访问权限
showAge.setAccessible(true);
//5、调用showAge方法
showAge.invoke(objectForPrivate,18);
System.out.println("------------------获取Student类的静态main方法------------------");
//1、获取类的字节码文件对象
Class<?> clazzFoMain = Class.forName("com.reflex.pojo.Student");
//2、获取Student类的静态main方法
Method main = clazzFoMain.getMethod("main",String[].class);
/*
*调用Student类的静态main方法 (由于main方法是静态方法,所以第一个参数可以给对象,也可以给null)
*另一种调用方式 main.invoke(null,new Object[]{new String[]{"a","b","c"}});
*/
main.invoke(null,(Object)new String[]{"a","b","c"});
}
}
3.3、测试输出结果如下:
------------------获取无参的showMessage方法------------------
Student类无参数的showMessage方法被调用
------------------获取带有一个参数的showName方法------------------
Student类带有一个参数的showName方法被调用,name=张三
------------------获取带有两个参数的showNameAndAge方法------------------
Student类带有两个参数的showNameAndAge方法被调用,name=张三 age=18
------------------获取带有一个参数的私有showAge方法------------------
Student类带有一个参数的私有showAge方法被调用,age=18
------------------获取Student类的静态main方法------------------
Student类的main方法被调用
4、通过Java反射获取字段并打印
4.1、创建一个Student实体类,用于反射调用
package com.reflex.pojo;
public class Student {
private String name;
private static Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public static Integer getAge() {
return age;
}
public static void setAge(Integer age) {
Student.age = age;
}
}
4.2、获取字段的测试类
package com.reflex.program;
import com.reflex.pojo.Student;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
public class MyField {
public static void main(String[] args) throws Exception{
System.out.println("------------------获取私有name字段------------------");
//1、获取类的字节码文件对象
Class<?> clazz = Class.forName("com.reflex.pojo.Student");
//2、获取无参数的公开构造方法
Constructor<?> constructor = clazz.getConstructor();
//3、创建对象实例并调用无参数的公开构造方法
Student object = (Student)constructor.newInstance();
//4、获取私有name字段 (注意:获取私有字段的方法名称是 getDeclaredField)
Field name = clazz.getDeclaredField("name");
//5、设置私有name字段的访问权限
name.setAccessible(true);
//6、为私有字段name赋值 (第一个参数为调用该字段的对象,后面的参数为字段的值)
name.set(object,"张三");
//7、输出该字段的值
System.out.println("私有name字段的值为:"+object.getName());
System.out.println("------------------获取私有静态age字段------------------");
//1、获取类的字节码文件对象
Class<?> clazzForAge = Class.forName("com.reflex.pojo.Student");
//1、获取私有静态age字段
Field age = clazzForAge.getDeclaredField("age");
//5、设置私有静态age字段的访问权限
age.setAccessible(true);
//6、为私有静态字段age赋值 (由于age字段是静态字段,所以第一个参数可以给对象,也可以给null)
age.set(null,18);
//7、输出该字段的值
System.out.println("私有静态age字段的值为:"+Student.getAge());
}
}
4.3、测试输出结果如下:
------------------获取私有name字段------------------
私有name字段的值为:张三
------------------获取私有静态age字段------------------
私有静态age字段的值为:18