注解及使用自定义注解

注解

注解是程序中的一种特殊标记。通过注解,编译器可以了解到该部分程序被保留的阶段、赋值传递等特殊用途。格式:@注解名

一、内置注解

在Java中常见的内置注解的如下:

@Override:表示被标记的方法继承了父类同名同参的方法,当检测到父类不存在该方法时将报编译时异常。

@Deprecated:表示被标记的方法已不推荐使用。

@SuppressWarnings():将提示编译器忽略当前被标记方法中的Warnings

二、注解本质

当我们点开@Override注解时,可以看到内容如下:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}

那么注解是否是被@interface修饰符修饰的类呢?

我们可以仿造这个格式自己创建一个注解Anno1

public @interface Anno1 {
}

在Anno1.java所在的文件夹中,使用javac命令编译成Anno1.class文件,再使用javap命令反编译,看到控制台输出如下:

反编译后结果

可见,注解实际上是一个继承了Annotation类的接口

三、自定义注解

下面我们开始尝试自定义并使用注解:

从(二)可知,注解实际上是一个继承了Annotation类的接口既然是接口。接口中一般含有抽象方法,在注解中,抽象方法也被称为属性。我们创建一个注解如下:(属性的修饰符默认为public abstract,可以不写)

public @interface Anno1 {
    
    String name();
    int age();
}

此时,我们就可以使用该注解

@Anno1(name="James",age=10)
public class Father {

}

通过反射应用注解实例:Test.java:

public static void main(String[] args) {

    Father father = new Father();
    Anno1 anno1 = father.getClass().getAnnotation(Anno1.class);
    System.out.println("name = " + anno1.name());
    System.out.println("age = " + anno1.age());
}

此时,会报空指针异常

注解报错

这是为什么呢?其实,当我们自定义Anno1注解时,并没有告诉编译器该注解的使用范围和保留阶段。因此编译器无法读取到它。此时只需要在Anno1上添加一行@Retention(RetentionPolicy.RUNTIME)即可。

@Retention(RetentionPolicy.RUNTIME)
public @interface Anno1 {

    String name();
    int age();
}

注解使用

四、元注解

抽象的说,作用在注解上的注解就是元注解…上文Anno1中添加的@Rentention就是一个常见元注解。

常见的元注解如下:

  1. @Retention:

    表示被修饰的注解将要保留的阶段。它有三个取值

    • RententionPolicy.SOURCE:将保留至源码阶段。编译时将隐藏

    • RententionPolicy.CLASS:将保留至class文件阶段。但对运行对虚拟机隐藏

    • RententionPolicy.RUNTIME:可保留至运行时。

    一般我们都选择保留至RUNTIME

  2. @Document:表示被修饰的注解将会记入api文档

  3. @Inherited:表示被修饰的注解将会被自动继承

  4. @Target

    表示被修饰的注解将要被作用的位置。它有三个常见取值

    • ElementType.TYPE:可作用于类
    • ElementType.FIELD:可作用于成员变量
    • ElementType.METHOD:可作用于成员方法

五、简单框架实战

目标:简单模拟Aop,在一个类中定义三个方法,分别用自定义的@MyBefore、@MyTest、@MyAfter注解修饰,当执行被@MyTest标记的方法时,将自动执行前置和后置方法

1.自定义注解

@MyBefore

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyBefore {

}

@MyAfter

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyAfter {
    
}

@MyTest

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyTest {
    
}

2.测试类DaoTest.java

public class DaoTest {
    @MyBefore
    public void init(){
        System.out.println("init...");
    }
    @MyTest
    public void test(){
        System.out.println("test...");
    }
    @MyAfter
    public void destroy(){
        System.out.println("destroy...");
    }
    @MyTest
    public void eat(){
        System.out.println("now eating...");
    }
    @MyTest
    public void cook(){
        System.out.println("now cooking...");
    }
}

3.执行测试类Test.java

public class Test {
    public static void main(String[] args) throws InvocationTargetException, IllegalAccessException, InstantiationException {
		
        Class<DaoTest> daoTestClass = DaoTest.class;
        DaoTest obj = daoTestClass.newInstance();

        Method[] methods = daoTestClass.getMethods();

        List<Method> beforeMethodList = new ArrayList<>();
        List<Method> testMethodList = new ArrayList<>();
        List<Method> afterMethodList = new ArrayList<>();

        for(Method method:methods){
            if(method.isAnnotationPresent(MyBefore.class)){
                beforeMethodList.add(method);
            }
            if(method.isAnnotationPresent(MyTest.class)){
                testMethodList.add(method);
            }
            if(method.isAnnotationPresent(MyAfter.class)){
                afterMethodList.add(method);
            }
        }

        for(Method m:testMethodList){
            for(Method beforeMethod:beforeMethodList){
                beforeMethod.invoke(obj);
            }
            m.invoke(obj);
            for(Method afterMethod:afterMethodList){
                afterMethod.invoke(obj);
            }
        }

    }
}

4.执行结果

执行结果

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值