ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

异常·反射·注解

异常·反射·注解

Java中的异常

运行时异常和非运行时异常

  • 运行时异常是指自己的代码写的不够好,边界情况没有处理好,能够通过编译但是运行会报错。比如空指针,数组越界
  • 非运行时异常是外部环境的问题,比如要访问的文件被删除了,SQL没连上去。编译都会欧保国

throw和throws

  • throw相当于一个能抛出异常的输出语句
  • throws是写到方法上面的,说这个方法里面可能存着某个异常但是我不处理,留给掉用者处理。如果调用者向上一抛出的话就会给JVM处理,结果就是直接报错,程序停止运行
  • 如果有一个catch啦接住这个异常的话程序还会继续运行

反射

  • 在运行时,动态地获取类的信息(属性、方法、构造器等),并可以操作它们

获取Class对象的三种方法

// 方式一:通过类名.class(编译时就知道类型)Class<User>c1=User.class;// 方式二:通过对象.getClass()(运行时拿到对象才知道类型)Useruser=newUser();Class<?>c2=user.getClass();// 方式三:通过全限定类名字符串(最灵活,最常用)Class<?>c3=Class.forName("com.example.User");
  • 一个类在JVM里面只有同一个Class对象

Class类的API

  • Field字段(操作字段的)
  • Method方法(invoke来调用的)
  • Constructor构造器(用来实例化的)

操作构造器来实例化

Class<?>clazz=Class.forName("com.example.User");// 获取无参构造器,创建实例Constructor<?>noArg=clazz.getDeclaredConstructor();Objectuser1=noArg.newInstance();// 获取有参构造器Constructor<?>withArg=clazz.getDeclaredConstructor(String.class,int.class);Objectuser2=withArg.newInstance("张三",25);
  • 只有操作构造器才能来实例化

注解

  • 注解是一种给代码添加元数据(描述信息)的方式,它本身不影响代码逻辑,但可以在编译期或运行时被读取和处理
  • 注解本质上就是接口
// 你写的注解@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public@interfaceMyAnnotation{Stringvalue();intage()default18;}
  • 反射编译后就是一个接口
// 注解的本质是一个继承了 java.lang.annotation.Annotation 的接口publicinterfaceMyAnnotationextendsAnnotation{Stringvalue();intage();// default 18 在编译时由框架读取处理}

元注解

  • @Target:注解能用到哪里
@Target({ElementType.METHOD,ElementType.FIELD})public@interfaceMyAnnotation{}
  • @Retention:注解能活到什么时候
源码(.java) → 字节码(.class) → JVM 加载到内存 SOURCE: ✅存在 ❌丢弃 ❌丢弃 CLASS: ✅存在 ✅存在 ❌丢弃 (默认) RUNTIME: ✅存在 ✅存在 ✅存在 (反射可用)
  • . @Inherited — 子类是否继承父类的注解

###自定义注解

@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public@interfaceMyAnnotation{// 带默认值的属性Stringvalue()default"";// 可以有多个属性intpriority()default0;// 属性类型支持:基本类型、String、Class、枚举、注解、以上类型的数组String[]tags()default{};}
  • 这个String value()是指变量value的类型是String,()没有任何意义
@MyAnnotation(value="test",priority=1,tags={"a","b"})publicvoiddoSomething(){}

注解的处理方式:运行时反射

// 自定义注解@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public@interfaceRoute{Stringpath();}// 使用注解publicclassUserController{@Route(path="/user/list")publicStringlistUsers(){return"user list";}@Route(path="/user/detail")publicStringgetUserDetail(){return"user detail";}}// 运行时通过反射读取注解publicclassRouter{publicstaticvoidmain(String[]args)throwsException{Class<?>clazz=UserController.class;for(Methodmethod:clazz.getDeclaredMethods()){// 判断方法上是否有 @Route 注解if(method.isAnnotationPresent(Route.class)){Routeroute=method.getAnnotation(Route.class);// 读取注解的属性值System.out.println("路径: "+route.path());System.out.println("方法: "+method.getName());// 可以把 path → method 的映射存起来,实现路由}}}}
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进