Appearance
注解
注解(Annotation)是 Java 5 引入的一种元数据形式,可以在代码中添加信息,用于标记类、方法、字段等元素。
注解概述
什么是注解
text
┌─────────────────────────────────────────────────────────────────┐
│ 注解概述 │
├─────────────────────────────────────────────────────────────────┤
│ 注解是一种特殊的接口,以 @ 开头 │
│ │
│ 注解的作用: │
│ 1. 编译检查:如 @Override 检查方法重写 │
│ 2. 代码分析:通过反射获取注解信息 │
│ 3. 生成文档:如 @param、@return │
│ 4. 运行时处理:框架通过注解实现功能 │
│ │
│ 注解 vs 注释: │
│ - 注释:给人看的,编译后忽略 │
│ - 注解:给程序看的,编译后保留 │
└─────────────────────────────────────────────────────────────────┘注解语法
java
// 注解的基本语法
@AnnotationName
public class MyClass {
@AnnotationName(parameter = "value")
public void method() {
}
@AnnotationName(param1 = "value1", param2 = "value2")
public void anotherMethod() {
}
// 无参数时可以省略括号
@Override
public String toString() {
return "MyClass";
}
}内置注解
@Override
java
public class OverrideDemo {
public static void main(String[] args) {
Child child = new Child();
child.show();
}
}
class Parent {
public void show() {
System.out.println("Parent show");
}
}
class Child extends Parent {
// @Override:标记方法重写,编译器检查是否正确重写
@Override
public void show() {
System.out.println("Child show");
}
// 如果方法名拼写错误,编译器会报错
// @Override
// public void shows() { } // 编译错误:方法未重写
}@Deprecated
java
public class DeprecatedDemo {
public static void main(String[] args) {
OldClass old = new OldClass();
// 使用 @Deprecated 标记的方法会产生警告
old.oldMethod(); // 警告:已过时
old.newMethod(); // 正常使用
}
}
class OldClass {
// @Deprecated:标记已过时的元素
@Deprecated(since = "2.0", forRemoval = false)
public void oldMethod() {
System.out.println("旧方法,不建议使用");
}
public void newMethod() {
System.out.println("新方法,推荐使用");
}
}@SuppressWarnings
java
import java.util.*;
public class SuppressWarningsDemo {
// @SuppressWarnings:抑制编译器警告
@SuppressWarnings({"unchecked", "deprecation"})
public static void main(String[] args) {
// 原始类型警告
List list = new ArrayList();
list.add("Hello");
// 使用过时方法
OldClass old = new OldClass();
old.oldMethod();
}
// 抑制未使用警告
@SuppressWarnings("unused")
public void unusedMethod() {
String unusedVariable = "未使用的变量";
}
}@FunctionalInterface
java
// @FunctionalInterface:标记函数式接口(只有一个抽象方法)
@FunctionalInterface
interface Calculator {
int calculate(int a, int b);
// 可以有默认方法
default void print() {
System.out.println("Calculator");
}
// 可以有静态方法
static Calculator add() {
return (a, b) -> a + b;
}
// 只能有一个抽象方法
// int anotherMethod(); // 编译错误
}
public class FunctionalInterfaceDemo {
public static void main(String[] args) {
Calculator add = (a, b) -> a + b;
System.out.println("10 + 5 = " + add.calculate(10, 5));
Calculator multiply = (a, b) -> a * b;
System.out.println("10 * 5 = " + multiply.calculate(10, 5));
}
}元注解
元注解是用于定义注解的注解。
@Target
java
import java.lang.annotation.*;
// @Target:指定注解可以使用的位置
@Target({
ElementType.TYPE, // 类、接口、枚举
ElementType.FIELD, // 字段
ElementType.METHOD, // 方法
ElementType.PARAMETER, // 参数
ElementType.CONSTRUCTOR, // 构造方法
ElementType.LOCAL_VARIABLE, // 局部变量
ElementType.ANNOTATION_TYPE, // 注解类型
ElementType.PACKAGE // 包
})
@interface MyAnnotation {
String value() default "";
}@Retention
java
import java.lang.annotation.*;
// @Retention:指定注解的保留策略
public enum RetentionPolicyDemo {
// SOURCE:源码保留,编译时丢弃
@Retention(RetentionPolicy.SOURCE)
@interface SourceAnnotation { }
// CLASS:字节码保留,运行时丢弃(默认)
@Retention(RetentionPolicy.CLASS)
@interface ClassAnnotation { }
// RUNTIME:运行时保留,可通过反射获取
@Retention(RetentionPolicy.RUNTIME)
@interface RuntimeAnnotation { }
}@Documented
java
import java.lang.annotation.*;
// @Documented:注解会被包含在 JavaDoc 中
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface ApiDoc {
String description();
String author();
}@Inherited
java
import java.lang.annotation.*;
// @Inherited:注解可以被继承
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface InheritableAnnotation {
String value();
}
@InheritableAnnotation("父类注解")
class ParentClass { }
// 子类会继承父类的 @InheritableAnnotation
class ChildClass extends ParentClass { }
// 非 @Inherited 的注解不会被继承
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface NonInheritedAnnotation {
String value();
}@Repeatable
java
import java.lang.annotation.*;
// Java 8+:可重复注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface Author {
String name();
}
// 容器注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface Authors {
Author[] value();
}
// 使用 @Repeatable
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Repeatable(Authors.class)
@interface Developer {
String name();
}
// 使用可重复注解
@Developer(name = "张三")
@Developer(name = "李四")
@Developer(name = "王五")
class Project { }
public class RepeatableDemo {
public static void main(String[] args) {
Developer[] developers = Project.class.getAnnotationsByType(Developer.class);
for (Developer dev : developers) {
System.out.println("开发者:" + dev.name());
}
}
}自定义注解
定义注解
java
import java.lang.annotation.*;
/**
* 自定义注解:用于标记 API 接口
*/
@Retention(RetentionPolicy.RUNTIME) // 运行时保留
@Target(ElementType.METHOD) // 用于方法
public @interface Api {
// 注解元素:类似接口方法
String path(); // 必须指定
String method() default "GET"; // 有默认值,可选
String description() default ""; // 有默认值,可选
int timeout() default 5000; // 有默认值,可选
// 特殊值 value:如果只有一个元素且名为 value,可以省略元素名
// String value();
}使用注解
java
// 使用自定义注解
class UserController {
@Api(path = "/users", method = "GET", description = "获取用户列表")
public void getUsers() {
System.out.println("获取用户列表");
}
@Api(path = "/users/{id}", method = "POST")
public void createUser() {
System.out.println("创建用户");
}
// 省略可选参数
@Api(path = "/users/{id}")
public void getUser() {
System.out.println("获取单个用户");
}
}注解元素类型
java
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface ElementTypes {
// 允许的类型:
// 1. 基本类型
int intValue();
double doubleValue();
boolean booleanValue();
// 2. String
String stringValue();
// 3. Class
Class<?> classValue();
// 4. 枚举
Thread.State enumValue();
// 5. 注解
Deprecated annotationValue();
// 6. 以上类型的一维数组
String[] arrayValue();
// 不允许的类型:
// Object、包装类(Integer、Double等)、多维数组
}注解处理
运行时处理
java
import java.lang.annotation.*;
import java.lang.reflect.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface Log {
String value() default "";
boolean enable() default true;
}
class Service {
@Log("执行业务方法")
public void businessMethod() {
System.out.println("业务方法执行");
}
@Log(value = "调试方法", enable = false)
public void debugMethod() {
System.out.println("调试方法执行");
}
public void normalMethod() {
System.out.println("普通方法");
}
}
public class AnnotationProcessor {
public static void main(String[] args) throws Exception {
Service service = new Service();
Class<?> clazz = Service.class;
// 遍历所有方法
for (Method method : clazz.getDeclaredMethods()) {
// 检查方法是否有 @Log 注解
if (method.isAnnotationPresent(Log.class)) {
Log log = method.getAnnotation(Log.class);
if (log.enable()) {
System.out.println("[日志] " + log.value());
}
// 执行方法
method.invoke(service);
} else {
method.invoke(service);
}
}
}
}类级别注解处理
java
import java.lang.annotation.*;
import java.lang.reflect.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface Table {
String name();
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface Column {
String name();
boolean primaryKey() default false;
}
@Table(name = "t_user")
class User {
@Column(name = "id", primaryKey = true)
private Long id;
@Column(name = "username")
private String username;
@Column(name = "email")
private String email;
// getter 和 setter
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
}
public class OrmDemo {
public static void main(String[] args) {
Class<User> clazz = User.class;
// 获取表名
Table table = clazz.getAnnotation(Table.class);
System.out.println("表名:" + table.name());
// 获取字段信息
System.out.println("\n字段信息:");
for (Field field : clazz.getDeclaredFields()) {
Column column = field.getAnnotation(Column.class);
if (column != null) {
System.out.println(field.getName() + " -> " + column.name() +
(column.primaryKey() ? " (主键)" : ""));
}
}
// 生成 SQL
StringBuilder sql = new StringBuilder("CREATE TABLE ");
sql.append(table.name()).append(" (");
boolean first = true;
for (Field field : clazz.getDeclaredFields()) {
Column column = field.getAnnotation(Column.class);
if (column != null) {
if (!first) sql.append(", ");
sql.append(column.name()).append(" ");
sql.append(getSqlType(field.getType()));
if (column.primaryKey()) {
sql.append(" PRIMARY KEY");
}
first = false;
}
}
sql.append(")");
System.out.println("\n生成的 SQL:\n" + sql);
}
private static String getSqlType(Class<?> type) {
if (type == Long.class || type == long.class) return "BIGINT";
if (type == String.class) return "VARCHAR(255)";
if (type == Integer.class || type == int.class) return "INT";
return "VARCHAR(255)";
}
}字段验证注解
java
import java.lang.annotation.*;
import java.lang.reflect.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface NotNull {
String message() default "字段不能为空";
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface Size {
int min() default 0;
int max() default Integer.MAX_VALUE;
String message() default "长度不在有效范围内";
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface Range {
long min() default Long.MIN_VALUE;
long max() default Long.MAX_VALUE;
String message() default "数值不在有效范围内";
}
class Person {
@NotNull(message = "姓名不能为空")
@Size(min = 2, max = 20, message = "姓名长度应在2-20之间")
private String name;
@Range(min = 0, max = 150, message = "年龄应在0-150之间")
private int age;
@NotNull(message = "邮箱不能为空")
private String email;
public Person(String name, int age, String email) {
this.name = name;
this.age = age;
this.email = email;
}
}
public class Validator {
public static void validate(Object obj) throws Exception {
Class<?> clazz = obj.getClass();
for (Field field : clazz.getDeclaredFields()) {
field.setAccessible(true);
Object value = field.get(obj);
// @NotNull 验证
NotNull notNull = field.getAnnotation(NotNull.class);
if (notNull != null && value == null) {
throw new IllegalArgumentException(
field.getName() + ": " + notNull.message());
}
// @Size 验证
Size size = field.getAnnotation(Size.class);
if (size != null && value instanceof String) {
int length = ((String) value).length();
if (length < size.min() || length > size.max()) {
throw new IllegalArgumentException(
field.getName() + ": " + size.message());
}
}
// @Range 验证
Range range = field.getAnnotation(Range.class);
if (range != null && value instanceof Number) {
long num = ((Number) value).longValue();
if (num < range.min() || num > range.max()) {
throw new IllegalArgumentException(
field.getName() + ": " + range.message());
}
}
}
}
public static void main(String[] args) {
try {
Person p1 = new Person("张三", 25, "zhangsan@example.com");
validate(p1);
System.out.println("验证通过");
} catch (Exception e) {
System.out.println("验证失败:" + e.getMessage());
}
try {
Person p2 = new Person(null, 25, "test@example.com");
validate(p2);
} catch (Exception e) {
System.out.println("验证失败:" + e.getMessage());
}
try {
Person p3 = new Person("张", 25, "test@example.com");
validate(p3);
} catch (Exception e) {
System.out.println("验证失败:" + e.getMessage());
}
try {
Person p4 = new Person("张三", 200, "test@example.com");
validate(p4);
} catch (Exception e) {
System.out.println("验证失败:" + e.getMessage());
}
}
}注解最佳实践
命名约定
java
// 注解命名约定
// 1. 使用名词或形容词
// 2. 首字母大写,驼峰命名
// 3. 不使用动词
// 好的命名
@interface Entity { }
@interface Service { }
@interface Valid { }
@interface NotNull { }
@interface Injectable { }
// 不好的命名
@interface Validate { } // 动词
@interface doSomething { } // 小写开头注解设计原则
java
import java.lang.annotation.*;
// 好的设计:职责单一,语义清晰
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface Cacheable {
String key(); // 缓存键
int expire() default 3600; // 过期时间(秒)
boolean async() default false; // 是否异步
}
// 使用示例
class ProductService {
@Cacheable(key = "product:{id}", expire = 7200)
public Product getProduct(Long id) {
// 查询数据库
return new Product(id, "商品" + id);
}
}
class Product {
Long id;
String name;
public Product(Long id, String name) {
this.id = id;
this.name = name;
}
}小结
本章我们学习了:
- 注解概述:注解的定义和作用
- 内置注解:@Override、@Deprecated、@SuppressWarnings、@FunctionalInterface
- 元注解:@Target、@Retention、@Documented、@Inherited、@Repeatable
- 自定义注解:定义和使用自定义注解
- 注解处理:运行时通过反射处理注解
- 最佳实践:命名约定和设计原则
恭喜你完成了 Java 基础教程的学习!接下来你可以继续学习:
