限定参数范围的注解之 "咖啡店定价" 的故事

让我们用一个 "咖啡店定价" 的故事来理解限定参数范围的注解原理,再结合源码一步步拆解底层逻辑。

故事:咖啡店的 "价格规则标签"

老王开了家咖啡店,规定所有咖啡的价格必须在 10-50 元之间。但店员经常记错价格,导致定价混乱。

于是老王想了个办法:

  1. 设计了一种 "价格范围标签"(类似注解),标签上印着 "最低 10 元,最高 50 元"
  2. 要求店员给所有咖啡的定价单都贴上这个标签(在代码中使用注解)
  3. 专门雇了个 "检查员"(类似注解处理器),每次定价时都对照标签检查价格是否合规

对应到 Java:限定参数范围的注解实现

我们要实现一个@PriceRange注解,用来限制方法参数必须在 10-50 之间。整个过程分 3 步:定义注解使用注解实现检查逻辑

第一步:定义 "价格范围标签"(自定义注解)

就像老王设计标签样式,我们需要定义注解的 "规则":

java 复制代码
import java.lang.annotation.*;

// 这个注解只能贴在方法的参数上
@Target(ElementType.PARAMETER)
// 这个注解在运行时还能被读取到(检查员在定价时还能看到标签)
@Retention(RetentionPolicy.RUNTIME)
public @interface PriceRange {
    // 最低价格(标签上的"最低10元")
    int min() default 10;
    // 最高价格(标签上的"最高50元")
    int max() default 50;
}

这里的@Target@Retention是 "元注解"(注解的注解):

  • @Target(ElementType.PARAMETER):规定这个注解只能贴在方法参数上(就像标签只能贴在定价单上)
  • @Retention(RetentionPolicy.RUNTIME):规定注解在程序运行时仍然有效(检查员在定价时能看到标签,而不是定价单被收起来后就看不到了)

第二步:使用 "价格范围标签"(在代码中应用注解)

就像店员给定价单贴标签,我们在需要限制的参数上加上@PriceRange

java 复制代码
public class CoffeeShop {
    // 给咖啡定价的方法,参数price贴上@PriceRange标签
    public void setCoffeePrice(@PriceRange int price) {
        System.out.println("咖啡定价:" + price + "元");
    }
}

第三步:实现 "检查员"(注解检查逻辑)

老王雇的检查员需要做两件事:

  1. 看到定价单上的标签(读取注解信息)

  2. 检查实际价格是否符合标签上的范围(校验参数值)

在 Java 中,我们可以通过反射实现这个 "检查员":

java 复制代码
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;

public class PriceChecker {
    // 检查方法调用时的参数是否符合@PriceRange规则
    public static void check(Object obj, String methodName, Object... params) throws Exception {
        // 1. 找到要调用的方法(找到定价单)
        Method method = obj.getClass().getMethod(methodName, int.class);
        
        // 2. 获取方法的参数(拿到定价单上的价格输入框)
        Parameter[] parameters = method.getParameters();
        
        // 3. 遍历参数,检查是否有@PriceRange注解
        for (int i = 0; i < parameters.length; i++) {
            Parameter param = parameters[i];
            // 判断参数上是否贴了@PriceRange标签
            if (param.isAnnotationPresent(PriceRange.class)) {
                // 4. 读取注解上的规则(标签上的min和max)
                PriceRange annotation = param.getAnnotation(PriceRange.class);
                int min = annotation.min();
                int max = annotation.max();
                
                // 5. 检查实际参数值是否符合规则(实际价格是否在范围内)
                int price = (int) params[i];
                if (price < min || price > max) {
                    throw new IllegalArgumentException("价格不符合规则!必须在" + min + "-" + max + "元之间");
                }
            }
        }
        
        // 6. 如果检查通过,正常调用方法(定价成功)
        method.invoke(obj, params);
    }

    // 测试一下
    public static void main(String[] args) throws Exception {
        CoffeeShop shop = new CoffeeShop();
        // 正常定价(20元在10-50之间)
        check(shop, "setCoffeePrice", 20); // 输出:咖啡定价:20元
        
        // 错误定价(5元低于最低10元)
        check(shop, "setCoffeePrice", 5); // 抛出异常:价格不符合规则!
    }
}

底层原理总结

限定参数范围的注解本质是 "带规则的标签 + 检查器" 的组合:

  1. 注解定义 :用@interface声明一个 "标签",通过元注解(@Target@Retention)规定标签的使用场景和生命周期,用成员变量(minmax)定义规则。

  2. 注解使用:在需要限制的参数上贴标签,告诉程序 "这个参数需要被检查"。

  3. 检查逻辑:通过反射(运行时)或注解处理器(编译时)实现 "检查员":

    • 反射方式:运行时读取参数上的注解信息,对比参数值和注解规则,不符合就报错。
    • 编译时方式:在编译阶段就检查(类似@Override的原理),直接让代码编译失败。

关键知识点

  • @Retention(RUNTIME)是运行时检查的关键,保证注解在程序运行时还能被读取。

  • 反射是 "检查员" 读取注解信息的工具(getAnnotation()方法)。

  • 注解本身不做任何事情,必须有对应的 "检查器"(代码)才能生效(就像标签本身不会说话,需要检查员来执行规则)。

这样的机制让 Java 代码能在编译或运行时自动校验参数,避免了手动写大量if(price < 10 || price >50)的重复代码。

相关推荐
维基框架5 分钟前
维基框架 (Wiki FW) v1.1.1 | 企业级微服务开发框架
java·架构
Propeller14 分钟前
【Android】LayoutInflater 控件实例化的桥梁类
android
某空_17 分钟前
【Android】BottomSheet
java
国家二级编程爱好者18 分钟前
Android开机广播是有序还是无序?广播耗时原因是什么?
android
猿小蔡-Cool19 分钟前
Robolectric如何启动一个Activity
android·单元测试·rebolectric
10km21 分钟前
jsqlparser(六):TablesNamesFinder 深度解析与 SQL 格式化实现
java·数据库·sql·jsqlparser
是2的10次方啊29 分钟前
Java多线程基础:进程、线程与线程安全实战
java
Industio_触觉智能34 分钟前
瑞芯微RK3576开发板Android14三屏异显开发教程
android·开发板·瑞芯微·rk3576·多屏异显·rk3576j·三屏异显
JavaArchJourney1 小时前
MySQL 索引:原理篇
java·后端·mysql
Java编程乐园1 小时前
Java函数式编程之【流(Stream)性能优化】
java·性能优化