1525 字
4 分钟
Java 注解与反射

JDBC#

Java Database Connectivity

用于连接和操作关系型数据库的 Java API。它提供了一组接口和类,使 Java 应用程序能够与各种数据库进行交互。

访问步骤#

  1. 加载数据库驱动

  2. 建立连接 DriverManager.getConnection()

  3. 创建连接对象

  4. 创建语句对象

  5. 执行sql语句获取执行结果

  6. 关闭连接(先开后关)

连接池#

预先创建好的多个数据库连接对象,节省每次new连接对象的开销。

注解#

概念#

注解(Annotation):贴在代码上的“标签”,可以被编译器、框架或工具读取的特殊备注。

  • 格式:@注解名
  • 作用范围packageclassmethodfield
  • 访问可以通过反射机制对这些元数据访问

内置注解#

包:java.lang

注解作用使用位置是否保留到运行时
@Override表示当前方法重写了父类的方法。如果父类没有这个方法,编译会报错。方法上否(只在编译期有效)
@Deprecated表示某个类、方法或字段已过时,不推荐使用。使用时编译器会警告你。类 / 方法 / 字段是(保留到运行时)
@SuppressWarnings抑制编译器警告。比如你用了不安全的泛型操作,可以用它关掉警告。类 / 方法 / 字段 / 局部变量
@FunctionalInterface表示这是一个函数式接口(只能有一个抽象方法)。如果不是,编译报错。接口上
@SafeVarargs用于可变参数方法,告诉编译器“我知道有泛型风险,但我保证安全”,从而消除警告。方法 / 构造器

@SuppressWarnings参数

参数值作用说明
"unchecked"忽略泛型未检查转换警告(如 List list = new ArrayList();
"deprecation"忽略使用了 @Deprecated 过时代码的警告
"rawtypes"忽略使用原始类型(如 List 而不是 List<String>
"unused"忽略未使用的变量、方法、参数等
"fallthrough"忽略 switch 中 case 穿透(无 break)警告
"serial"忽略可序列化类缺少 serialVersionUID 的警告
"all"idea自带,不推荐

元注解#

包:java.lang.annotation

@Retention#

作用:指定注解保留到哪个阶段。

参数类型RetentionPolicy

参数值含义是否可通过反射获取
RetentionPolicy.SOURCE只在源代码中存在,编译时丢弃不能
RetentionPolicy.CLASS编译后保留在 .class 文件中,但 JVM 不加载不能(默认值)
RetentionPolicy.RUNTIME保留在运行时,JVM 加载后可用能(常用)

@Target#

作用:限制注解能标注在哪些程序元素上。

参数类型ElementType[](数组,可写多个)

参数值可标注的位置
ElementType.TYPE类、接口、注解、枚举
ElementType.FIELD字段(成员变量)
ElementType.METHOD方法
ElementType.PARAMETER方法参数
ElementType.CONSTRUCTOR构造方法
ElementType.LOCAL_VARIABLE局部变量
ElementType.ANNOTATION_TYPE注解类型本身(用于元注解)
ElementType.PACKAGE包(需配合 package-info.java 使用)
ElementType.TYPE_PARAMETER类型参数(Java 8+,如 class MyClass<T> 中的 T
ElementType.TYPE_USE任何类型使用处(Java 8+,如 List<@My String>

示例:@Target({ElementType.METHOD, ElementType.FIELD})


@Documented#

作用:是否在生成 JavaDoc 时包含该注解。

参数无参数(标记型注解)


@Inherited#

作用:父类的注解是否被子类继承(仅对类有效)。

参数无参数(标记型注解)


@Repeatable#

作用:允许同一个地方多次使用同一个注解。

参数value(必须指定一个“容器注解”的 class)

参数名类型说明
valueClass<? extends Annotation>指定一个“容器注解”,用于存放重复的注解

自定义注解#

  • 1个参数,名为value,使用注解可以不给参数名
  • default参数默认值:不显式声明时使用
@元注解
public @interface 注解名{
//注解参数:
类型 参数名() default 默认值;
}

反射#

概念#

  • 静态语言:运行时代码能改变自身结构(Java、C、C++)
  • 动态语言:运行时代码不能改变自身结构(C#、JavaScript、Python)
  • 反射:程序运行期间,动态获取类的结构信息(类名、构造器、方法、字段、注解等),并对其进行操作(创建对象、调用方法、访问字段)。
  • Java:通过反射机制成为准动态语言

Class#

包:java.lang.Classjava.lang.reflect

  • 动态获取类的结构信息通过Class类
  • Class 本身也是一个类
  • Class 对象只能由系统建立对象
  • 一个加载的类在 JVM 中只会有一个 Class 实例
  • 一个 Class 对象对应的是一个加载到 JVM 中的一个 class 文件
  • 每个类的实例都会记得自己是由哪个 Class 实例所生成
  • 通过 Class 可以完整地得到一个类中的所有被加载的结构
  • Class 类是 Reflection 的根源,针对任何你想动态加载、运行的类,唯有先获得相应的 Class 对象

四种方式获取:

// 1. 通过类名(最常用,最灵活)
Class<?> c1 = Class.forName("com.example.User");
// 2. 通过类.class(编译期已知)
Class<User> c2 = User.class;
// 3. 通过对象.getClass()
User u = new User();
Class<? extends User> c3 = u.getClass();
// 4. 包装类通过TYPE属性
Class c4 = Integer.TYPE;

方式返回类型类型是否已知是否触发类初始化使用场景注意事项
Class.forName()Class<?>运行时才知道执行 static 块动态加载、配置文件、框架反射必须类在 classpath;要写全限定名;可能抛 ClassNotFoundException
类名.classClass<User>编译期已知不会触发编译时确定的类;泛型安全最安全高效;不能用于动态类名
对象.getClass()Class<? extends User>运行时真实类型类必须已加载多态场景;获取实际类型返回的是实际类型,可能是子类
包装类 .TYPEClass<Integer>已知不触发获取基本类型对应的 ClassInteger.TYPE == int.class,不是 Integer.class

常用方法#

获取类信息

c1.getName(); // 全限定名
c1.getSimpleName(); // 类名
c1.getSuperclass(); // 父类
c1.getInterfaces(); // 接口
c1.getAnnotations(); // 注解

示例

class User {
private String name;
private User(String name) {
this.name = name;
}
private void hello() {
System.out.println("Hello " + name);
}
}
// 反射使用
Class<?> clazz = Class.forName("User");
// 创建对象
Constructor<?> con = clazz.getDeclaredConstructor(String.class);
con.setAccessible(true);
Object obj = con.newInstance("Tom");
// 调用方法
Method m = clazz.getDeclaredMethod("hello");
m.setAccessible(true);
m.invoke(obj);

优缺点#

  1. 高度灵活,解耦严重依赖

  2. 支持运行时扩展

  3. 是大型框架的基础

  4. 性能较低(绕过编译期优化)

  5. 破坏封装性

  6. 编译期无法检查错误

  7. 代码可读性、可维护性下降

结论: 业务代码慎用,框架代码必用


对比#

对比项new反射
编译期检查
性能
灵活性
是否依赖类名字符串

分享

如果这篇文章对你有帮助,欢迎分享给更多人!

Java 注解与反射
https://oddpalmer.space/posts/注解与反射/注解与反射/
作者
Oddpalmer
发布于
2026-01-22
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时