简单介绍
那么什么叫做反射呢
英语告诉我们叫:Reflection,ok,讲解完成,拜拜\n*100
ok,看来你已经看了105行了,接下来才是重点
Java的反射是指程序在运行期可以拿到一个对象的所有信息。
正常情况下,如果我们要调用一个对象的方法,或者访问一个对象的字段,通常会传入对象实例:
main
public class Main {
public static void main(String[] args) {
doome doome1 = new doome();
doome1.test("获得美女微信嘻嘻嘻");
}
}
dome
public class doome {
public void test(String name){
System.out.println(name);
}
}
这样的叫做正射,也就是你知道这个类,并且去new进行调用,进行初始化,使用类去操作。当然前提是你知道这个类。
那么自然反射就知道了,你不知道这个类是什么,不能去进行初始化,我们只知道一些基本的信息。
举个栗子:
你在校园里面走路,发现一个美女,想加微信,但是不太好,求兄弟(给兄弟跪下),让他去帮你要🐎,从而获得了美女的微信
你只需要知道这个美女的特征,让兄弟(反射API)去根据你描述的信息去获得微信,你不需要知道怎么去获得的,你只要知道🐎就行
场景: 你想加一个美女的微信
过程:
你知道的特征:长发、红衣服、在图书馆(=类名+方法名+参数的字符串描述)
兄弟(反射API):接收你的特征描述,去校园里找人
兄弟的操作:
根据“长发红衣服在图书馆”找到对应的人(=Class.forName("类名"))
使用特定话术要微信(=getMethod("方法名"))
执行要微信操作(=method.invoke())
你得到的结果:微信二维码(=方法返回值)
ok,代码就出来了
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class Main {
public static void main(String[] args) throws Exception {
// 1. 加载类:
Class<?> clazz = Class.forName("doome"); // 注意:类名要和上面的doome完全一致(包括大小写)//长头发
// 2. 获取方法:
// 参数1:方法名(你的方法是test);参数2:方法的参数类型(String.class)
Method method = clazz.getMethod("test", String.class);//图书馆
// 3. 获取构造器:
Constructor constructor = clazz.getConstructor();
//getConstructor() 找的是公有的构造器,如果要找私有的需要用 getDeclaredConstructor()//找到美女在的教室了
// 4. 创建对象:
Object object = constructor.newInstance();//获得对象,即兄弟找到美女了
// 5. 调用方法
method.invoke(object, "获得美女微信嘻嘻嘻");
}
}
ok,那么上面的就是反射了
优缺点
缺点:
- 破坏封装:由于反射允许访问私有字段和私有方法,所以可能会破坏封装而导致安全问题。
- 性能开销:由于反射涉及到动态解析,因此无法执行 Java 虚拟机优化,再加上反射的写法的确要复杂得多,所以性能要比“正射”差很多,在一些性能敏感的程序中应该避免使用反射。
优点:
- 开发通用框架:像 Spring,为了保持通用性,通过配置文件来加载不同的对象,调用不同的方法。
- 动态代理:在面向切面编程中,需要拦截特定的方法,就会选择动态代理的方式,而动态代理的底层技术就是反射。
- 注解:注解本身只是起到一个标记符的作用,它需要利用反射机制,根据标记符去执行特定的行为。
栗子
讲解之前让我们先了解一下
第一步
获取反射类的 Class 对象:
// 1. 加载类:
Class<?> clazz = Class.forName("doome"); // 注意:类名要和上面的doome完全一致(包括大小写)//长头发
首先在java里面class是一个特殊的对象,代表程序里面的类和接口。Java 中的每个类型(包括类、接口、数组以及基础类型)在 JVM 中都有一个唯一的 Class 对象与之对应。
Class 对象中包含了与类相关的很多信息,如类的名称、类的父类、类实现的接口、类的构造方法、类的方法、类的字段等等。这些信息通常被称为元数据(metadata)。
当然除了前面提到的,通过类的全名获取 Class 对象,还有以下两种方式:
- 如果你有一个类的实例,你可以通过调用该实例的
getClass()方法获取 Class 对象。例如:String str = "Hello World"; Class cls = str.getClass(); - 如果你有一个类的字面量(即类本身),你可以直接获取 Class 对象。例如:
Class cls = String.class;
第二步
通过 Class 对象获取构造方法 Constructor 对象:
Method method = clazz.getMethod("test", String.class);//图书馆
第三步
通过 Constructor 对象初始化反射类对象:
// 3. 获取构造器:
Constructor constructor = clazz.getConstructor();
//getConstructor() 找的是公有的构造器,如果要找私有的需要用 getDeclaredConstructor()//找到美女在的教室了
第四步
获取要调用的方法的 Method 对象:
// 4. 创建对象:
Object object = constructor.newInstance();//获得对象,即兄弟找到美女了
第五步
通过 invoke() 方法执行:
// 5. 调用方法
method.invoke(object, "获得美女微信嘻嘻嘻");
机制讲解
使用反射,首先需要获得反射类的 Class 对象,每一个类,不管它最终生成了多少个对象,这些对象只会对应一个 Class 对象,这个 Class 对象是由 Java 虚拟机生成的,由它来获悉整个类的结构信息。
也就是说,java.lang.Class 是所有反射 API 的入口。
java.lang.Class:标识嘞的对象,提供了方法来获取类的字段、方法、构造函数等java.lang.reflect.Field:表示类的字段(属性)。提供了访问和修改字段的能力java.lang.reflect.Method:表示类的方法。提供了调用方法的能力java.lang.reflect.Constructor:表示类的构造函数。提供了创建对象的能力
而方法的反射调用,最终是由 Method 对象的 invoke() 方法完成的
插播一下:weiny说:学新知识点的难点往往不在于语言是否清晰,而是对专业名词的理解 md,怎么感觉比如我列举出来的栗子都nb啊,服了

