Java反射、注解

本文详细介绍了Java反射机制,包括如何访问构造函数、成员变量和方法,并探讨了注解的使用,如@Target和@Retention。反射与注解结合,能增强代码的灵活性,常用于框架开发。

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

最近本着不求甚解的态度重温了一下主流框架的源码,所以趁热打铁的总结一下,学习框架或开发框架所必备的基础知识:

一、反射

1.1、简介

本文简单总结一下Java反射和注解,反射可以算是必备条件了,基本学习的主流框架中都会看到反射的身影,他的灵活使用也为很多逻辑的扩展提供了可能,通过Java的反射机制,可以在程序中访问已经加载到JVM中的Java对象的描述,实现访问、检测、修复和修改描述Java本身对象的功能,Java中的java.lang.reflect包提供使用注解功能。

Java中的所有类均即成了Object类,在Object类中定义了getClass方法,该方法返回一个Class的对象:

Class c = object.getClass();

利用返回的Class,即可访问Class描述信息,如:属性、方法‘构造函数等;

1.2、访问构造函数

  • Java提供了一下通过反射获取构造函数的方法:
  1. getConstructors():获取权限位Public的构造函数
  2. getConstructors(Class<?> … parameterTypes):获取权限为public且指定参数类型的构造函数
  3. getDeclaredConstructors():按照声明顺序返回所有构造函数,包private类型
  4. getDeclaredConstructors(Class<?> … parameterTypes):获取指定参数类型的构造函数
  • 针对Constructor常用的方法:
  1. isVarArgs():是否允许可变数量参数,返回boolean ,true表示有,false表示没有
  2. getParameterTypes():按照声明的顺序返回参数类型
  3. getExceptionTypes():返回抛出异常的类型
  4. newInstance():根据传入的参数调用构造函数创建实例
  5. setAccessible():默认不允许反射privite修饰的方法和属性,但如果先执行并设置为true,则可以反射
  6. getModifiers():获得可以解析出方法修饰符的整数
  • Modifier常用的解析方法

  1. isPublic(int mode):是否为Public修饰符
  2. isProtected(int mode):是否为Protected修饰符
  3. isPrivate(int mode):是否为Private修饰符
  4. isStatic(int mode):是否为Static修饰符
  5. isFinal(int mode):是否为Final修饰符
  6. toString(int mode):以字符串返回修饰符
  • 实例:
  1. 创建实例ConstructExample
public class ConstructorExample {

   int number;
   public String name;
   protected float aFloat;
   private ConstructorExample() {
   }

   protected ConstructorExample(int number) {
      this.number = number;
   }

   public ConstructorExample(String name, int number) throws NumberFormatException {
      this.number = number;
      this.name = name;
   }

   public void prinln() {
      System.out.println("name = " + name);
      System.out.println("number = " + number);
   }
}

   2、反射获取构造函数信息

<think>我们有一个用户查询,要求了解Java反射注解的使用方法或实现原理。用户特别提到了“使用教程”或“实现原理”,因此我们的回答需要覆盖这两方面。根据提供的引用,我们可以总结出以下关键点:1.引用[1]提到反射的方式:实例化对象、通过getClass方法、得到包等。但文本不完整,我们可以参考其他引用。2.引用[2]强调注解在日常开发中使用多,反射较少,但框架底层大量使用。同时提到注解反射是基本功,面试常问。3.引用[3]的目录结构提供了注解反射的详细大纲:包括注解的概念、内置注解、元注解、自定义注解反射的概念、动态语言与静态语言、Java反射机制、反射API、Class类、类加载过程、类加载器、运行时类的结构、泛型信息以及操作注解。4.引用[4]提到“反射操作注解”,这也是一个重要的应用。因此,我们组织回答的结构如下:1.先简要介绍反射注解的概念及其重要性。2.分别讲解反射的使用方法和原理。-反射的使用:包括获取Class对象的三种方式、通过反射获取构造方法并创建对象、获取字段和方法、调用方法等。-反射的原理:涉及JVM的类加载机制、Class对象、方法区等。3.然后讲解注解的使用方法和原理。-注解的使用:内置注解(如@Override)、元注解(如@Target)、自定义注解注解的解析(反射或编译时处理)。-注解的原理:注解本质上是接口,而注解信息的存储和读取由JVM实现。4.最后,结合反射注解:如何通过反射获取注解信息并利用。注意:使用教程部分需要代码示例,而原理部分需要解释机制。由于用户要求使用中文,我们使用中文回答。另外,我们还需要生成相关问题。下面开始编写回答。</think> ### Java反射注解的使用与原理 #### **一、反射的使用方法** 1. **核心API** - **获取Class对象**(三种方式): ```java Class<?> clazz1 = Class.forName("java.lang.String"); // 类全路径 Class<?> clazz2 = String.class; // 类字面量 Class<?> clazz3 = "".getClass(); // 对象.getClass() ``` - **操作类成员**: ```java // 获取构造方法并实例化 Constructor<?> cons = clazz1.getConstructor(String.class); Object obj = cons.newInstance("Hello"); // 调用方法 Method method = clazz1.getMethod("length"); int length = (int) method.invoke(obj); // 返回字符串长度 // 访问字段 Field field = clazz1.getDeclaredField("value"); field.setAccessible(true); // 打破私有限制 char[] chars = (char[]) field.get(obj); ``` 2. **应用场景** - 动态加载类(如插件化开发) - 框架底层(如Spring的IoC容器通过反射创建Bean) - 调试工具(查看运行时对象结构) --- #### **二、注解的使用方法** 1. **内置常用注解** | 注解 | 作用 | |---------------|-------------------------------| | `@Override` | 标记方法重写父类/接口方法 | | `@Deprecated` | 标记已过时方法/类 | | `@SuppressWarnings` | 抑制编译器警告 | 2. **自定义注解** ```java @Target(ElementType.METHOD) // 仅用于方法 @Retention(RetentionPolicy.RUNTIME) // 运行时保留 public @interface MyAnnotation { String value() default ""; // 带默认值的属性 int priority() default 0; } ``` - `@Target`:定义注解作用目标(类、方法、字段等) - `@Retention`:定义注解生命周期(源码、编译、运行时) 3. **注解解析(结合反射)** ```java Method method = obj.getClass().getMethod("myMethod"); if (method.isAnnotationPresent(MyAnnotation.class)) { MyAnnotation anno = method.getAnnotation(MyAnnotation.class); System.out.println("Priority: " + anno.priority()); } ``` --- #### **三、反射注解的实现原理** 1. **反射原理** - JVM在类加载时生成`Class`对象(位于方法区) - Class对象包含类元数据:字段、方法、构造器等指针 - 反射调用本质是通过`Class`对象访问这些元数据 - **性能开销**:绕过了编译器优化,需安全检查(可通过`setAccessible(true)`减少开销)[^3] 2. **注解原理** - 注解本质是继承`Annotation`的接口 - 编译器为注解生成代理类(如`$Proxy1`) - 运行时通过动态代理解析注解属性 - 注解信息存储在类文件的`RuntimeVisibleAnnotations`属性中 3. **关键内存结构** ```mermaid graph LR A[Java源文件] --编译--> B[字节码文件] B --类加载--> C[方法区] C --> D[Class对象] D --> E[字段/方法/构造器指针] D --> F[注解存储区] ``` --- #### **四、反射操作注解的典型应用** 1. **ORM框架映射** ```java @Table("user") // 自定义注解 public class User { @Column("id") private int userId; public static void main(String[] args) { Table tableAnno = User.class.getAnnotation(Table.class); String tableName = tableAnno.value(); // 获取表名"user" // 通过反射读取字段注解生成SQL } } ``` 2. **注解处理器** - **编译时处理**(如Lombok):继承`AbstractProcessor`修改AST - **运行时处理**:结合反射动态改变行为(如权限检查) --- ### 相关问题 1. 为什么反射会降低性能?有哪些优化反射调用的方法? 2. 如何在编译时处理注解(如Lombok原理)? 3. 如何利用注解实现简单的AOP功能(如权限校验)? 4. `@Retention(RetentionPolicy.SOURCE)`和`RUNTIME`的应用场景有什么区别? [^1]: Java注解反射的核心机制 [^2]: 框架对反射注解的依赖场景 [^3]: JVM类加载与反射的底层交互过程 [^4]: 反射注解在实际工程中的取舍
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值