目录
看完这个使用方法,那么可以深入理解反射的作用了(白话理解反射的作用)
这个示例演示了如何使用反射获取类的构造器。在示例中,printConstructors 和 printConstructor 方法用于打印构造器的信息。
这个示例演示了如何使用反射获取类的成员变量。在示例中,printFields 和 printField 方法用于打印成员变量的信息
在这个示例中,printMethods 和 printMethod 方法用于打印成员方法的信息。这样,你就能够使用反射获取类的成员方法并进行操作。
反射是什么?
反射其实是Java提供的一种方法,能够加载类,并允许以编程的方式解剖类中的各种成分(成员变量,方法,构造器(构造方法)等) 其实就是一种在运行时检查或操作类,方法,字段等程序结构的能力。(在Java中,反射机制允许程序在运行时获取类的信息,调用类的方法,访问类的字段)
反射的作用是什么?
想要理解反射的作用你先耐心浏览一遍反射的使用步骤
- 获取类型信息:通过反射可以获取类,结构体,接口等类型的信息,包括成员变量,方法,属性等。这可以让你在运行时动态的了解一个对象的结构
- 实例化对象:使用反射可以在运行时实例化对象,即使你在编写代码时不知道要实例化的确切类型
- 调用方法和属性:通过反射可以在运行时调用对象的方法和访问其属性,这对于动态地调用不同类型的对象的方法或属性是很有用的
- 获取和设置字段值:反射也可以用于获取和设置对象的字段值,即使这些字段是私有的
也可以这样理解
- 获取类的信息:通过反射可以获取类的名称,父类,接口,字段和方法等信息
- 创建对象:通过反射可以在运行时动态地创建对象,例如根据类名创建对象等
- 访问和修改对象的属性:通过反射可以获取和修改对象的属性值,包括私有属性和共有属性(反射的作用:可以破坏封装性)
- 调用对象的方法:通过反射可以调用对象的方法,包括私有方法和公有方法
- 获取和操作注解:通过反射可以获取类,方法,字段等上的注解,并可以根据注解的信息来动态地调整程序行为
下面是一个简单的例子,展示在Java中如何使用反射获取类信息
import java.lang.reflect.*;
public class ReflectionExample {
public static void main(String[] args) {
// 获取类信息
Class<?> clazz = String.class;
//这里的String是一个类,这里调用class方法来获取类信息
//<?>是范型,可以用来接收任何一个类型的对象
System.out.println("Class Name: " + clazz.getName());
// 获取构造方法
Constructor<?>[] constructors = clazz.getConstructors();
System.out.println("Constructors: " + Arrays.toString(constructors));
// 获取方法
Method[] methods = clazz.getMethods();
System.out.println("Methods: " + Arrays.toString(methods));
// 实例化对象
try {
Object obj = clazz.newInstance();
System.out.println("Instance: " + obj);
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
//try catch可以不用看,是系统对你的方法安全性有问题,重要的就是下面这三行
//Object obj = clazz.newInstance();
//System.out.println("Instance: " + obj);
//e.printStackTrace();
}
}
看完这个使用方法,那么可以深入理解反射的作用了(白话理解反射的作用)
通常情况下,当我们写程序时,我们在编码时,我们在编码时就已经知道了类的结构,比如类的名字,属性和方法。然而,反射允许程序在运行时去“探知”,“了解”类的信息,而不是在编写代码是就知道
考虑一个简单的例子:你在一个包中写了一个类,然后你在你的程序中引入了这个包,后来别人拿到了这个这个包的源码,对这个类进行了修改,增加了几个方法,这个时候你并不知道这个类进行了修改,但是,如果你使用反射,你的程序就可以在运行时就发现这个类的新方法,并调用它们,而不需要你在编写代码时就知道这些方法的存在。(这就是反射的作用)
当你使用反射时,你的程序可以在运行时动态地探查类的结构,包括新添加的方法,字段和参数等,如果某个类的源代码被修改,添加了新的方法和参数,而你的程序在运行时就使用了反射,它仍然能够发现并调用这些新的结构
这些特性有什么用
这些特性是的反射在某些情境下非常有用,尤其是在编写通用,灵活的代码,与其他可能被修改的代码交互时。例如,一些框架和库可能需要与用户提供的插件或模块进行交互,而这些插件可能会在运行时动态地添加新的功能
反射学什么?
- 反射第一步:加载类,获取类的字节码:Class对象
- 获取类的构造器:Constructor对象
- 获取类的成员变量:Field对象
- 获取类的成员方法:Method对象
反射第一步:加载类,获取类的字节码:class对象
序号 | 获取方式 | 示例 |
1 | 类字面量(MyClass.class) | Class clazz1 = MyClass.class; |
2 | 对象的 getClass() 方法 | MyClass obj = new MyClass(); <br>Class clazz2 = obj.getClass(); |
3 | Class.forName() 方法(通过类的全限定名) | Class clazz3 = Class.forName("com.example.MyClass"); |
import java.lang.reflect.*;
public class ReflectionExample {
public static void main(String[] args) {
// 通过类字面量获取Class对象
Class clazz1 = MyClass.class;
printClassInfo(clazz1);
// 通过对象的getClass()方法获取Class对象
MyClass obj = new MyClass();
Class clazz2 = obj.getClass();
printClassInfo(clazz2);
// 通过Class.forName()方法获取Class对象
try {
Class clazz3 = Class.forName("MyClass");
printClassInfo(clazz3);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static void printClassInfo(Class clazz) {
System.out.println("类名: " + clazz.getName());
System.out.println("简单类名: " + clazz.getSimpleName());
System.out.println("是否是接口: " + clazz.isInterface());
System.out.println("是否是数组: " + clazz.isArray());
System.out.println("是否是基本类型: " + clazz.isPrimitive());
System.out.println("---------------------------");
// 获取类的字段信息
Field[] fields = clazz.getDeclaredFields();
System.out.println("字段信息:");
for (Field field : fields) {
System.out.println("字段名: " + field.getName() + ", 类型: " + field.getType().getSimpleName());
}
System.out.println("---------------------------");
// 获取类的方法信息
Method[] methods = clazz.getDeclaredMethods();
System.out.println("方法信息:");
for (Method method : methods) {
System.out.println("方法名: " + method.getName() + ", 返回类型: " + method.getReturnType().getSimpleName());
}
System.out.println("---------------------------");
// 获取类的构造方法信息
Constructor[] constructors = clazz.getDeclaredConstructors();
System.out.println("构造方法信息:");
for (Constructor constructor : constructors) {
System.out.println("构造方法名: " + constructor.getName());
}
System.out.println("===========================");
}
}
class MyClass {
private int age;
public String name;
public MyClass() {
}
public MyClass(String name, int age) {
this.name = name;
this.age = age;
}
public void sayHello() {
System.out.println("Hello from MyClass!");
}
private void privateMethod() {
System.out.println("This is a private method.");
}
}
获取类的构造器:constructor对象
序号 | 获取构造器的方法 | 示例 |
---|---|---|
1 | getDeclaredConstructors() | Constructor[] constructors = clazz.getDeclaredConstructors(); |
2 | getDeclaredConstructor(Class<?>... parameterTypes) | Constructor constructor = clazz.getDeclaredConstructor(String.class, int.class); |
3 | getConstructors() | Constructor[] constructors = clazz.getConstructors(); |
4 | getConstructor(Class<?>... parameterTypes) | Constructor constructor = clazz.getConstructor(String.class, int.class); |
import java.lang.reflect.Constructor;
public class ConstructorExample {
public static void main(String[] args) {
// 获取 Class 对象
Class<?> clazz = MyClass.class;
// 1. 获取所有声明的构造器
Constructor<?>[] constructors1 = clazz.getDeclaredConstructors();
printConstructors("Declared Constructors", constructors1);
// 2. 获取指定参数类型的声明构造器
try {
Constructor<?> constructor1 = clazz.getDeclaredConstructor(String.class, int.class);
printConstructor("Declared Constructor with parameters", constructor1);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
// 3. 获取所有公共的构造器
Constructor<?>[] constructors2 = clazz.getConstructors();
printConstructors("Public Constructors", constructors2);
// 4. 获取指定参数类型的公共构造器
try {
Constructor<?> constructor2 = clazz.getConstructor(String.class, int.class);
printConstructor("Public Constructor with parameters", constructor2);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
public static void printConstructors(String title, Constructor<?>[] constructors) {
System.out.println(title + ":");
for (Constructor<?> constructor : constructors) {
System.out.println(constructor);
}
System.out.println("---------------------------");
}
public static void printConstructor(String title, Constructor<?> constructor) {
System.out.println(title + ":");
System.out.println(constructor);
System.out.println("---------------------------");
}
}
class MyClass {
private int age;
public String name;
public MyClass() {
}
public MyClass(String name, int age) {
this.name = name;
this.age = age;
}
public void sayHello() {
System.out.println("Hello from MyClass!");
}
private void privateMethod() {
System.out.println("This is a private method.");
}
}
这个示例演示了如何使用反射获取类的构造器。在示例中,
printConstructors
和printConstructor
方法用于打印构造器的信息。
获取类的成员变量:field对象
序号 | 获取成员变量的方法 | 示例 |
---|---|---|
1 | getDeclaredFields() | Field[] fields = clazz.getDeclaredFields(); |
2 | getDeclaredField(String name) | Field field = clazz.getDeclaredField("fieldName"); |
3 | getFields() | Field[] fields = clazz.getFields(); |
4 | getField(String name) | Field field = clazz.getField("fieldName"); |
import java.lang.reflect.Field;
public class FieldExample {
public static void main(String[] args) {
// 获取 Class 对象
Class<?> clazz = MyClass.class;
// 1. 获取所有声明的成员变量
Field[] fields1 = clazz.getDeclaredFields();
printFields("Declared Fields", fields1);
// 2. 获取指定名称的声明成员变量
try {
Field field1 = clazz.getDeclaredField("name");
printField("Declared Field by Name", field1);
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
// 3. 获取所有公共的成员变量
Field[] fields2 = clazz.getFields();
printFields("Public Fields", fields2);
// 4. 获取指定名称的公共成员变量
try {
Field field2 = clazz.getField("name");
printField("Public Field by Name", field2);
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
public static void printFields(String title, Field[] fields) {
System.out.println(title + ":");
for (Field field : fields) {
System.out.println(field);
}
System.out.println("---------------------------");
}
public static void printField(String title, Field field) {
System.out.println(title + ":");
System.out.println(field);
System.out.println("---------------------------");
}
}
class MyClass {
private int age;
public String name;
public MyClass() {
}
public MyClass(String name, int age) {
this.name = name;
this.age = age;
}
public void sayHello() {
System.out.println("Hello from MyClass!");
}
private void privateMethod() {
System.out.println("This is a private method.");
}
}
这个示例演示了如何使用反射获取类的成员变量。在示例中,
printFields
和printField
方法用于打印成员变量的信息
获取类的成员方法
序号 | 获取成员方法的方法 | 示例 |
---|---|---|
1 | getDeclaredMethods() | Method[] methods1 = clazz.getDeclaredMethods(); |
2 | getDeclaredMethod(String name, Class<?>... parameterTypes) | Method method1 = clazz.getDeclaredMethod("methodName", String.class, int.class); |
3 | getMethods() | Method[] methods2 = clazz.getMethods(); |
4 | getMethod(String name, Class<?>... parameterTypes) | Method method2 = clazz.getMethod("methodName", String.class, int.class); |
import java.lang.reflect.Method;
public class MethodExample {
public static void main(String[] args) {
// 获取 Class 对象
Class<?> clazz = MyClass.class;
// 1. 获取所有声明的成员方法
Method[] methods1 = clazz.getDeclaredMethods();
printMethods("Declared Methods", methods1);
// 2. 获取指定名称和参数类型的声明成员方法
try {
Method method1 = clazz.getDeclaredMethod("sayHello");
printMethod("Declared Method by Name", method1);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
// 3. 获取所有公共的成员方法
Method[] methods2 = clazz.getMethods();
printMethods("Public Methods", methods2);
// 4. 获取指定名称和参数类型的公共成员方法
try {
Method method2 = clazz.getMethod("sayHello");
printMethod("Public Method by Name", method2);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
public static void printMethods(String title, Method[] methods) {
System.out.println(title + ":");
for (Method method : methods) {
System.out.println(method);
}
System.out.println("---------------------------");
}
public static void printMethod(String title, Method method) {
System.out.println(title + ":");
System.out.println(method);
System.out.println("---------------------------");
}
}
class MyClass {
private int age;
public String name;
public MyClass() {
}
public MyClass(String name, int age) {
this.name = name;
this.age = age;
}
public void sayHello() {
System.out.println("Hello from MyClass!");
}
private void privateMethod() {
System.out.println("This is a private method.");
}
}
在这个示例中,
printMethods
和printMethod
方法用于打印成员方法的信息。这样,你就能够使用反射获取类的成员方法并进行操作。
反射的注意事项
虽然反射提供了修改更新程序的灵活性,但是需要注意,由于它绕过来编译时的类型检查,可能会导致一些潜在的运行时错误。比如反射能够通过一些方式获取私有方法,或者私有属性,并且对他们进行属性修改,但是其他人并不知道。