1、反射概述
1.1什么是反射
反射(Reflection)是Java 一个强大的特性,它允许程序在运行时动态地获取、访问类的所有信息。
1.2反射的作用
获取类信息:在运行时,可以获取任意一个对象所属的类,包括类的名称、包名、父类、接口、注解等。
动态创建实例 :无需使用new关键字,可以通过类名(字符串)在运行时构造任意类的对象。
访问成员变量:可以获取类的所有变量(包括私有和final 变量),并读取或修改其值,突破了访问权限的限制。
调用方法:可以获取类的所有方法(包括私有方法),并动态地调用它们。
2、Class
2.1 class概述
Class 类的核心概念:
JVM加载完类之后,在堆内存中就产生了一个Class类型的对象;
Class对象像该类的 "说明书"包含了这个类的所有信息(类名、父类、接口、属性、方法、构造器等);
Class对象是反射的根源。
简单来说:
你写的 Person 类、String 类、ArrayList 类,在 JVM 加载后,都会对应一个 Class 对象;
这个 Class 对象是唯一的 (一个类在 JVM 中只有一份字节码,对应一个 Class 对象);
程序运行时,通过这个 Class 对象就能 "反推" 出原类的所有信息,这就是反射的基础。
从 JVM 层面看:
反射的本质是程序通过访问 JVM 中存储的类的元数据(类名、属性、方法、构造器),突破编译期的访问控制检查,直接操作类的底层数据结构。
2.2获取Class对象的三种方式
三种方式:
-
类.class
-
对象.getClass()
-
Class.forName(全类名)
案例:
Student类:
java
public class Student {
private String name;
private int age;
private String address;
//构造方法:一个私有,一个默认,两个公共
public Student() {
}
private Student(String name) {
this.name = name;
}
Student(String name, int age) {
this.name = name;
this.age = age;
}
public Student(String name, int age, String address) {
this.name = name;
this.age = age;
this.address = address;
}
//成员方法:一个私有,四个公共
//成员方法:一个私有,四个公共
public void method1() {
System.out.println("执行method1()");
}
public void method2(String s) {
System.out.println("执行method2():" + s);
}
private void method3() {
System.out.println("执行method3()");
}
private String method4(String s, int i) {
return "执行method3():"+s + "," + i;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", address='" + address + '\'' +
'}';
}
}
ClassTest类:
java
public class ClassTest {
public static void main(String[] args) throws ClassNotFoundException {
System.out.println("---------使用类.属性来获取该类对应的Class对象---------");
Class<Student> c1 = Student.class;
System.out.println(c1);
Class<Student> c2 = Student.class;
System.out.println(c1 == c2);
System.out.println("---使用对象.getClass()方法返回该对象所属类对应的Class对象--");
Student s = new Student();
Class<? extends Student> c3 = s.getClass();
System.out.println(c1 == c3);
System.out.println("----使用Class.forName(全类名)来获取该类对应的Class对象---");
Class<?> c4 = Class.forName("com.hg.java.Student");
System.out.println(c1 == c4);
}
}
3、Constructor
3.1Constructor概述
Constructor 类的核心概念:
Constructor 类(全限定名:java.lang.reflect.Constructor)是反射体系中专门用来描述类的构造器的类;
类的每个构造器(无参、有参、公有、私有)在反射中都会对应一个 Constructor 对象,这个对象就像构造器的 "操作手柄",通过它你可以在运行时创建类的实例,甚至调用原本无法直接访问的私有构造器。
简单来说:
Person 类的 public Person() 无参构造器 → 对应一个 Constructor 对象;
Person 类的 public Person(String name, int age) 有参构造器 → 对应另一个 Constructor 对象;
即使是 private Person(String name) 私有构造器,也能通过 Constructor 对象访问(解除限制后)。
3.2获取Constructor对象的方法
常用方法:
| 方法 | 说明 |
|---|---|
| Constructor<?>[ ] getConstructors() | 返回所有公共构造方法的数组 |
| Constructor<?>[ ] getDeclaredConstructors() | 返回所有构造方法的数组 |
| Constructor getConstructor(Class<?>... parameterTypes) | 返回单个公共构造方法对象 |
| Constructor getDeclaredConstructor(Class<?>...parameterTypes) | 返回单个构造方法对象 |
案例:
java
public class ConstructorTest {
public static void main(String[] args) throws ClassNotFoundException,
NoSuchMethodException {
Class<?> c = Class.forName("com.hg.java1.Student");
System.out.println("---返回所有构造方法的数组----");
Constructor<?>[] cons = c.getDeclaredConstructors();
for (Constructor con : cons) {
System.out.println(con);
}
System.out.println("-----返回单个构造方法----");
Constructor<?> con = c.getConstructor();
System.out.println(con);
con = c.getConstructor(String.class, int.class, String.class);
System.out.println(con);
}
}
3.3Constructor常用方法
常用方法:
| 方法 | 说明 |
|---|---|
| T newInstance(Object...initargs) | 根据指定的构造方法创建对象 |
案例:
java
public class ConstructorTest {
public static void main(String[] args) throws ClassNotFoundException,
NoSuchMethodException, IllegalAccessException,
InvocationTargetException, InstantiationException {
Class<?> c = Class.forName("com.hg.java1.Student");
System.out.println("------通过反射获取公共构造方法并创建对象--------");
Constructor<?> con = c.getConstructor();
Student s1 = (Student) con.newInstance();
System.out.println(s1);
con = c.getConstructor(String.class, int.class, String.class);
Object obj = con.newInstance("林青霞", 30, "西安");
System.out.println(obj);
}
}
4、Filed
4.1Filed概述
核心概念:
Field 类(全限定名:java.lang.reflect.Field)是反射体系中专门用来描述类的成员变量的类;
每个类的成员变量(不管是 public、private、static 还是实例变量),在反射中都会对应一个 Field 对象,这个对象就像成员变量的 "操作手柄"------ 通过它你可以在运行时读取、修改变量的值,甚至能操作原本无法直接访问的私有变量。
简单来说:
Person 类的 public int age → 对应一个 Field 对象;
Person 类的 private String name → 对应另一个 Field 对象;
即使是 static String version 静态变量,也能通过 Field 对象读写。
4.2获取Field对象的方法
常用方法:
| 方法 | 说明 |
|---|---|
| Field[ ] getFields() | 返回所有公共成员变量的数组 |
| Field[ ] getDeclaredFields() | 返回所有成员变量的数组 |
| Field getField(String name) | 返回单个公共成员变量 |
| Field getDeclaredField(String name) | 返回单个成员变量 |
案例:
java
public class FieldTest {
public static void main(String[] args) throws Exception {
Class<?> c = Class.forName("com.hg.java1.Student");
System.out.println("---------返回所有公共成员变量的数组----------");
Field[] fields = c.getFields();
for (Field field : fields) {
System.out.println(field);
}
System.out.println("---------返回所有成员变量的数组----------");
fields = c.getDeclaredFields();
for (Field field : fields) {
System.out.println(field);
}
System.out.println("---------返回单个公共成员变量----------");
Field addressField = c.getField("address");
System.out.println(addressField);
System.out.println("---------返回单个私有成员变量----------");
Field nameField = c.getDeclaredField("name");
System.out.println(nameField);
}
}
5、Method
5.1Method概述
核心概念:
Method 类(全限定名:java.lang.reflect.Method)是反射体系中专门用来描述类的方法的类
每个类的方法(不管是 public/private、实例方法 / 静态方法、有参 / 无参方法),在反射中都会对应一个 Method 对象 ------ 这个对象就像方法的 "操作手柄",通过它你能在运行时调用任意方法,哪怕是原本无法直接访问的私有方法。
简单来说:
Person 类的 public String getName() → 对应一个 Method 对象;
Person 类的 private void sayHello(String msg) → 对应另一个 Method 对象;
Math 类的 public static int max(int a, int b) → 也能通过 Method 对象调用。
5.2获取Method对象的方法
常用方法:
| 方法 | 说明 |
|---|---|
| Method[ ] getMethods() | 返回所有公共成员方法的数组 |
| Method[ ] getDeclaredMethods() | 返回所有成员方法的数组 |
| Method getMethod(String name, Class<?>... parameterTypes) | 返回单个公共成员方法 |
| Method getDeclaredMethod(String name, Class<?>... parameterTypes) | 返回单个成员方法 |
案例:
java
public class MethodTest {
public static void main(String[] args) throws Exception {
Class<?> c = Class.forName("com.hg.java1.Student");
System.out.println("-----------返回所有公共成员方法的数组--------");
Method[] methods = c.getMethods();
for (Method method : methods) {
System.out.println(method);
}
System.out.println("-----------返回所有成员方法的数组--------");
methods = c.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method);
}
System.out.println("-----------返回单个公共成员方法--------");
Method method = c.getMethod("method1");
System.out.println(method);
Method method2 = c.getMethod("method2", String.class);
System.out.println(method2);
Method method3 = c.getMethod("method3", String.class, int.class);
System.out.println(method3);
System.out.println("-----------返回单个非公共成员方法--------");
Method method4 = c.getDeclaredMethod("function");
System.out.println(method4);
}
}
5.3Method常用方法
常用方法:
| 方法 | 说明 |
|---|---|
| Object invoke(Object obj,Object... args) | 调用obj对象的成员方法,参数是args,返回值是Object类型 |
案例:
java
package com.hg.java1;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class MethodTest {
public static void main(String[] args) throws Exception {
Class<?> c = Class.forName("com.hg.java1.Student");
Constructor<?> con = c.getConstructor();
Object obj = con.newInstance();
System.out.println("-----------调用成员方法--------");
Method method = c.getMethod("method1");
Method method2 = c.getMethod("method2", String.class);
Method method3 = c.getMethod("method3", String.class, int.class);
Method method4 = c.getDeclaredMethod("function");
method.invoke(obj);
method2.invoke(obj, "林青霞");
Object o = method3.invoke(obj, "林青霞", 30);
System.out.println(o);
method4.setAccessible(true);
method4.invoke(obj);
}
}
6、Annotation
6.1Annotation概述
核心概念:
Annotation(全限定名 java.lang.annotation.Annotation)是反射体系中专门用来描述类的注解的类;
每个加在类 / 方法 / 属性上的注解,在反射中都会对应一个 Annotation对象 ------ 这个对象就像注解的 "操作手柄",通过它你能在运行时读取注解的所有属性值,判断某个元素是否被该注解标记。
简单来说:
加在 Person 类上的 @MyAnnotation(value="张三") → 对应一个 MyAnnotation 实例;
反射的核心就是判断注解是否存在,进而获取 value="张三" 这类属性。
6.2获取Annotation对象的方法
常用方法:
| 方法 | 说明 |
|---|---|
| Annotation[ ] getAnnotations() | 返回直接存在于此元素上的所有注解数组 |
| Annotation[ ] getDeclaredAnnotations() | 返回存在于此元素上的所有注解数组 |
| Annotation getAnnotation(Class<?>... annotationClass) | 返回直接存在于此元素上的单个注解 |
| Annotation getDeclaredAnnotation(Class<?>... annotationClass) | 返回存在于此元素上的单个注解 |
| isAnnotationPresent(Class<A> annoClass) | 判断当前元素(类 / 方法 / 字段)是否加了指定注解 |
案例:
java
public class AnnotationTest {
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("com.hg.java1.SampleClass");
System.out.println("----------返回存在于此类上的所有注解数组---------");
Annotation[] annotations = clazz.getAnnotations();
for(Annotation annotation : annotations){
if(annotation instanceof CustomAnnotation){
CustomAnnotation customAnnotation = (CustomAnnotation) annotation;
System.out.println("name: " + customAnnotation.name());
System.out.println("value: " + customAnnotation.value());
}
}
System.out.println("----------返回存在于此类上的单个注解---------");
if (clazz.isAnnotationPresent(MyAnnotation.class)) {
CustomAnnotation customAnnotation =
clazz.getAnnotation(CustomAnnotation.class);
System.out.println("name: " + customAnnotation.name());
System.out.println("value: " + customAnnotation.value());
}
System.out.println("----------返回存在于此属性上的所有注解数组---------");
Field field = clazz.getDeclaredField("sampleField");
annotations = field.getAnnotations();
for(Annotation annotation : annotations){
if(annotation instanceof CustomAnnotation){
customAnnotation = (CustomAnnotation) annotation;
System.out.println("name: " + customAnnotation.name());
System.out.println("value: " + customAnnotation.value());
}
}
System.out.println("----------返回存在于此元素上的单个注解---------");
if (field.isAnnotationPresent(MyAnnotation.class)) {
customAnnotation = field.getAnnotation(CustomAnnotation.class);
System.out.println("name: " + customAnnotation.name());
System.out.println("value: " + customAnnotation.value());
}
System.out.println("----------返回存在于此方法上的所有注解---------");
Method method = clazz.getMethod("getSampleField");
annotations = method.getAnnotations();
for(Annotation annotation : annotations){
if(annotation instanceof CustomAnnotation){
customAnnotation = (CustomAnnotation) annotation;
System.out.println("name: " + customAnnotation.name());
System.out.println("value: " + customAnnotation.value());
}
}
System.out.println("----------返回存在于此方法上的单个注解---------");
if (method.isAnnotationPresent(MyAnnotation.class)) {
customAnnotation = method.getAnnotation(CustomAnnotation.class);
System.out.println("name: " + customAnnotation.name());
System.out.println("value: " + customAnnotation.value());
}
}
}
@CustomAnnotation(name="SampleClass", value = "Sample Class Annotation")
class SampleClass {
@CustomAnnotation
private String sampleField;
@CustomAnnotation(name="getSampleMethod", value = "Sample Method Annotation")
public String getSampleField() {
return sampleField;
}
public void setSampleField(String sampleField) {
this.sampleField = sampleField;
}
}
//注解必须标注 @Retention(RetentionPolicy.RUNTIME),否则反射完全读不到
@Retention(RetentionPolicy.RUNTIME)
@interface CustomAnnotation {
public String name() default "这是name";
public String value() default "这是value";
}