反射
示例代码
import java.lang.reflect.*;
public class Example {public static void main(String[] args) throws Exception {// 获取 Class 对象Class<?> clazz = Class.forName("java.lang.String");// 获取类名、包名和修饰符String className = clazz.getName();String packageName = clazz.getPackage().getName();int modifiers = clazz.getModifiers();String modifierStr = Modifier.toString(modifiers);System.out.println("类名:" + className);System.out.println("包名:" + packageName);System.out.println("修饰符:" + modifierStr);// 获取构造器并创建对象Constructor<?> constructor = clazz.getConstructor(String.class);Object object = constructor.newInstance("Hello, world!");// 调用字符串方法,将字母转为大写Method method = clazz.getMethod("toUpperCase");String result = (String) method.invoke(object);System.out.println(result);}
}
反射的概念
反射机制指在程序运行过程中,对任意一个类都能获取其所有属性和方法,并且对任意一个对象都能调用其任意一个方法。这种动态获取类和对象的信息,以及动态调用对象的方法的功能被称为Java语言的反射机制。
反射(Reflection)是 Java 中非常重要且强大的一个特性,它允许程序在运行时动态地获取、检查和修改类的字段、方法、构造函数等成员,以及调用对象的方法,而不需要事先知道这些成员的名字或类型。
通过反射,程序可以在运行时操作类的成员,而不必依赖于编译时的类型信息。这为我们编写灵活、扩展性强的代码提供了无限的可能性,可以更加方便地实现一些高级的功能和框架,如依赖注入、ORM 等。
在 Java 中,反射主要由以下三个类或接口组成:
- Class 类:表示一个 Java 类型的类对象,包含了该类的所有信息,例如字段、方法、构造函数等成员。
- Constructor 类:表示一个类的构造函数,可以用来创建该类的新实例。
- Method 类:表示一个类的方法,可以用来调用该方法并获取方法的返回值。
反射的使用需要谨慎,因为它带来了一定的性能损失和安全风险。反射可以绕过访问权限的限制,因此不得不对其进行限制控制。反射还会使代码变得复杂和难以维护,同时也不符合面向对象编程的原则。因此,在实际开发中,应该根据具体需求和场景合理使用反射。
反射的步骤
(1)获取想要操作的类的Class对象,该Class对象是反射的核心,通过它可以调用类的任意方法。
-
获取class对象的方法如下
-
调用某个对象的getClass方法以获取该类对应的Class对象
Person p = new Person(); Class clazz = p.getClass();
-
调用某个类的class属性以获取该类对应的Class对象
Class clazz = Person.class;
-
调用Class类中的forName静态方法以获取该类对应的Class对象,这是最安全、性能也最好的方法
Class clazz=Class.forName("fullClassPath"); //fullClassPath为类的包路径及名称
-
(2)调用Class对象所对应的类中定义的方法,这是反射的使用阶段。
(3)使用反射API来获取并调用类的属性和方法等信息。
示例代码
//1:获取Person类的Class对象
Class clazz = Class.forName("hello.java.reflect.Persion");
//2:获取Person类的所有方法的信息
Method[] method = clazz.getDeclaredMethods();
for(Method m:method){System.out.println(m.toString());
}//3:获取Person类的所有成员的属性信息
Field[] field = clazz.getDeclaredFields();
for(Field f:field){System.out.println(f.toString());
}
//4:获取Person类的所有构造方法的信息
Constructor[] constructor = clazz.getDeclaredConstructors();
for(Constructor c:constructor){System.out.println(c.toString());
}
反射创建对象
创建对象的两种方式如下
-
使用Class对象的newInstance方法创建该Class对象对应类的实例,这种方法要求该Class对象对应的类有默认的空构造器
-
先使用Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance方法创建Class对象对应类的实例,通过这种方法可以选定构造方法创建实例。
示例代码
//1.1:获取Person类的Class对象
Class clazz = Class.forName("hello.java.reflect.Persion");
//2.1:使用newInstane方法创建对象
Person p = (Person) clazz.newInstance();
//1.2:获取构造方法并创建对象
Constructor c = clazz.getDeclaredConstructor(String.class, String.class, int.class);
//2.2:根据构造方法创建对象并设置属性
Person p1 = (Person) c.newInstance("李四", "男",20);
反射调用对象的方法
反射提供了 Method 类来表示一个类的方法,并允许我们在运行时动态地获取、调用和修改对象的方法。invoke()
方法可以用来调用指定对象的方法,并传入方法参数。
示例代码
//step 1:获取Persion类(hello.java.reflect.Persion)的Class对象
Class clz = Class.forName("hello.java.reflect.Persion");
//step 2:获取Class对象中的setName方法
Method method = clz.getMethod("setName", String.class);
//step 3:获取Constructor对象
Constructor constructor = clz.getConstructor();
//step 4:根据Constructor定义对象
Object object = constructor.newInstance(); //
//step 5:调用method的invoke方法,这里的method表示setName方法
//因此,相当于动态调用object对象的setName方法并传入alex参数
method.invoke(object, "alex");