Java学习30

一、上午 3h 注解入门 + Java 内置注解

1. 注解核心概念详细讲解

1.1 什么是注解

注解(Annotation):Java 中的一种标记 ,写在类、方法、变量、参数上方,用来给程序附加额外信息

1.2 注解三大核心作用

  1. 做标记:标记方法重写、类过时、忽略警告
  2. 简化代码:替代 XML 配置文件,框架主流用法
  3. 程序识别 :运行时通过反射读取注解信息,自动执行逻辑

1.3 注解 vs 注释 本质区别(必背)

表格

类型 作用范围 程序能否读取 用途
单行 // 多行 /* */ 注释 仅给程序员看 不能被 JVM / 代码解析 代码说明、笔记
注解 @XXX 标记程序元素 可以被反射读取 框架配置、业务标记、校验

1.4 注解使用位置

可标注:类、接口、成员变量、方法、形参、构造方法、局部变量等

2. Java 三大内置常用注解(重点 + 代码案例)

2.1 @Override 重写校验

作用 :强制校验当前方法是否真的重写了父类方法,写错方法名直接编译报错使用场景:子类重写父类 / 接口方法

java

运行

复制代码
class Animal{
    public void eat(){
        System.out.println("动物吃饭");
    }
}

class Dog extends Animal{
    // 加上@Override 严格校验重写格式
    @Override
    public void eat() {
        System.out.println("小狗啃骨头");
    }
}

解释 :不加也能重写,加上是语法校验,防止手写错误。


2.2 @Deprecated 标记过时 / 废弃

作用:标记类、方法、变量已经过时,不建议继续使用,调用时出现删除线提示

java

运行

复制代码
public class TestDeprecated {
    // 标记该方法已过时
    @Deprecated
    public void oldMethod(){
        System.out.println("老旧方法");
    }

    public static void main(String[] args) {
        TestDeprecated t = new TestDeprecated();
        t.oldMethod(); // 代码出现删除线,提示废弃
    }
}

拓展:源码中大量旧 API 全部使用此注解标记。


2.3 @SuppressWarnings 压制警告

作用:消除代码中黄色警告,不影响程序运行,仅美化代码提示常用参数:

  • @SuppressWarnings("all"):压制所有警告
  • @SuppressWarnings("unused"):压制未使用变量警告
  • @SuppressWarnings("rawtypes"):压制泛型未指定警告

java

运行

复制代码
import java.util.ArrayList;

public class TestWarning {
    // 压制所有警告
    @SuppressWarnings("all")
    public static void main(String[] args) {
        ArrayList list = new ArrayList(); // 无泛型警告直接消失
        int a; // 未使用变量警告消失
    }
}

3. 注解初识定义格式

简易格式:

java

运行

复制代码
public @interface 注解名{
    
}

@interface定义注解专用关键字,和 class、interface 同级。


二、下午 2.5h 四大元注解 + 自定义注解(核心重难点)

1. 四大元注解(用来修饰自定义注解,控制注解规则)

元注解:注解的注解,专门用来规定自定义注解能怎么用

1.1 @Target 【重中之重】

作用 :限定自定义注解只能写在哪些位置常用取值(ElementType 枚举):

  • ElementType.TYPE:作用在 类、接口、枚举上
  • ElementType.FIELD:作用在 成员变量上
  • ElementType.METHOD:作用在 成员方法上
  • ElementType.PARAMETER:作用在 方法参数上
  • ElementType.CONSTRUCTOR:作用在构造方法上

1.2 @Retention 【最核心,决定能否被反射读取】

作用 :设置注解保留生命周期,三个级别优先级由低到高

  1. RetentionPolicy.SOURCE:仅存在源码阶段,编译后消失 → 不能反射读取
  2. RetentionPolicy.CLASS:保留到class 字节码,运行时丢失 → 默认级别,无法反射解析
  3. RetentionPolicy.RUNTIME:保留到程序运行时只有这个能被反射读取解析

实战开发、框架注解 必须写 RUNTIME

1.3 @Documented

作用:使用 javadoc 生成 API 文档时,将注解信息一同写入文档,纯文档作用。

1.4 @Inherited

作用 :父类上加了该注解,子类自动继承父类身上的这个注解

2. 自定义注解完整语法 + 三类案例

规则

  1. 使用 @interface 定义
  2. 内部可以定义属性 ,格式:数据类型 属性名() default 默认值;
  3. 属性支持类型:基本类型、String、枚举、注解、以上类型数组

2.1 无属性自定义注解(标记注解)

java

运行

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

// 限定只能作用在类上
@Target(ElementType.TYPE)
// 运行时有效,支持反射读取
@Retention(RetentionPolicy.RUNTIME)
public @interface MyFlagAnno {
    // 无任何属性,纯做标记
}

使用:

java

运行

复制代码
@MyFlagAnno
public class User {
    
}

2.2 单属性自定义注解 + value 简写

规则 :注解中只有一个属性,且名字为value,使用时可省略value=直接赋值

java

运行

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

@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyValueAnno {
    // 唯一属性value
    String value();
}

正常写法:

java

运行

复制代码
@MyValueAnno(value = "学生管理类")

简写写法(最常用):

java

运行

复制代码
@MyValueAnno("学生管理类")

2.3 多属性自定义注解 + 设置默认值

java

运行

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

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyInfoAnno {
    // 注解属性,带默认值
    String author() default "匿名开发者";
    int version() default 1;
    String desc(); // 无默认值,使用时必须赋值
}

使用方式:

java

运行

复制代码
public class Book {
    @MyInfoAnno(desc = "查询书籍信息",author = "张三",version = 2)
    public void selectBook(){
        
    }
}

三、晚上 1.5h 反射解析注解 + 实战练习(注解最终用途)

核心原理

只有被@Retention(RetentionPolicy.RUNTIME)修饰的注解,才能通过反射获取

1. 反射常用注解解析 API

java

运行

复制代码
// 1. 判断类上是否存在指定注解
clazz.isAnnotationPresent(注解名.class)

// 2. 获取类上的注解对象
注解类型 变量 = clazz.getAnnotation(注解名.class)

// 3. 获取方法/变量上注解同理
method.getAnnotation()
field.getAnnotation()

2. 完整综合案例:反射读取自定义注解属性

步骤 1:定义运行时注解

java

运行

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

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ClassInfo {
    String className();
    String type() default "业务类";
}

步骤 2:实体类使用注解

java

运行

复制代码
@ClassInfo(className = "用户实体类",type = "数据实体")
public class UserEntity {
    
}

步骤 3:反射解析注解(核心代码)

java

运行

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

public class AnnoParseTest {
    public static void main(String[] args) {
        // 1. 获取Class对象
        Class<UserEntity> clazz = UserEntity.class;

        // 2. 判断是否标注了ClassInfo注解
        boolean hasAnno = clazz.isAnnotationPresent(ClassInfo.class);
        if(hasAnno){
            // 3. 获取注解对象
            ClassInfo classInfo = clazz.getAnnotation(ClassInfo.class);
            // 4. 读取注解里面的属性值
            String name = classInfo.className();
            String type = classInfo.type();
            System.out.println("注解类名:"+name);
            System.out.println("注解类型:"+type);
        }
    }
}

逐行解释

  1. isAnnotationPresent:判断标记是否存在
  2. getAnnotation:拿到注解实例
  3. 直接调用注解内部属性名 () 即可取值

3. 简易实战:模拟框架注解配置

需求:自定义注解配置端口号,通过注解读取启动端口

1. 定义配置注解

java

运行

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

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ServerConfig {
    int port() default 8080;
    String host() default "127.0.0.1";
}

2. 服务类使用注解

java

运行

复制代码
@ServerConfig(port = 8888,host = "localhost")
public class WebServer {
    
}

3. 工具类读取注解自动启动

java

运行

复制代码
public class ServerStart {
    public static void main(String[] args) {
        Class<WebServer> clazz = WebServer.class;
        ServerConfig config = clazz.getAnnotation(ServerConfig.class);
        System.out.println("服务器IP:"+config.host());
        System.out.println("启动端口:"+config.port());
        System.out.println("模拟服务器启动成功");
    }
}

实战意义:SpringBoot 配置端口、MyBatis 映射路径底层全是这套逻辑。

4. 注解在框架中的底层用途总结

  1. Spring:@Component @Controller 扫描注解,反射创建对象存入容器
  2. SpringMVC:@RequestMapping 解析注解路径,映射请求地址
  3. MyBatis:注解配置 SQL 语句,运行时反射读取执行
  4. JUnit:@Test 标记测试方法,框架识别自动运行

四、计划遗漏必补重要知识点(你原计划没有,必考)

1. 注解属性限制

  • 不能定义 void、自定义实体类等非常规类型
  • 数组属性用法:String[] value() default {};

2. 重复注解(JDK8 + 新特性)

同一位置可以多次使用同一个注解,框架高频使用

3. 注解不支持继承方法属性

自定义注解不能继承类,只能被元注解 @Inherited 让子类继承标记

4. 编译期注解与运行期注解使用场景区分

  • SOURCE:仅编译校验(@Override 本质就是源码级别)
  • RUNTIME:业务框架配置、反射解析必备

5. 注解没有执行逻辑

注解本身只是标记,无任何代码逻辑 ,所有功能全靠反射代码读取注解后实现


五、Day30 最终达标验收完整版

  1. 分清注解与注释本质区别,说出三大内置注解用法
  2. 熟记四大元注解作用、@Target 位置、@Retention 三级生命周期
  3. 独立手写:无属性、单属性 value 简写、多属性带默认值三种自定义注解
  4. 熟练使用反射 API:判断注解存在、获取注解、读取注解属性值
  5. 能独立完成「配置注解 + 反射读取」简易实战案例
  6. 理解主流框架底层依靠注解 + 反射实现自动化配置原理

六、统一规范(JDK17 无报错)

  1. 所有自定义注解必须加上 @Retention(RetentionPolicy.RUNTIME) 才能解析
  2. 一个 java 文件仅一个 public 类,练习代码全部整合无冲突
  3. 所有案例均可直接复制运行,无需额外导包

整体流程(先看懂大框架)

  1. 定义注解 → 相当于做一张自定义标签
  2. 使用注解 → 把标签贴在类上
  3. 反射解析注解 → 把标签撕下来读内容
相关推荐
次元工程师!1 小时前
LangFlow开发(三)—Bundles组件架构设计(3W+字详细讲解)
java·前端·python·低代码·langflow
三品吉他手会点灯1 小时前
C语言学习笔记 - 40.数据类型 - scanf函数的编程规范与非法输入处理
c语言·开发语言·笔记·学习
凯瑟琳.奥古斯特1 小时前
数据冗余与规范化的本质[数据库原理]
开发语言·数据库·职场和发展
码农老李2 小时前
openEuler2403服务器版 原生官方镜像和飞腾定制镜像
开发语言·php
charlie1145141912 小时前
现代Qt开发教程(新手篇)2.3——QImage、QPixmap、QIcon 图像处理基础
开发语言·图像处理·qt
范范@2 小时前
python基础-函数
开发语言·python
Bechamz3 小时前
大数据开发学习Day36
大数据·学习
特种加菲猫3 小时前
从零开始手撕AVL树:详解插入、平衡因子更新与四种旋转
开发语言·c++
oddsand13 小时前
Redis网络模型
java·数据库·redis