目录
参考:https://blog.csdn.net/weixin_45525272/article/details/125821047
一、反射概述
反射机制:是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意属性和方法;这种动态获取信息以及动态调用对象方法的功能称为 java 语言的反射机制。
反射原理:jvm加载.class文件时会为每个java类创建一个class对象,class对象会保存类的所有函数、属性等信息,我们只要获取到类的class对象,就可以通过class对象在不知道类的类型的情况下创建类的对象、调用类的函数。
二、获取class类对象的方法
获取Class类对象有三种方式:
(1)Class.forName(全类名)方法:编译期获取,通过Class的静态函数forName
(2)类名.class属性:加载字节码阶段获取,加载类名时获取其class属性
(3)对象名.getClass()方法:运行时获取,通过被创建的对象的getClass方法
代码示例如下:
package org.example;
class Student{
};
public class App
{
public static void main( String[] args ) throws ClassNotFoundException {
// 1.通过类名获取
Class clazz1 = Class.forName("org.example.Student");
System.out.println(clazz1);
// 2.通过class属性来获取
Class clazz2 = Student.class;
System.out.println(clazz2);
// 3.利用对象的getClass方法来获取class对象
Student s = new Student();
Class clazz3 = s.getClass();
System.out.println(clazz3);
//同一个类的类对象都相同
System.out.println(clazz1 == clazz2);
System.out.println(clazz2 == clazz3);
}
}
执行结果如下:
class org.example1.Student
class org.example1.Student
class org.example1.Student
true
true
三、通过反射创建并操作类对象
代码示例如下:
package org.example;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
class Student{
private Integer id;
private String name;
public Student()
{
id = 0;
name = "";
System.out.println( "Student()");
}
public Student(Integer id,String name)
{
this.id = id;
this.name = name;
System.out.println( "Student(int id,String name)");
}
public void test1(String s){
System.out.println( "public test1("+s+")" + this);
}
private void test2(String s){
System.out.println( "private test2("+s+")" + this);
}
public String toString() {
return "["+id.toString()+","+name.toString()+"]";
}
};
public class App
{
public static void main( String[] args ) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException {
//1.通过类名获取Student的类对象
Class clazz1 = Class.forName("org.example.Student");
System.out.println(clazz1);
//创建Student对象,getConstructor:获取构造函数Student(Integer,String),newInstance:调用构造函数Student(1,"gekang1")
Object obj1 = (Object) clazz1.getConstructor(Integer.class,String.class).newInstance(1,"gekang1");
//2.知道Student类的情况下通对象调用函数
if(obj1 instanceof Student)
{
Student s1 = (Student) obj1;
s1.test1("s1");
}
//3.修改对象变量(不知道Student类的情况)
Field f1 = clazz1.getDeclaredField("name");
//私有变量访问前先临时设置其访问属性
f1.setAccessible(true);
//修改私有变量的值
f1.set(obj1,"gekang2");
//4.获取并调用公有函数,getDeclaredMethod获取公有函数test1(String)
Method m1 = clazz1.getDeclaredMethod("test1",String.class);
//调用函数test1("m1")
m1.invoke(obj1,"m1");
//5.获取并调用私有函数test2(String)
Method m2 = clazz1.getDeclaredMethod("test2",String.class);
//设置私有函数访问属性
m2.setAccessible(true);
//调用私有函数test2("m2")
m2.invoke(obj1,"m2");
}
}
执行结果如下:
class org.example.Student
Student(int id,String name)
public test1(s1)[1,gekang1]
public test1(m1)[1,gekang2]
private test2(m2)[1,gekang2]
四、反射应用
1.数据库驱动引擎
代码示例如下:
package org.example;
import java.lang.reflect.InvocationTargetException;
//数据库接口
interface db {
abstract void connect(String server);
abstract void execute(String sql);
abstract void fetchall();
}
//oracle引擎
class oracle implements db {
@Override
public void connect(String server) {
System.out.println("oracle connect:" + server);
}
@Override
public void execute(String sql) {
System.out.println("oracle execute:" + sql);
}
@Override
public void fetchall() {
System.out.println("oracle fetchall");
}
}
//mysql引擎
class mysql implements db{
@Override
public void connect(String server) {
System.out.println("mysql connect:" + server);
}
@Override
public void execute(String sql) {
System.out.println("mysql execute:" + sql);
}
@Override
public void fetchall() {
System.out.println("mysql fetchall");
}
}
public class App
{
public static void main( String[] args ) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
//可从配置文件读取数据库驱动引擎
String database = "org.example.mysql";
//获取数据库驱动引擎类对象
Class<?> dbClass = Class.forName(database);
//反射生成数据库引擎对象(用户只需依赖db接口即可,无需以来oracle和mysql类)
db a = (db)dbClass.getDeclaredConstructor().newInstance();
//使用数据库引擎对象
a.connect("127.0.0.1:1000");
a.execute("select * from dual");
a.fetchall();
}
}
执行结果如下:
mysql connect:127.0.0.1:1000
mysql execute:select * from dual
mysql fetchall
2.面向切面编程(AOP)
面向切面编程底层本质是用了反射,代码示例如下:
package org.example;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
interface IStudent{
void test(String name);
void test2();
}
class Student implements IStudent{
@Override
public void test(String name){
System.out.println("Stuend test:" + name);
}
@Override
public void test2(){
System.out.println("Stuend test2");
}
}
class StudentHandler implements InvocationHandler {
private final Object target;
public StudentHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("在调用方法之前执行一些操作:" + method.getName());
Object result = method.invoke(target, args);
System.out.println("在调用方法之后执行一些操作:"+ method.getName());
return result;
}
}
public class App {
public static void main(String[] args) {
//模拟spring boot框架启动时创建Student对象
Student s1 = new Student();
//创建Student拦截器
StudentHandler sh = new StudentHandler(s1);
//创建Student代理(实际返回给用户的是该代理对象)
IStudent s2 = (IStudent)Proxy.newProxyInstance(s1.getClass().getClassLoader(),s1.getClass().getInterfaces(),sh);
//执行Student成员函数
s2.test("gekang");
s2.test2();
}
}