JavaSE(十三)

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)是反射体系中专门用来描述类的成员变量的类;

每个类的成员变量(不管是 publicprivatestatic 还是实例变量),在反射中都会对应一个 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";
}
相关推荐
heartbeat..6 小时前
Redis 中的锁:核心实现、类型与最佳实践
java·数据库·redis·缓存·并发
6 小时前
java关于内部类
java·开发语言
好好沉淀6 小时前
Java 项目中的 .idea 与 target 文件夹
java·开发语言·intellij-idea
gusijin6 小时前
解决idea启动报错java: OutOfMemoryError: insufficient memory
java·ide·intellij-idea
To Be Clean Coder6 小时前
【Spring源码】createBean如何寻找构造器(二)——单参数构造器的场景
java·后端·spring
lsx2024066 小时前
FastAPI 交互式 API 文档
开发语言
吨~吨~吨~6 小时前
解决 IntelliJ IDEA 运行时“命令行过长”问题:使用 JAR
java·ide·intellij-idea
你才是臭弟弟6 小时前
SpringBoot 集成MinIo(根据上传文件.后缀自动归类)
java·spring boot·后端
短剑重铸之日6 小时前
《设计模式》第二篇:单例模式
java·单例模式·设计模式·懒汉式·恶汉式
VCR__6 小时前
python第三次作业
开发语言·python