[Java]详解什么是注解以及如何自定义注解?

一、什么是注解

(1).注解的作用

①:注解一般用于对程序的说明,就像注释一样,但是区别是注释是给人看的,但是注解是给程序看的。
②:让编译器进行编译检查的作用,比如下边这个@Override注解是重写的意思,子类重写了父类的方法,但是改动了方法名,所以报错。

(2).注解的格式

注解是以“@注解名”在代码当中存在的,还可以添加一些参数值,例如 @SuppressWarnings(value = “unchecked”)

(3).注解在哪里使用

可以附加在package、class、method、field等上面,相当于给他们添加了额外的辅助信息。我们可以通过反射的方式对这些注解进行访问。

二、注解的类型

一般常用的注解分为三类:

(1).内置注解

  • ①:@Override:修辞方法的,表示一个方法重写了父类方法

  • ②:@Deprecated:修辞方法、属性、类,表示不鼓励程序员使用这样的元素,通常是因为它很危险或存在更好的选择。通俗来说就是遗弃。

  • ③:@SuppressWarnings:用来抑制编译时的警告信息,括号里的的值包括
    a.deprecation:使用了过时的类或方法的警告
    b.unchecked:执行了未检查时的转换时的警告,集合就是未指定泛型
    c.fall through:当在switch语句使用时发生case穿透
    d.path:在类路径、源文件路径等中有不存在路径的警告
    e.serial:可序列化类上缺少serialVerisonUID定义时的警告
    f.finally:任何finally橘子不能完成时的警告
    g.all:以上所有情况的警告。
    一个 @SuppressWarnings(“all”),
    多个 @SuppressWarnings(value={“all”,“path”})

(2).元注解

元注解是用于注解的注解,在JDK 1.5中提供了4个标准的用来对注解类型进行注解的注解类
①:@Target注解(用来描述注解的使用范围,即注解可以使用在什么地方,在定义注解的时候使用这个我们可以更加清晰的知道它的使用范围)

public enum ElementType {
  
    TYPE,              //类,接口

    FIELD,            //成员变量

    METHOD,          //方法

    PARAMETER,       //方法参数

    CONSTRUCTOR,    //构造方法

    LOCAL_VARIABLE,     //局部变量

    ANNOTATION_TYPE,      //注解类
    
    PACKAGE,           // 包

    TYPE_PARAMETER,     //类型参数

    TYPE_USE      //使用类型的任何地方
}

②:@Retention注解(表示这个注解在什么时候还有效 , 用于描述注解的生命周期)

public enum RetentionPolicy {
    SOURCE, // 源文件保留
    CLASS,  // 编译期保留,默认值
    RUNTIME // 运行期保留,可通过反射去获取注解信息,咱们自定义的类一般使用这个
}

③:@Documented 这个注解只是用来标注生成javadoc的时候是否会被记录(了解就好)。

④:@Inherited注解的作用是:使被它修饰的注解具有继承性

(3).自定义注解

①:@interface是用来声明一个注解的,格式public @interface 注解名{定义内容}
②:其中的每一方法实际上是声明了一个配置参数
③:方法的名称就是参数的名称
④:返回值类型就是参数的类型(返回值类型只能是基本数据类型,Class,String,enum)
⑤:可以通过default来声明参数的默认值
⑥:如果只有一个参数成员,一般参数名称为value
⑦:注解参数必须有值,我们自定义注解元素时,经常使用空字符串,0作为默认值
在这里插入图片描述

三、自定义注解实现及测试

Controller.annotation:

package Test.annotation;

import Test.Test;

import java.lang.annotation.*;

//该注解可以应用于类、接口(包括注解类型)、枚举
@Target(ElementType.TYPE)//ElementType.TYPE
//该注解标记的元素可以被Javadoc 或类似的工具文档化
@Documented
//该注解的生命周期,由JVM 加载,包含在类文件中,在运行时可以被获取到
@Retention(RetentionPolicy.RUNTIME)//RUNTIME
public @interface Controller {
}

RequestMapping.annotation:

package Test.annotation;

import Test.Test;

import java.lang.annotation.*;

/**
 * @author yhz
 */

//该注解可以应用于类、接口(包括注解类型)、枚举 以及方法上
@Target({ElementType.TYPE,ElementType.METHOD})//ElementType.TYPE
//该注解标记的元素可以被Javadoc 或类似的工具文档化
@Documented
//该注解的生命周期,由JVM 加载,包含在类文件中,在运行时可以被获取到
@Retention(RetentionPolicy.RUNTIME)//RUNTIME
public @interface RequestMapping {
    String value()default "";
}

TestController.java

package Test.controller;

import Test.annotation.Controller;
import Test.annotation.RequestMapping;

/**
 * @BelongsProject: SpringTest
 * @Version: 1.0
 */
@Controller
@RequestMapping("test")
public class TestController {

    @RequestMapping
    public String index(){
        System.out.println("test->index");
        return "";
    }

    @RequestMapping
    public String index1(){
        System.out.println("test->index1");
        return "";
    }
}

如果把controller注解在方法上,会报错,原因是我们定义的@controller注解只能写在类、接口、枚举上面。

Main.java 用于将该项目中被标记@Controller注解的类,创建实例并存入一个Map中。

package Test;

import Test.annotation.Controller;
import Test.annotation.RequestMapping;

import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @BelongsProject: 3.9.demo
 * @Author: YHZ
 * @CreateTime: 2023-07-22  14:36
 * @Description: TODO
 * @Version: 1.0
 */
public class Main {
    public static List<String>arr= new ArrayList<>();
    public static Map<String,Object>controllerMap = new HashMap<>();
    static {
        String fileName =  "E:\\SpringTest\\src";
        File file = new File(fileName);
        getFilePath(file);

        try {
            chooseController();
        }
        catch (Exception e){
            e.printStackTrace();
        }
    }

    private static void getFilePath(File file) {
        File[] fs = file.listFiles();
        for (File f : fs) {
            if (f.isDirectory()){
                getFilePath(f);
            }
            if (f.isFile()) {
                String filepath = f.toString();
                filepath = filepath.split("src")[1];
                filepath = filepath.substring(1,filepath.length());
                if( filepath.endsWith(".java")) {
                    //把是.java文件的全类名放到arr中
                    arr.add(filepath.replace("\\", ".").replace(".java", ""));
                }
            }
        }
    }

    //查找所有controller,并创建对象装入Map里(“url”:Object)
    private static void chooseController() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        for(String file: arr){
            Class<?> aClass = Class.forName(file);
            if(aClass.isAnnotationPresent(Controller.class)){
                Object o = aClass.getDeclaredConstructor().newInstance();
                RequestMapping annotation = aClass.getAnnotation(RequestMapping.class);
                if(annotation==null){
                    throw  new RuntimeException("没有标记RequestMapping");
                }
                controllerMap.put(annotation.value(),o);
            }
        }
    }
}

在这里插入图片描述

结果:

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值