JAVA-反射篇

本文详细介绍了Java反射机制,包括反射的概念、用途以及如何使用反射进行类操作,如获取类信息、创建对象、访问属性和方法、处理注解等。通过反射,开发者可以在运行时动态地操作类和对象,实现强大的功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、反射是什么?

反射 (reflect)、在javav的java.lang.reflect包下,反射是java为我们提供的一种操作字节码文件的类库。

二、反射的用处?

通过反射机制可以动态的在程序运行时获取字节码文件(.class文件),并且针对字节码文件进行读取、修改等操作,实现动态的操作类,反射也是OOP原则的重要实现方式。大多数框架中都应用了反射,例如SSM三大框架等,

三、如何使用反射

如果要使用反射,首先需要知道反射中重要的类有那些。以及如何通过反射获取Class文件。
!!!!本文章只展示常用的基本的方法,其他方法请查看javaAPI文档
!!!!以下示例未包含获取匿名内部类的方法和枚举的方法,他日再补充

0. 反射判断类型

首先判断文件的类型(可能有些鸡肋)你也可以不用。

 Class c = Class.forName("java.util.Map");
          c.isInterface();//判断文件是否为 接口 类型
          c.isAnnotation();//判断文件是否为 注解 类型
          c.isEnum();//判断文件是否为 枚举 类型
          //....

1. 反射相关类

相关类作用
java.lang.class字节码类 ,代表了整体的字节码文件
java.reflect.Constructor字节码中的构造方法的字节码 ,代表了字节码中的构造方法
java.reflect.Field字节码中的属性的字节码,代表了属性
java.reflect.Method字节码中的方法的字节码,代表类中的方法

2.通过反射获取类三种方式

第一种:

通过java.lang.class包下的静态方法: **forName(String s)**获取,
优点: 这种方法比较通用,可以获取绝大多的class对象,只要能读到路径就能获取。
缺点: 就是不能读取到类路径之外的

java方法:

    public static Class<?> forName(String className)
                throws ClassNotFoundException{
                //........
}

使用示例:

Class<?> s = Class.forName("java.long.String");//获取String类的class对象

关于路径:
有时我们需要保证类在多种环境下的路径中也能被正确的找到,所以我们需要一种通用的方法,这种方法可以获取并且只能获取类路径(即:src目录为类路径根路径)下的类文件。

方法:

String path = Thread.currentThread().getContextClassLoader()
	.getResource("全限定路径.后缀") //从根开始例如:com/ccnn/resource/a.properties 获取类时后缀为.class
	.getPath();
	//Thread.currentThread() ---->获取当前线程对象
	//getContextClassLoader() ---->获取线程对象的类加载器对象
	//getResource("文件名.后缀") ---->类加载器默认从当前根路径下作为起点加载资源
	//getPath(); ---->获取路径

//直接以流的形式返回
InputStream inputStream=  Thread.currentThread().getContextClassLoader().getResourceAsStream("全限定路径.后缀"); //直接以流的形式返回

path 即为获取到的类的 绝对 路径。

小知识点:
在执行Class.forName("java.long.String");时会进行类加载,而静态代码块只会在类加载时执行,并且只会执行一次,

第二种:

在java中任何一个对象都拥有 getClass() 方法 通过对象 .getClass() 就能获取到类的Class字节码对象。

java方法:

 public final native Class<?> getClass();
 //所有类都默认继承了Object超类,也就默认继承了此方法。

使用示例:

Date time = new Date();
Class<?> c = time.getClass();//获取Date类的class对象

第三种:

在java中任何一个“数据类型”都拥有 Class 属性 通过对象 .Class 就能获取到数据类型的 Class字节码对象。

使用示例:

 Class<?> c = int.class;//获取int的class对象

3.通过Class字节码对象操作字节码文件

3.1 使用Class字节码对象实例化对象

使用Class字节码对象实例化类比直接 new 类要更加灵活,比如:通过读取配置文件中的字符串,可以动态的实例化配置文件中字符串所指的对象,修改配置文件就能达到实例化任意对象的功能。完美体现了OOP原则,即:对修改关闭,对扩展开放
方法:

MyClass myClass = (MyClass) Class.forName("MyClass").newInstance();

3.2 反射获取类的修饰符

int codename = Class.forName("user").getModifiers();
        String modifierName = Modifier.toString(codename);
        System.out.println(modifierName);

3.3反射获取类名

String className = Class.forName("user").getName();
        System.out.println(className);//user

3.4反射获取类的属性

3.4.1获取属性名
获取所有public修饰的属性名
  Field[] field = Class.forName("user").getFields();//获取所有public修饰的属性
        for (Field f :field){
            System.out.println(f.getName());
        }

获取某个public修饰的属性名
Field field = Class.forName("user").getField("name"); //获取某个public修饰的属性
        System.out.println(field.getName());
获取任意修饰符所有属性名
Field[] field = Class.forName("user").getDeclaredFields();
        for (Field f :field){
            System.out.println(f.getName());
        }

获取指定名称的任意修饰符的属性名
Field field = Class.forName("user").getDeclaredField("age");
        System.out.println(field.getName());
3.4.2获取属性的数据类型
Field field = Class.forName("user").getDeclaredField("name");
        System.out.println(field.getType());
3.4.3获取属性修饰符
 Field field = Class.forName("user").getDeclaredField("name");
        int codename = field.getModifiers(); //得到修饰符的代号
        String modifierName = Modifier.toString(codename); //获取代号所指的修饰符
        System.out.println(modifierName);

       
3.4.4获取和修改属性值
Class c = Class.forName("user"); //获取某个public修饰的属性
        user user = (user)c.newInstance(); //通过反射实例化对象
        Field field = c.getDeclaredField("name"); //获取某个属性
        field.get(user); //获取属性值
        //访问私有的属性需要在执行set()方法之前打破封装
        //field.setAccessible(true);
        field.set(user,"李四"); //修改值
        System.out.println(user.getName()); //李四

3.5反射获取类的方法

3.5.0获取方法对象
 Class c = Class.forName("user");
        c.getMethods();//获取所有public修饰的方法,包括继承的。
        c.getDeclaredMethods();//获取所有修饰符修饰的所有的方法,不包括继承的
        /*在获取指定方法对象时分为三种情况*/
        //1.无参的
        c.getMethod("getAge");
        //2.有参数的
        c.getMethod("getAbc", String.class);//
        //3.可以重载的方法,重载方法之间使用参数区分
        c.getMethod("getAbc", String.class,int.class,boolean.class);
3.5.1获取方法修饰符
// Class.forName("user").getDeclaredMethods(); //获取所有的方法对象
       Method method =  Class.forName("user").getMethod("getAge");//获取指定的方法对象
        int i = method.getModifiers(); //和获取属性修饰符一样都是调用“getModifiers()”方法,但是这两个并不是同一个类的方法
        String mod = Modifier.toString(i);
        System.out.println(mod); //public
3.5.2获取方法修返回值类型
Method method = Class.forName("user").getMethod("getA");
        Class type = method.getReturnType(); //获取返回值类型
        String name =type.getName();
        System.out.println(name);
3.5.2获取方法名
Method method = Class.forName("user").getMethod("getA");
        String methodName =  method.getName();//获取方法名
        System.out.println(methodName);
3.5.3获取方法名形式参数列表
 Method method = Class.forName("user").getMethod("getA");

        Parameter[] parameters = method.getParameters();//获取所有的形式参数
        for (Parameter parameter :parameters){
            //boolean result = parameter.isAnnotationPresent(NotNull.class);//某个注解是否存在
            // parameter.getAnnotation(NotNull.class);//获取某个注解
            //....获取注解的方法很多不一一列举请看**注解篇**
            Type type =parameter.getParameterizedType();//获取形式参数类型
            System.out.println(type.getTypeName());
        }

        //或

        Class[] types =  method.getParameterTypes();
        for (Class c : types){
           String name =  c.getSimpleName();//
            System.out.println(name);
        }

3.5.4获取方法抛出的异常
 Method method = Class.forName("user").getMethod("getAge");
        Class[] exceptions = method.getExceptionTypes();//获取方法抛出的所有异常
        for (Class exceptionClass : exceptions){
            String exceptionName = exceptionClass.getSimpleName();
            System.out.println(exceptionName);
        }
3.5.5获取方法体的内容
//待补充
3.5.5反射构造方法
 Class c = Class.forName("user");
        c.getConstructors(); //获取无参构造方法且是public修饰的
        c.getDeclaredConstructor(int.class,String.class); //获取指定参数的所有构造方法
        c.getDeclaredConstructors(); //获取所有构造方法
        //获取构造方法的修饰符、返回值、参数列表等 和以上方式相同。
3.5.6调用方法
 Class c = Class.forName("user");
 		/*创建对象*/
        Object obj = c.newInstance();
        /*获取符合条件的方法*/
        Method method = c.getMethod("getAge",String.class);
        /*调用Obj方法,传入参数*/
        method.invoke(obj,"参数值");//调用方法

4获取类的父类

 Class c = Class.forName("user");
        /*
        如果这个类表示Object类、接口、原始类型或void、则返回null。
         */
        c.getSuperclass();//获取父类

5获取类的接口

  Class c = Class.forName("user");
        /*
        1.如果该对象是一个类,则返回该类实现的所有接口的对象,
        2.如果该对象是一个接口,则返回接口扩展的所有接口的对象
        3.如果此对象是一个不实现接口的类或接口,则该方法返回长度为0的数组
        */
       Class[] classes = c.getInterfaces();
       c.getAnnotatedInterfaces(); //返回带注解接口
        /*
           1.如果该对象是一个类,则返回直接实现的接口的对象
           2.如果该对象是一个接口,则返回接口直接扩展的接口的对象
           3.如果该对象是一个不实现接口的类或接口,则该方法返回长度为0的数组
        */
       c.getGenericInterfaces();

6获取注解

6.1获取类或者接口的注解
Class c = Class.forName("user");
		c.getAnnotatedInterfaces();//获取带注解的接口
        c.getAnnotation(NotNull.class);//如果有这个注解则返回该注解,否则返回null指定类型的注解
        c.getAnnotations(); //返回此元素上存在的注解
        c.getAnnotatedSuperclass();//获取父类的注解
        c.getAnnotationsByType(AnnotatedElement.class);//获取类上直接的某个类型的注解
        c.getDeclaredAnnotations();//直接存在于此元素上的注解。 此方法忽略继承的注解
        c.getDeclaredAnnotation(NotNull.class);//如果这样的注解在类上直接存在,则返回指定类型的元素注解,否则返回null。此方法忽略继承的注解。
        c.getDeclaredAnnotationsByType(NotNull.class);//如果此类注解直接存在或间接存在,则返回该元素的注解(指定类型)。 此方法忽略继承的注解.   
6.2获取属性的注解
   Class c = Class.forName("user");
        Field field = c.getDeclaredField("name");
        field.isAnnotationPresent(NotNull.class);//如果此元素上存在指定类型的注解,则返回true,否则返回false。
        field.getAnnotation(NotNull.class);//如果该元素存在这样的注解则返回该注解,否则返回null指定类型的注解。
        field.getAnnotations();//返回此元素上存在的注解
        field.getDeclaredAnnotation(NotNull.class);//如果这样的注解直接存在,则返回指定类型的元素注解,否则返回null
        field.getDeclaredAnnotations();//返回直接存在于此元素上的注解
6.3获取有关于普通方法和构造的注解
 Class c = Class.forName("user");
        Method method =  c.getMethod("getA", String.class);
        method.isAnnotationPresent(NotNull.class);//如果此元素上存在指定类型的注解,则返回true,否则返回false
        method.getAnnotation(NotNull.class);//返回该元素的存在如果这样的注解则返回该注解,否则返回null指定类型的注解。
        method.getAnnotations();//返回此元素上存在的注解。
        method.getAnnotatedReturnType();//表示使用类型来指定此可执行文件所表示的方法/构造函数的返回类型。
        method.getDeclaredAnnotations();//返回 直接存在于此元素上的注解。
        method.getDeclaredAnnotation(NotNull.class);//如果这样的注解直接存在,则返回指定类型的元素注解,否则返回null。
        method.getDeclaredAnnotationsByType(NotNull.class);//如果此类注解直接存在或间接存在,则返回该元素的注解(指定类型)。此方法忽略继承的注解。如果在该元素上没有直接或间接存在的指定注解,则返回值为长度为0.的数组
        method.getParameterAnnotations();//按照顺序返回形式参数列表的注解 显式的和隐式的

暂未完结~
欢迎指正,欢迎补充

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值