1,Java反射机制(Reflection)是Java语言中一个强大的工具,它提供了一些类和接口允许程序在运行时检查和操作类的结构和行为。也就是说在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性。反射的本质理解是得到class对象后,反向获取对象的各种信息。通常当执行new Person()创建一个Person类时,JVM会去本地磁盘找person.class文件并加载person.class到内存中,同时产生Class对象,这个Class对象是JVM自动创建的,一个类只产生一个Class对象。Class类的实例对象表示正在运行的Java应用程序中的类和接口,每个类都有唯一的Class对象。Class类没有公共构造方法。Class对象是在加载类时由Java虚拟机自动构造的,Class 对象用于提供类本身的信息。
2,反射的使用步骤,1)获取想要操作的Class对象,它是反射的核心,我们可以通过Class对象任意调用。2)调用 Class 类中的方法是反射的使用阶段。3)使用反射 API 操作这些信息。
3,Java反射 API 用来生成 JVM 类别、接口或对象的信息,包括如下类别:
1)Class 类:反射的核心类,可获取类属性、方法等信息。 2)Field 类:Java.lang.reflec 包中的类,表示类的成员变量,可用于获取和设置类中的属性值。 3)Method 类:Java.lang.reflec 包中的类,表示类的方法,可用于获取方法信息或执行方法。 4)Constructor 类:Java.lang.reflec 包中的类,表示类的结构方法。
4,除了使用new创建对象外,使用Java反射可以创建对象。通过new创建对象的效率相对较高。通过反射,首先找到类资源,使用类加载器创建,过程繁琐,效率较低。
5,反射机制的优缺点。优点:1)能够运行时动态获取类的实例,提高灵活性;2)与动态编译结合。缺点:使用反射性能较低,需要解析字节码,将内存中的对象进行解析。解决方案:1) 通过setAccessible(true)关闭JDK的安全检查来提升反射速度;2)多次创建一个类的实例时,有缓存会快很多;3) ReflflectASM工具类,通过字节码生成的方式加快反射速度;4) 相对不安全,破坏了封装性(因为通过反射可以获得私有方法和属性)。
6,Java反射机制的作用如下:1)在运行过程中判断任何对象的类别;2)在运行过程中构建任何类别的对象;3)在运行过程中判断任何类别的成员变量和方法;4)在运行过程中调用任何对象的方法。
7,获取Class对象
Class<?> clazz1 = MyClass.class; // 方式一:通过类名,需要导入类的包,依赖太强,不导包就抛编译错误
Class<?> clazz2 = new MyClass().getClass();// 方式二:通过对象实例,基本不常用,对象都有了一般不需要反射。
Class<?> clazz3 = Class.forName("com.example.MyClass");// 方式三:通过类的全限定名
8,获取构造器对象方法:
批量的方法:
public Constructor[] getConstructors() //所有"公有的"构造方法
public Constructor[] getDeclaredConstructors() //获取所有的构造方法(包括私有、受保护、默认、公有)
获取单个的方法:
public Constructor getConstructor(Class… parameterTypes)//获取单个的"公有的"构造方法
public Constructor getDeclaredConstructor(Class…parameterTypes) //获取"某个构造方法"可以是私有的,或受保护、默认、公有;
Constructor con = clazz.getConstructor(形参.class);
MyClass hero =con.newInstance(实参);
Constructor<?>[] constructors = clazz1.getDeclaredConstructors();//获取所有的构造方法(包括私有、受保护、默认、公有)
for (Constructor<?> constructor : constructors) {
Object obj = constructor.newInstance();//生成反射类的对象,Constructor对象调用newInstance(Object... initargs)创建对象
}
9,获取类的属性
getField和getDeclaredField的区别
getField 只能获取public的,包括从父类继承来的字段。
getDeclaredField 可以获取本类所有的字段,包括private的,但是 不能获取继承来的字段。
Field[] fields = clazz1.getDeclaredFields();
for (Field field : fields) {
field.set();//操作反射类的属性
}
10,获取类的方法
Method[] methods = clazz1.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method);
}
11,操作属性
Field field = clazz1.getDeclaredField("someField");
field.setAccessible(true); // 设置为可访问
field.set(obj, "newValue"); // 设置属性值
Object value = field.get(obj); // 获取属性值
12,调用方法
Method method = clazz1.getDeclaredMethod("someMethod", String.class);//获取成员方法,包括私有的(不包括继承的)
method.setAccessible(true); // 设置为可访问
Object result = method.invoke(obj, "argument"); // 调用方法
13,举例如下
对于一个类Person,
class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
public static void main(String[] args) {
try {
// 获取Class对象
Class<?> clazz = Class.forName("com.example.Person");
// 获取类的构造方法
Constructor<?> constructor = clazz.getConstructor(String.class, int.class);
Object person = constructor.newInstance("Hello", 30);
// 获取和操作属性
Field nameField = clazz.getDeclaredField("name");
nameField.setAccessible(true);
System.out.println("Name before: " + nameField.get(person));
nameField.set(person, "Jane Doe");
System.out.println("Name after: " + nameField.get(person));
// 获取和调用方法
Method getNameMethod = clazz.getDeclaredMethod("getName");
System.out.println("Invoked getName: " + getNameMethod.invoke(person));
Method setNameMethod = clazz.getDeclaredMethod("setName", String.class);
setNameMethod.setAccessible(true);
setNameMethod.invoke(person, "John Smith");
System.out.println("Invoked setName: " + getNameMethod.invoke(person));
} catch (Exception e) {
e.printStackTrace();
}
}