Java注解学习
java中我们经常要遇到各种注解,这些注解极大的方便了我们的开发。我们也就知道注解的原理好像也是一种接口和标志什么什么的,本质上说我们对JDK注解并不了解。所以理解JDK注解是我们java开发的基础。在spring中就大面积的使用了注解。所以理解这些基础的注解对于后期的开发都特别重要。
注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明。
根据注解没有没有参数可以将注解分为元数据和标记两种。
JDK自带注解
@Override 表示当前方法覆盖了父类的方法
@Deprecation 表示方法已经过时,方法上有横线,使用时会有警告。
@SuppviseWarnings 表示关闭一些警告信息(通知java编译器忽略特定的编译警告)
在实际开发中我们也需要自定义注解来实现一些功能。主要用来标记。
自定义注解声明的时候使用@interface
元注解
元注解是jdk提供给我们的基本注解,也是我们开发注解的基础。元注解有@Retention、@Target、@Document、@Inherited和@Repeatable
@Retention
是用来说明注解存在的阶段,java代码主要分为三个阶段。分别为源码、字节码和运行中。Retention就标记该注解在哪个阶段存在。
@Retention(RetentionPolicy.SOURCE),注解仅存在于源码中,在class字节码文件中不包含
@Retention(RetentionPolicy.CLASS), 默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得
@Retention(RetentionPolicy.RUNTIME), 注解会在class字节码文件中存在,在运行时可以通过反射获取到
如果我们是自定义注解,则通过前面分析,我们自定义注解如果只存着源码中或者字节码文件中就无法发挥作用,而在运行期间能获取到注解才能实现我们目的,所以自定义注解中肯定是使用 @Retention(RetentionPolicy.RUNTIME)
@Target
Target是用来表示注解的作用范围,可以是类、方法和属性等。
@Target(ElementType.TYPE) 作用接口、类、枚举、注解
@Target(ElementType.FIELD) 作用属性字段、枚举的常量
@Target(ElementType.METHOD) 作用方法
@Target(ElementType.PARAMETER) 作用方法参数
@Target(ElementType.CONSTRUCTOR) 作用构造函数
@Target(ElementType.LOCAL_VARIABLE)作用局部变量
@Target(ElementType.ANNOTATION_TYPE)作用于注解(@Retention注解中就使用该属性)
@Target(ElementType.PACKAGE) 作用于包
@Target(ElementType.TYPE_PARAMETER) 作用于类型泛型,即泛型方法、泛型类、泛型接口 (jdk1.8加入)
@Target(ElementType.TYPE_USE) 类型使用.可以用于标注任意类型除了 class (jdk1.8加入)
@Documented
用来说明是否有文档,这里的文档说的意思是通过javadoc命令生成的文档。
@Inherited
说明注解是否可以被继承
@Repeatable
用来说明注解是否可以重复修饰
注解属性类型
注解属性类型可以有以下列出的类型
1.基本数据类型
2.String
3.枚举类型
4.注解类型
5.Class类型
6.以上类型的一维数组类型
注解的属性的提取
注解的本质也是接口,对于有元数据的注解,在编译的时候会生成get方法,用来获取已经声明的值。因为我们代码的赋值操作都要经过set或者构造函数,因此对于注解来说。我们就必须通过class来检测注解和被修饰类的关系。然后通过反射获取值,然后再进行赋值操作。这样在代码运行起来的时候,我们通过注解设置的值就可以成为代码的一部分。
定义属性注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface MyField {
/***
* 属性
* @return
*/
String myName() default "默认名称";
}
定义方法注解
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface MyMethod {
/**
* value
* @return
*/
String value() default "测试";
/**
* 消息
* @return
*/
String message() default "测试消息";
}
定义类注解
@Target(ElementType.TYPE)
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface MyScaffold {
String value() default "类注解";
}
父类
@MyScaffold
public class Parent {
@MyMethod(value = "show",message = "测试")
public void show(String name,String message){
System.out.println("调用传入的值:"+name+"---"+message);
}
}
子类
public class Son extends Parent{
public String test="123";
/**
* 默认名称
*/
@MyField(myName = "默认名称")
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Son{" +
"test='" + test + ''' +
", name='" + name + ''' +
'}';
}
}
注解测试
public class TestAnnotation {
/***
* 初始化一个类
*/
static Parent parent=new Son();
/***
* 主函数
* @param args
*/
public static void main(String[] args) throws IntrospectionException, InvocationTargetException, IllegalAccessException, InstantiationException {
System.out.println("原来的实体:"+parent.toString());
/***
* 代码中通过判断传入的值和注解的值
* 决定使用的值
*/
showTEMP("123","123");
/***
* 类级别的注解判断
*/
classTEMP();
/***
* 属性注解操作
*/
fieldTEMP();
System.out.println("新的的实体:"+parent.toString());
}
private static void fieldTEMP() throws IntrospectionException, InvocationTargetException, IllegalAccessException, InstantiationException {
//创建一个新的son
//Object obj=Son.class.newInstance();
//获取公有和私有的属性
Field[] fields = Son.class.getDeclaredFields();
for (int i=0;i<fields.length;i++){
//抑制对private的检测
fields[i].setAccessible(true);
Object value=fields[i].get(parent);
MyField myField=fields[i].getAnnotation(MyField.class);
//如果默认传入的是空的
if (null!=myField&& StringUtils.isEmpty(value)){
fields[i].set(parent,myField.myName());
}else {
fields[i].set(parent, value);
}
}
}
/**
* 类级别注解
*/
private static void classTEMP(){
System.out.println("son类是myscaffold的子类吗?:"+Son.class.isAnnotationPresent(MyScaffold.class));
if (Son.class.isAnnotationPresent(MyScaffold.class)){
MyScaffold annotation=Son.class.getAnnotation(MyScaffold.class);
System.out.println("获取到的类注解:"+annotation.value());
System.out.println(annotation);
Annotation[] list=parent.getClass().getAnnotations();
System.out.println(list.toString());
}
}
/***
* 方法级别的注解方法
* @param s
* @param s1
*/
private static void showTEMP(String s, String s1) {
if (s.equals("123")){
System.out.println("方法");
Method[] list=parent.getClass().getMethods();
System.out.println(list.toString());
for (int i = 0; i < list.length; i++) {
if (list[i].getDeclaredAnnotations().length>0){
MyMethod annotations=list[i].getAnnotation(MyMethod.class);
if (null!=annotations){
Parameter[] parameters=list[i].getParameters();
System.out.println(parameters);
System.out.println("传入的值:"+s+"--"+s1);
parent.show(annotations.value(),annotations.message());
System.out.println("使用注解属性值:"+annotations.value()+"--"+annotations.message());
}
}
}
}
}
}
测试效果
- 初识字节流+实现缓冲字节流OutputStream的主要方法构造方法读关流实现BufferedInputStream实现BufferedOutputStream为什么read()返回的是Int型而不是
- Properties+重温Map+本地计数器Map方法Properties的方法用Properties的好处
- SequenceInputStreamSequenceInputStream构造方法读关流刷新
- 怎么实现关闭窗口
- java.io.StreamCorruptedException: invalid type code: AC错误的解决方法
- 不可不知的一点Python陷阱
- 10个应该早点知道的Python技巧
- 一文读懂如何用 Python 实现6种排序算法
- 5 个很好的 Python 面试题
- Python部署手记:django, gunicorn, virtualenv, circus, nginx
- Python图像处理库:Pillow 初级教程
- 陷阱!python参数默认值
- 怎么样才算是精通 Python?
- 教你一招 | Python实现无向图最短路径
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- springboot-mybatis-demo遇到的坑
- 快速学习-Sentinel 工作主流程
- 快速学习-Sentinel 流量控制
- 快速学习-Sentinel 熔断降级
- C#中关于SqlDataAdapter的Update(dataTable)方法
- Jmeter保存下载的文件
- SNAP Java API处理Sentinel-1数据
- springboot开发spark-submit的java代码
- Kustomize ConfigMapGenerate自动生成ConfigMap中的坑
- Godot游戏开发实践之二:AI之寻路新方式
- Vue 侦听器 watch 扩展之立即触发回调、深度监听和注销
- WPF开发之以管理员身份运行
- 快速学习-Sentinel: 分布式系统的流量防卫兵
- Godot游戏开发实践之一:使用High Level Multiplayer API制作多人游戏(上)
- Godot游戏开发实践之一:使用High Level Multiplayer API制作多人游戏(下)