当前位置: 首页 > news >正文

第十一章 注解

1、JDK预置注解

Deprecated

用来标记过时的元素,比如过时的类、过时的方法、过时的属性;

@Deprecated
public class AnnotationTest01 {public static void main(String[] args) {MyClass1 myClass1 = new MyClass1();System.out.println(myClass1.num);myClass1.doSome();}
}// 标注这个类已过时,不建议使用了
@Deprecated
class MyClass1 {// since属性值表示从哪个版本开始已过时。// forRemoval属性值如果是true表示已移除。@Deprecated(since = "9", forRemoval = true)public int num = 100;@Deprecatedpublic void doSome(){}
}

Override

修饰实例方法,则该方法必须是个重写方法,否则就会编译失败;

//@Override
public class AnnotationTest02 {//@Overridepublic static int num = 100;@Overridepublic boolean equals(Object obj){return false;}//@Overridepublic static void m(){}
}

SuppressWarnings(抑制警告的注解)

        @SuppressWarnings("rawtypes”):抑制未使用泛型的警告

        @SuppressWarnings("resource"):抑制未关闭资源的警告        

        @SuppressWarnings("deprecation”):抑制使用了已过时资源时的警告

        @SuppressWarnings("all"):抑制所有警告

@SuppressWarnings("all")
public class AnnotationTest03 {public static void main(String[] args) throws Exception{//@SuppressWarnings("rawtypes")List list = new ArrayList();//@SuppressWarnings("resource")FileInputStream in = new FileInputStream("e:/file.txt");        // 流没关//@SuppressWarnings("deprecation")MyClass1 myClass1 = new MyClass1();}
}

Functionalinterface: “函数式接口”的注解

使用@FunctionalInterface标注的接口,则该接口就有且只能存在一个抽象方法,否则就会发生编译错误。(注意:接口中的默认方法或静态方法可以有多个。)

/*** 关于Java内置注解:@FunctionalInterface*      1. 这个注解是专门用来标注接口的。*      2. 被标注的接口必须是一个  函数式接口,如果不是函数式接口,则编译器报错。*      3. 这个注解也是给编译器看的。*      4. 什么是函数式接口?*          如果这个接口中抽象方法只有一个(有且仅有一个)。称为函数式接口。*      5. 被 @FunctionalInterface 标注的接口中,允许有多个默认方法和静态方法。*/
public class AnnotationTest04 {
}@FunctionalInterface
interface Flyable {void fly();//void run();default void run(){System.out.println("默认方法是可以的");}static void doSome(){System.out.println("静态方法");}
}

2、自定义注解

  • 使用@interface来定义注解
  • 默认情况下注解可以出现在类上、方法上、属性上、构造方法上、方法参数上
/*** 自定义的注解。(以下这是注解的定义过程!!!!!)*/
public @interface MyAnnotation {
}/*** 以下是使用注解的过程!!!!!!*/
@MyAnnotation
public class AnnotationTest05 {@MyAnnotationprivate String name;@MyAnnotationpublic void doSome(){}public void doOther(@MyAnnotation String name, @MyAnnotation String password){}public void toDo(@MyAnnotationString name,@MyAnnotationString password){}
}

注解也可以定义属性

  • 注解也可以定义属性,不过属性定义时,属性名后面必须加一个小括号
  • 属性的类型只能是:

        byte,short,int,long,float,double,boolean,char

        String,Class,枚举类型、注解类型

        以上所有类型的一维数组形式

注解的使用

        注解在使用时必须给属性赋值,除非你使用了default关键字为属性指定了默认值。

        如果属性只有一个,并且属性名是value时,使用注解时value可以省略不写。

        如果属性是一个数组,使用注解时,数组值只有一个,数组的大括号是可以省略的。

注解使用示例(数据库信息)

public @interface DataBaseInfo {/*** 注解里也可以定义属性,但是属性定义时有要求,属性名后面必须添加:()* 语法:*      属性的类型 属性的名字();*/String driver() default "com.mysql.cj.jdbc.Driver"; // 使用 default 关键字来指定属性的默认值。String url();String user();String password();byte b() default 0;short s() default 0;int i() default 0;long l() default 0L;float f() default 0.0F;double d() default 0.0;boolean flag() default false;char c() default '0';Class clazz() default String.class;Season season() default Season.SPRING;MyAnnotation myAnnotation();/*** 可以是一维数组形式* @return*/String[] names();// 注解的属性的数据类型,必须是以上的几种类型,或者这几种类型的一维数组,不能是其他类型。// Object obj();
}
/*** 季节的枚举类型*/
public enum Season {SPRING, SUMMER, AUTUMN, WINTER
}

如果注解中有属性,那么使用的时候,必须给属性赋值,没有赋值则报错;

除非定义注解的时候给属性指定了默认值;

怎么给属性赋值?

语法:@DataBaseInfo(属性名=值,属性名=值,属性名=值,属性名=值,属性名=值)

public class AnnotationTest06 {// 语法规则:如果这个注解中有属性,那么使用的时候,必须给属性赋值。没有赋值则报错。// 除非你定义注解的时候给属性指定了默认值。// 怎么给属性赋值?语法:@DataBaseInfo(属性名=值,属性名=值,属性名=值,属性名=值,属性名=值)@DataBaseInfo(//driver="oracle.jdbc.driver.OracleDriver",url="jdbc:mysql://localhost:3306/powernode",user="root",password="123456",myAnnotation=@MyAnnotation,names={"zhangsan", "lisi", "wangwu"},flag=true,i=100,clazz=Integer.class,season=Season.WINTER)public void connDB(){}}

注解使用实例(Ⅱ)

public @interface Table {/*** 有一个属性,并且这个属性的名字是value*///String value();String[] value();
}
//@Table(value="t_user")
// 如果属性名是value的话, 在使用注解的时候,该属性名可以省略。
//@Table("t_user")//@Table(value={"t_user1", "t_user2"})
// value可以省略。
//@Table({"t_user1", "t_user2"})
//@Table({"t_user"})@Table("t_user")
public class AnnotationTest07 {@SuppressWarnings("all")public static void main(String[] args) {}
}

3、元注解

用来标注注解的注解叫做元注解。

常用的元注解

@Retention:设置注解的保持性

① Retention英文意思有保留、保持的意思,它表示注解存在阶段是保留在源代码(编译期),字节码(类加载)或者运行时(JVM中运行)。

② 在@Retention注解中使用枚举RetentionPolicy来表示注解保留时期。
        @Retention(RetentionPolicy.SOURCE):注解仅存在于源代码中,在字节码文件中不包含。
        @Retention(RetentionPolicy.CLASS):注解在字节码文件中存在,但运行时无法获得(默认)。
        @Retention (RetentionPolicy.RUNTIME):注解在字节码文件中存在,且运行时可通过反射获取。

// @Retention(value = RetentionPolicy.SOURCE) // @MyAnnotation 注解保留在源码中。
// @Retention(value = RetentionPolicy.CLASS) // @MyAnnotation 注解保留在字节码中,这是默认的行为,但不能被反射。
// @Retention(value = RetentionPolicy.RUNTIME) // @MyAnnotation 注解保留在字节码中,并且在运行时可以被反射。@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {}

@Target:设置注解可以出现的位置

用于描述注解可以使用的位置,该注解使用ElementType枚举类型用于描述注解可以出现的位置,ElementTyep有如下枚举值:

@Target(ElementType.TYPE): 作用于接口、类、枚举、注解
@Target(ElementType.FIELD): 作用于属性、枚举的常量
@Target(ElementType.METHOD): 作用于方法
@Target(ElementType.PARAMETER): 作用于方法参数
@Target(ElementType.CONSTRUCTOR): 作用于构造方法
@Target(ElementType.LOCAL VARIABLE): 作用于局部变量
@Target(ElementType.ANNOTATION TYPE): 作用于注解
@Target(ElementType.PACKAGE): 作用于包
@Target(ElementType.TYPE PARAMETER): 作用于泛型,即泛型方法、泛型类和泛型接口。
@Target(ElementType.TYPE USE):作用于任意类型。

//@Target(value={ElementType.METHOD})
//@Target(ElementType.METHOD) // 限定注解只能出现在方法上@Target({ElementType.METHOD, ElementType.TYPE, ElementType.FIELD})
public @interface MyAnnotation {}
@MyAnnotation
public class Test {@MyAnnotationint num = 100;@MyAnnotationpublic static void main(String[] args) {}
}

 @Documented:设置注解是否可以生成到帮助文档中

使用javadoc.exe工具可以从程序源代码中抽取类、方法、属性等注释形成一个源代码配套的API帮助文档,而该工具抽取时默认不包括注释内容。

@Inherited:设置注解是否支持继承

继承,一个被@Inherited注解了的注解修饰了一个父类,则它的子类也继承了父类的注解

@Retention(RetentionPolicy.RUNTIME)
@Inherited // 表示 @MyAnnotation注解能够被继承
public @interface MyAnnotation {}@MyAnnotation
public class Animal {
}public class Cat extends Animal{
}
public class Test {public static void main(String[] args) {Class<Cat> catClass = Cat.class;System.out.println(catClass);   // class com.powernode.javase.annotation.meta3.CatMyAnnotation annotation = catClass.getAnnotation(MyAnnotation.class);System.out.println(annotation);     // @com.powernode.javase.annotation.meta3.MyAnnotation()}
}

@Repeatable:设置注解在某一个元素上是否可以重复使用 

Repeatable表示可重复的含义,该注解属于JDK1.8版本的新特性。

@Repeatable(Authors.class)
public @interface Author {/*** 作者的名字* @return 作者的名字*/String name();
}public @interface Authors {Author[] value();}
public class Test {@Author(name = "张三")@Author(name = "李四")public void doSome(){}}

反射

@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})      // 注解可以应用于类(ElementType.TYPE)、字段(ElementType.FIELD)和方法
@Retention(RetentionPolicy.RUNTIME)     // 注解在运行时(RetentionPolicy.RUNTIME)保留,因此可以通过反射读取
@Inherited      // 该注解可以被继承(如果父类使用了该注解,子类也会继承该注解)
@Documented
public @interface Annotation1 {String name() default "";int age() default 0;}
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Annotation2 {String email() default "";double price() default 0.0;
}
@Annotation1(name="zhangsan22222", age=3333)
@Annotation2(email="zhangsan@123.com", price = 3000.5)
public class MyClass {@Annotation1@Annotation2String s;@Annotation1@Annotation2public void doSome(){System.out.println("name = " + s);}}
public class Test {public static void main(String[] args) throws Exception {// 获取类Class<MyClass> mcClass = MyClass.class;             // 获取MyClass类的Class对象// 获取类上的所有注解Annotation[] annotations = mcClass.getAnnotations();for(Annotation a : annotations){System.out.println(a);}// 获取指定注解// 判断该类上是否存在这个注解if(mcClass.isAnnotationPresent(Annotation1.class)){         // 检查MyClass类上是否存在Annotation1注解// 获取指定的某个注解Annotation1 a1 = mcClass.getAnnotation(Annotation1.class);// 访问注解对象中的属性System.out.println(a1.name());System.out.println(a1.age());}if(mcClass.isAnnotationPresent(Annotation2.class)){Annotation2 a2 = mcClass.getAnnotation(Annotation2.class);  // 获取注解实例System.out.println(a2.email());System.out.println(a2.price());}// 通过反射获取doSome方法上的Annotation1注解// 1. 获取指定方法对象(需要方法名和参数类型)Method doSomeMethod = mcClass.getMethod("doSome");      // 通过反射获取MyClass类中名为doSome且无参数的方法对象// 2. 检查方法上是否存在Annotation1if(doSomeMethod.isAnnotationPresent(Annotation1.class)){      // 检查该方法上是否存在Annotation1注解Annotation1 a3 = doSomeMethod.getAnnotation(Annotation1.class);     // 获取该注解的实例a3System.out.print("方法上的Annotation1:" + a3);}}
}

 获取注解

// 1、获取类上的所有注解
Annotaion[] annotations = clazz.getAnnotations();// 2、获取类上指定的某个注解  用于检查类上是否存在指定的注解 AnnotationTest01
clazz.isAnnotationPresent(AnnotationTest01.class);   
// 返回该类上指定类型的注解对象
AnnotationTest01 an = clazz.getAnnotation(AnnotationTest01.class);// 3、获取属性上的所有注解
// 类中的一个属性(成员变量);返回该属性上所有注解(不包括继承的,因为属性不能从父类继承注解)
Annotation[] annotations = field.getAnnotations();// 4、获取属性上指定的某个注解
field.isAnnotationPresent(AnnotationTest02.class)
// 属性上是否有AnnotationTest02注解
AnnotationTest02 an = field.getAnnotation(AnnotationTest02.class);// 5、获取方法上的所有注解
Annotation[] annotations = method.getAnnotations();// 6、获取方法上指定的某个注解
method.isAnnotationPresent(AnnotationTest02.class)
AnnotationTest02 an = method.getAnnotation(AnnotationTest02.class);

4、扫描包的类

        编写程序扫描一个包下所有的类,凡是被@Table注解标注的类都要生成一条建表语句,表名在@Table注解中指定。被@Table标注的类中的属性被@Column注解标注,在@Column注解中描述字段的名称和字段的数据类型。

ViP表

@Table("t_vip")
public class Vip {@Column(name = "id")private String id;//@Column(name = "name")private String name;//@Column(name = "grade")private String grade;
}

User表

@Table("t_user")
public class User {@Column(name = "uid")private String userid;@Column(name = "uname")private String username;@Column(name = "pwd")private String password;@Column(name = "age", type = "int")private int age;private String email;       // 不加注解就不能参与建表
}

Table注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Table {/*** 用来指定表的名字* @return 表的名字*/String value();
}

Column注解

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {/*** 字段的名字* @return 字段的名字*/String name();/*** 字段的数据类型* @return 字段的数据类型*/String type() default "varchar";
}

生成建表语句

public class Test {private static String classpathRoot;private static StringBuilder sb = new StringBuilder();public static void main(String[] args) {// 扫描类路径当中所有的文件,找到所有的.class结尾的文件// 通过.class文件的路径找到对应的全限定类名(全限定类名是带包名的。)classpathRoot = Thread.currentThread().getContextClassLoader().getResource(".").getPath();//System.out.println("类路径的根:" + classpathRoot);// 创建File对象File file = new File(classpathRoot);// 调用方法来生成建表语句generateCreateStatement(file);System.out.println(sb);}/*** 通过这个方法,来生成建表语句** @param file 起初的这个file代表的是类的根目录*/private static void generateCreateStatement(File file) {if (file.isFile()) { // file是一个文件的时候,递归结束//System.out.println(file.getAbsolutePath());String classFileAbsolutePath = file.getAbsolutePath();if (classFileAbsolutePath.endsWith(".class")) {// 程序执行到这里,表示文件一定是一个字节码文件//System.out.println(classFileAbsolutePath);String className = classFileAbsolutePath.substring(classpathRoot.length() - 1, classFileAbsolutePath.length() - ".class".length()).replace("\\", ".");//System.out.println(className);try {// 获取类Class<?> clazz = Class.forName(className);// 判断类上面是否有@Table注解if(clazz.isAnnotationPresent(Table.class)){Table tableAnnotation = clazz.getAnnotation(Table.class);// 获取到表的名字String tableName = tableAnnotation.value();System.out.println(tableName);sb.append("create table ");sb.append(tableName);sb.append("(");// 获取所有的属性Field[] fields = clazz.getDeclaredFields();for(Field field : fields){// 判断字段上是否存在 @Column 注解if(field.isAnnotationPresent(Column.class)){Column columnAnnotation = field.getAnnotation(Column.class);// 字段名String columnName = columnAnnotation.name();System.out.println(columnName);sb.append(columnName);sb.append(" ");// 字段的类型String columnType = columnAnnotation.type();System.out.println(columnType);sb.append(columnType);sb.append(",");}}// 删除当前sb中的最后一个逗号sb.deleteCharAt(sb.length() - 1);sb.append(");\n");}} catch (Exception e) {throw new RuntimeException(e);}}return;}File[] files = file.listFiles();for (File f : files) {//System.out.println(f.getAbsolutePath());generateCreateStatement(f);}}
}

http://www.xdnf.cn/news/791767.html

相关文章:

  • AI数据集构建:从爬虫到标注的全流程指南
  • 使用ArcPy生成地图系列
  • 0518蚂蚁暑期实习上机考试题3:小红的字符串构造
  • 如何爬取google应用商店的应用分类呢?
  • Java-redis实现限时在线秒杀功能
  • 【RAG最新总结】检索增强生成最新进展2024-2025
  • 解决FreePBX 17初始配置时网页无响应
  • CCF CSP 第37次(2025.03)(3_模板展开_C++)(哈希表+stringstream)
  • 【AI学习从零至壹】基于深度学习的⽂本分类任务
  • C++算法训练营 Day6 哈希表(1)
  • 《仿盒马》app开发技术分享-- 个人中心关于逻辑完善(端云一体)
  • Java 文件操作 和 IO(5)-- 综合案例练习 -- 示例三
  • 移动端测试岗位高频面试题及解析
  • 左值引用和右值引用
  • 【C++篇】STL适配器(下篇):优先级队列与反向迭代器的底层奥秘
  • Splitting Items
  • torch.nn中的各种组件
  • element级联地址选择器
  • java类的生命周期
  • Make All Equal
  • 2.2.2 06年T3
  • LeetCode 152. 乘积最大子数组 - 动态规划解法详解
  • 集成学习三种框架
  • C++中的指针参数传递与引用参数传递详解
  • 5985/wsman 是什么?
  • 一、基础环境配置
  • Linux中实现用户态DMA直通访问的零拷贝机制
  • 《Spring Bean 是怎么被创建出来的?容器启动流程全景分析》
  • 小体积涵盖日常办公等多功能的软件
  • MyBatis实战项目测试