38_Java中的注解

java中的注解

1、注解概述

@Ovrride:用来修饰方法,表示该方法是重写父类的方法,如果不是,就会报错

注解(Annotation):也叫元数据,一种代码级别的说明,它是JDK1.5及以后版本引入的一个特性

它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明

JDK1.5之后的新特性

说明程序的

注解和注释:

​ 注解:用来说明程序,给计算机看的

​ 注释:用来对程序进行说明性的文字,给程序员看的

Java中常见的几个注解:

​ @Override

​ @Deprecated

​ @SuppressWarnings

​ @FunctionalInterface

@Override

​ 用于指定方法是否重写父类的方法,只能修饰方法,不能够修饰其它元素

​ 单独来看,可能丝毫看不出程序中@Override有何作用,因为他的作用是告诉编译器检查这个方法,保证父类要包含一个被该方法重写的方法

@Deprecated

​ 用于表示某个程序元素(类、方法等)已过时,当其它程序使用已过时的类、方法时,编译器将会给出警告

​ Java 9 为@Deprecated增加了两个属性:

​ since:该String类型的属性指定该API从哪个版本被标记为过时

​ forRemoval:该boolean类型的属性指定该API在将来事发后会被删除

@SuppressWarnings

​ 指示被该注解修饰的程序元素(以及该程序元素中的所有子元素)取消显示指定的编译器警告

​ 使用注解来关闭编译器警告时,一定要在括号里使用 name = value 的形式为该注解的成员变量设置值

​ @SuppressWarnings(value = "all")

@FunctionalInterface

​ Java 8 新增的,只能用来修饰接口,表示该接口是一个函数式接口

​ 函数式接口:接口中有且仅有一个抽象方法

​ Lambda表达式的使用前提:接口中有且仅有一个抽象方法

参考代码:

package com.itheima_01;

public class Fu {
    public void show(){
        System.out.println("fu show");
    }

    @Deprecated
    public void method(){
        System.out.println("fu method");
    }
}
package com.itheima_01;

public class Zi extends Fu{
    @Override
    public void show(){
        System.out.println("zi show");
    }
}
package com.itheima_01;

@FunctionalInterface
public interface Inter {
    void show();

//    void show2();
}
package com.itheima_01;

import java.util.ArrayList;
import java.util.List;

/*
    测试类
 */
//@SuppressWarnings(value = "all")  用于取消编译器检查

public class Test {
    public static void main(String[] args){
        Fu f = new Fu();
        f.method(); //被标记的方法在调用处显示过时

//        @SuppressWarnings(value = "all")
        List<String> list = new ArrayList();
    }
}
2、元注解:

对注解进行注解。也就是写在注解上面的注解。

两个常用的元注解:

​ @Retention

​ @Target

可以通过跟进@Deprecated、@Override查看

@Retention(表示注解存在的位置:class文件、源代码)

​ 只能用于修饰注解定义,用于指定被修饰的注解可以保留多长时间

​ 包含了一个RetentionPolicy类型的value成员变量,所以使用的@Retention时必须为该value成员变量指定

@Retention中可以使用的值定义在RetentionPocily中,常用值如下:

​ RetentionPolicy.CLASS:编译器把注解记录在class文件中,当运行Java程序时,JVM不可获取注解信息,这是默认值

​ RetentionPolicy.RUNTIME:编译器把注解记录在class文件中,当运行Java程序时,JVM也可以获取注解信息,开发中常用

​ RetentionPolicy.SOURCE:注解只保留在源代码中,编译器直接丢弃这种注解

@Target(表示注解修饰的对象如:接口、类、方法等等等)

​ 只能用于修饰注解定义,用于指定被修饰的注解能用于修饰哪些程序单元,包含一个名为value的成员变量

@Target中可以使用的值定义在ElementType中,常用值如下:

​ @Target(ElementType.TYPE):可以用于接口、类、枚举、注解

​ @Target(ElementType.FIELD):可以用于属性字段、枚举的常量

​ @Target(ElementType.METHOD):可以用于方法

​ @Target(ElementType.PARAMETER):可以用于方法参数

​ @Target(ElementType.CONSTRUCTOR):可以用于构造函数

​ @Target(ElementType.LOCAL_VARIABLE):可以用于局部变量

3、自定义注解:

定义格式:

元注解

public @interface 注解名称{

​ 属性列表;

}

注解的本质:

public Interface MyAnnotation extends Annotation{}

​ 是一个接口,该接口默认继承Annotation接口

​ 既然是接口,那么内部定义的内容,就是接口中可以定义的内容

注解的属性:

​ 属性:接口中的抽象方法

​ 格式:返回值类型 属性名()[default 默认值]

注解属性类型可以有以下列出的类型:

​ 基本数据类型

​ String

​ 枚举类型

​ 注解类型

​ Class类型

​ 以上类型的一维数组类型

参考代码:

package com.itheima_02;

//@interface 表示定义一个注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyAnnotation {
    /*
        无参无返回值的方法:void show();
        无参带返回值的方法:String show();

        注解中定义属性也是这样的格式:
            返回值类型 属性名()
     */

    //定义两个属性
    String name() default "fqy";
    int age();
}
4、注解的使用和解析:

使用注解:

​ 如果注解有多个属性,则可以在注解括号中用 “,” 号隔开分别给对应的属性赋值

​ 如果定义属性时,使用default关键字给属性默认初始化值,则使用注解时,可以不进行属性的赋值

​ 如果只有一个属性需要赋值,并且属性的名称时value,则value可以省略,直接定义值即可

​ 数组赋值时,值使用{}包裹。如果数组中只有一个值,则{}可以省略

参考代码:

package com.itheima_03;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyAnnotation {
//    String name() default "zs";    //表示默认值为zs,使用时可以不用给此属性赋值
//
//    int age();

//    String value(); //当注解中只有一个属性需要赋值,且此属性为value时可以直接定义值

    String[] names();
}
package com.itheima_03;

//@MyAnnotation(name = "张三", age = 36)    //注解的多个属性使用,隔开
//@MyAnnotation(age = 36)
//@MyAnnotation("好好学习天天向上")   //@MyAnnotation(value = "好好学习天天向上")
//@MyAnnotation(names = {"张三", "李四", "王五", "赵六"})
@MyAnnotation(names = "张三") //属性为数组时,只有一个值大括号可以省略
public class MyAnnotationTest {

}

解析注解:

​ 获取字节码文件对象,获取谁的呢?谁使用了注解,就是获取谁的

​ Class c = MyAnnotationTest.class;

​ 获取字节码对象上的注解信息

​ MyAnnotation annotation = c.getAnnotation(MyAnnotation.class);

​ 解析注解

​ String name = annotation.name();

​ int age = annotation.age();

参考代码:

package com.ithiema_04;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyAnnotation {
    String name() default "zs";    //表示默认值为zs,使用时可以不用给此属性赋值

    int age();
}
package com.ithiema_04;

//@MyAnnotation(age = 36)
@MyAnnotation(name = "张三", age = 30)
public class MyAnnotationTest {
    public static void main(String[] args){
        //!!!通过反射解析注解
        //先获取使用注解类的class文件
        //再通过一个方法传入使用注解的class文件,来创建对应的注解对象,在获取其属性对应的值

        //获取字节码文件对象,谁使用了注解就获取谁的字节码文件
        Class<MyAnnotationTest> c = MyAnnotationTest.class;

        //通过字节码文件对象获取注解信息
        MyAnnotation myAnnotation = c.getAnnotation(MyAnnotation.class);

        //通过注解的属性获取对应的值
        String name = myAnnotation.name();
        int age = myAnnotation.age();

        System.out.println(name + "," + age);
    }
}

案例:框架通用技术:

需求:通过注解,运行指定类中的指定方法

参考代码:

package com.itheima_05;

public class Student {
    public void study(){
        System.out.println("好好学习天天向上");
    }
}
package com.itheima_05;

public class Teacher {
    public void teach(){
        System.out.println("用爱成就学员");
    }
}
package com.itheima_05;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/*
    定义一个注解
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyAnnotation {
    String className();
    String methodName();
}
package com.itheima_05;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/*
    通过注解来运行指定类中的指定方法
 */

//运行某个类中的某个方法,只需要来修改这里的内容即可
//@MyAnnotation(className="com.itheima_05.Student",methodName="study")
@MyAnnotation(className="com.itheima_05.Teacher",methodName="teach")
public class MyAnnotationTest {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //!!!通过注解来获取类名和方法名

        //获取class文件对象,谁使用了注解就获取谁的
        Class<MyAnnotationTest> myAnnotationTestClass = MyAnnotationTest.class;
        //通过字节码文件对象创建注解对象
        MyAnnotation myAnnotation = myAnnotationTestClass.getAnnotation(MyAnnotation.class);

        //通过注解对象获取属性值
        String className = myAnnotation.className();
        String methodName = myAnnotation.methodName();

        //以下部分为反射机制:即通过class字节码文件创建Class对象,再通过Class对象创建实例化对象,在调用其中的方法
        //通过类名反射得到Class对象
        Class<?> c = Class.forName(className);  //com.ithiema_06.Student

        //通过Class对象创建一个对象
        Constructor<?> con = c.getConstructor();
        Object obj = con.newInstance();

        //通过Class得到方法
        Method m = c.getMethod(methodName);//study

        //调用方法
        m.invoke(obj);
    }
}
posted @ 2023-01-07 10:18  如此而已~~~  阅读(18)  评论(0编辑  收藏  举报