【Java】注解入门
本文作为注解的入门文章,主要向读者介绍注解的基本概念与用法,目的还是能够看懂JDK源代码的注解相关代码。
主要内容有:初步了解一下注解的定义;JDK提供的注解;自己写一个注解;用于自己写注解时用的注解(元注解);JDK在运行时如何解析注解的;
目录
什么是注解
预置注解
自定义注解
定义注解
注解属性
元注解
@Retention
@Target
@Documented
@Inherited
@Repeatable
注解的解析
什么是注解
对注解的理解:
- 就像是对人贴上了一个标签。吴小明这个人是个理想主义者、单身狗、技术宅。
- 对类或方法贴上一个标签。某方法是Override、Deprecated、SuppressWarnings。
一般概念:说明程序,是给计算机看的。和注释的区别是,注释是用文字描述程序的,给程序员看的。
注解的定义:
- 注解(Annotation),也叫元数据。一种代码级别的说明。
- 用在类上,方法上,成员变量,构造器,...上对成分进行编译约束,标记等操作的。
简单认识:
- 它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。
- 像一种修饰符一样,它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。
- 注解是给编译器或JVM看的,编译器或JVM可以根据注解来完成对应的功能。
注解的功能:
- 使用注解:@注解名称
- 为程序的元素(类、方法、成员变量)加上更直观更明了的说明,这些说明信息是与程序的业务逻辑无关,并且供指定的工具或框架使用。
- 注解不会也不能影响代码的实际逻辑,仅仅起到辅助性的作用。包含在java.lang.annotation包中。
- 简单来说:注解其实就是代码中的特殊标记,这些标记可以在编译、类加载、运行时被读取,并执行相对应的处理。
注解的本质:
- 元注解的格式:public @interface 注解名 { }
- 本质是一个接口,该接口默认继承Annotation接口:
public interface 注解名 extends java.lang.annotation.Annotion {}
Java预定义注解:
- @Override:检测被该注解标注的方法是否是继承自父类(接口)的;
- @Deprecated:该注解标注的内容,表示已过时;
- @SuppressWarnings():压制警告,一般传递参数all;
作用分类:
- 编写文档:通过代码里标识的注解生成文档【生成文档doc文档】
- 代码分析:通过代码里标识的注解对代码进行分析【使用反射】
- 编译检查:通过代码里标识的注解让编译器能够实现基本的编译检查【Override】
预置注解
在 java.lang 包下存在着5个基本的 Annotation
@Deprecated
发出提醒警告,告诉开发者正在调用一个过时的元素比如过时的方法、过时的类、过时的成员变量。
使用示例:
public class Hero {@Deprecatedpublic void say(){System.out.println("Noting has to say!");}public void speak(){System.out.println("I have a dream!");}
}
@Override
这个大家应该很熟悉了,提示子类要复写父类中被 @Override 修饰的方法。
@SuppressWarnings
阻止警告的意思。之前说过调用被 @Deprecated 注解的方法后,编译器会警告提醒,而有时候开发者会忽略这种警告,他们可以在调用的地方通过 @SuppressWarnings 达到目的。
@SuppressWarnings("deprecation")
public void test1(){Hero hero = new Hero();hero.say();hero.speak();
}
@SafeVarargs
参数安全类型注解。它的目的是提醒开发者不要用参数做一些不安全的操作,它的存在会阻止编译器产生 unchecked 这样的警告。它是在 Java 1.7 的版本中加入的。
@SafeVarargs // Not actually safe!
static void m(List<String>... stringLists) {Object[] array = stringLists;List<Integer> tmpList = Arrays.asList(42);array[0] = tmpList; // Semantically invalid, but compiles without warningsString s = stringLists[0].get(0); // Oh no, ClassCastException at runtime!
}
上面的代码中,编译阶段不会报错,但是运行时会抛出 ClassCastException 这个异常,所以它虽然告诉开发者要妥善处理,但是开发者自己还是搞砸了。Java 官方文档说,未来的版本会授权编译器对这种不安全的操作产生错误警告。
自定义注解
定义注解
语法格式:
修饰符 @interface 注解名{
// 注解属性
}
特性:
- 所有的自定义 Annotation 会自动继承 java.lang.Annotation 这一接口,并且不能再去继承别的类或是接口.
- 参数成员只能用 public 或默认(default)这两个访问权修饰
- 参数成员只能用基本类型 byte, short, char, int, long, float, double, boolean 八种基本数据类型和 String、Enum、Class、annotations 等数据类型,以及这一些类型的数组
- 要获取类方法和字段的注解信息,必须通过 Java 的反射技术来获取 Annotation 对象,因为你除此之外没有别的获取注解对象的方法
- 注解也可以没有定义成员, 不过这样注解就没啥用了。此外,自定义注解需要使用到元注解;
第一个注解实例
@FirstAnnotation //注解可以用在类上
public class Main {@FirstAnnotation //可以用在方法上public static void main(@FirstAnnotation String[] args) { //可以用在参数上@FirstAnnotation //可以用在变量上int a = 10;}
}@interface FirstAnnotation {}
注解属性
格式:
修饰符 @interface 注解名{
// 注解属性
}
注解属性
- 格式1:数据类型 属性名();
- 格式2:数据类型 属性名() default 默认值;
特性:
- 注解可以有属性,属性名必须带()
- 在用注解的时候,属性必须赋值,除非这个属性有默认值!!
第一个注解属性实例
@MyBook(name="《Java基础》",authors = {"aa","bb","cc"} , price = 99.9 )
public class AnnotationDemo01 {@MyBook(name="《MySQL数据库入门到删库跑路》",authors = {"小白","小黑"} ,price = 19.9 , address = "北京")public static void main(String[] args) {}
}// 自定义一个注解
@interface MyBook{String name();String[] authors(); // 数组double price();String address() default "广州";
}
特殊属性:
- value属性,如果只有一个value属性的情况下,使用value属性的时候可以省略value名称不写!
- 但是如果有多个属性,且多个属性没有默认值,那么value是不能省略的。
特殊属性
public class Main {@Annotation01("01") //等价于@Annotation01(value="01")public void test01() {}//但是如果有多个属性,且多个属性没有默认值,那么value是不能省略的。@Annotation02(value = "02", str = "02")public void test02() {}//但是如果有多个属性,且多个属性没有默认值,那么value是不能省略的。@Annotation03("03")public void test03() {}
}@interface Annotation01 {String value(); //value属性,如果只有一个value属性的情况下,使用value属性的时候可以省略value名称不写!
}
@interface Annotation02 {String value();String str();
}
@interface Annotation03 {String value();String str() default "003";
}
元注解
理解元注解:
- 元注解也是一张标签,但是它是一张特殊的标签,它的作用和目的就是给其他普通的标签进行解释说明的。
- 即,元注解是用在自定义注解上的注解
元标签有 @Retention、@Documented、@Target、@Inherited、@Repeatable 5 种。
@Retention
功能:
- 申明注解的生命周期
- 申明注解的作用范围:编译时,运行时。
它的取值如下:
- RetentionPolicy.SOURCE 注解只在源码阶段保留,在编译器进行编译时它将被丢弃忽视。
- RetentionPolicy.CLASS 注解只被保留到编译进行的时候,它并不会被加载到 JVM 中。
- RetentionPolicy.RUNTIME 注解可以保留到程序运行的时候,它会被加载进入到 JVM 中,所以在程序运行时可以获取到它们。
使用示例:
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {方法体
}
@Target
功能:
- 默认的注解可以在类,方法,构造器,成员变量,... 使用。
- 约束自定义注解只能在哪些地方使用
@Target 有下面的取值:
- ElementType.ANNOTATION_TYPE 可以给一个注解进行注解
- ElementType.CONSTRUCTOR 可以给构造方法进行注解
- ElementType.FIELD 可以给属性进行注解
- ElementType.LOCAL_VARIABLE 可以给局部变量进行注解
- ElementType.METHOD 可以给方法进行注解
- ElementType.PACKAGE 可以给一个包进行注解
- ElementType.PARAMETER 可以给一个方法内的参数进行注解
- ElementType.TYPE 可以给一个类型进行注解,比如类、接口、枚举
实例:
@Target({ElementType.METHOD , ElementType.FIELD}) // 申明只能注解方法和成员变量!
// @Target(ElementType.METHOD ) // 申明只能注解方法
@interface MyTest{
}
@Documented
顾名思义,这个元注解肯定是和文档有关。它的作用是能够将注解中的元素包含到 Javadoc 中去。
@Inherited
Inherited 是继承的意思,但是它并不是说注解本身可以继承,而是说如果一个超类被 @Inherited 注解过的注解进行注解的话,那么如果它的子类没有被任何注解应用的话,那么这个子类就继承了超类的注解。
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@interface Test {}@Test
public class A {}public class B extends A {}注解 Test 被 @Inherited 修饰,之后类 A 被 Test 注解,类 B 继承 A,类 B 也拥有 Test 这个注解。
可以这样理解:
- 老子非常有钱,所以人们给他贴了一张标签叫做富豪。
- 老子的儿子长大后,只要没有和老子断绝父子关系,虽然别人没有给他贴标签,但是他自然也是富豪。
- 老子的孙子长大了,自然也是富豪。
- 这就是人们口中戏称的富一代,富二代,富三代。虽然叫法不同,好像好多个标签,但其实事情的本质也就是他们有一张共同的标签,也就是老子身上的那张富豪的标签。
@Repeatable
Repeatable 自然是可重复的意思。@Repeatable 是 Java 1.8 才加进来的,所以算是一个新的特性。
什么样的注解会多次应用呢?通常是注解的值可以同时取多个。
举个例子,一个人他既是程序员又是产品经理,同时他还是个画家。
@interface Persons {Person[] value();
}@Repeatable(Persons.class)
@interface Person{String role default "";
}@Person(role="artist")
@Person(role="coder")
@Person(role="PM")
public class SuperMan{}
注意上面的代码,@Repeatable 注解了 Person。而 @Repeatable 后面括号中的类相当于一个容器注解。
什么是容器注解呢?就是用来存放其它注解的地方。它本身也是一个注解。
注解的解析
功能:
- 对于一个类,我们需要知道这个类到底用了哪些注解。
- 并且获取到注解中的值。
AnnotatedElement接口定义了与注解解析相关的方法
所有的类成分Class, Method , Field , Constructor:都实现了AnnotatedElement接口,则他们都拥有解析注解的能力:
- Annotation[] getDeclaredAnnotations() 获得当前对象上使用的所有注解,返回注解数组。
- T getDeclaredAnnotation(Class<T> annotationClass) 根据注解类型获得对应注解对象
- boolean isAnnotationPresent(Class<Annotation> annotationClass) 判断当前对象是否使用了指定的注解,如果使用了则返回true,否则false
解析注解数据的原理:
比如注解作用成员方法,则要获得该成员方法对应的Method对象,再来拿上面的注解
比如注解作用在类上,则要该类的Class对象,再来拿上面的注解
比如注解作用在成员变量上,则要获得该成员变量对应的Field对象,再来拿上面的注解
总结
什么是注解:给代码打个标签,说明它是一类什么样的代码;
什么是预置注解,它们都是干什么的:JDK提供的,可以直接使用的注解,对代码进行标记,例如@Override标明这个函数是重写父类中的同名函数的。
自定义注解:自己写一个注解。
元注解:用在自己写注解时用到的注解。
注解的解析:自己编写的注解时怎么解析的,看懂JDK注解的解析。
引用、参考资料:
- Java核心技术(卷一)
- 黑马程序员
【Java】注解入门相关推荐
- java 注解入门 简书_Java基础-注解
注解是什么? Java注解(Annotation)又称为Java标注.可以从字面的意思理解它,其实就是一个标注.他可以根据定义作用于不同的地方.注解对他们注解的代码没有直接影响.注解是JDK 5中引入 ...
- java 注解入门 简书_Java注解入门
Java注解(Annotation) 0.0 Hello World 先上代码,再加以说明.这样不至于让初学者懵. 例1 public class Dog extends Animal(){ @Ove ...
- java annotation入门_JAVA - Annotation 注解 入门
Java注解提供了关于代码的一些信息,但并不直接作用于它所注解的代码内容.在这个教程当中,我们将学习Java的注解,如何定制注解,注解的使用以及如何通过反射解析注解. Java1.5引入了注解,当前许 ...
- java从入门到精通_想要开始学java?你要的java从入门到精通布列如下!
java从入门到精通,让我来告诉你! 毫无疑问,java是当下最火的编程语言之一.对于许多未曾涉足计算机编程的领域「小白」来说,深入地掌握java看似是一件十分困难的事.其实,只要掌握了科学的学习方法 ...
- 深入理解 Java 注解
本文内容基于 JDK8.注解是 JDK5 引入的,后续 JDK 版本扩展了一些内容,本文中没有明确指明版本的注解都是 JDK5 就已经支持的注解. :notebook: 本文已归档到:「blog」 : ...
- Java 注解深入理解
内容概要 Annotation的概念 Annotation的作用 Annotation的分类 系统内置注解 元注解 自定义注解 解析注解信息 JDK8注解新特性 附:项目源码地址 一.Annotati ...
- swagger 怎么去掉get delete_自学 Java 怎么入门?
给你推荐一个写得非常用心的Java基础教程:码邦主2020年最新的Java视频教程 这个教程将Java的入门基础知识贯穿在一个实例中,逐步深入,可以帮助你快速进入Java编程的世界.万事开头难,逐步跟 ...
- Java 从入门到高级学习路线
前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家.点击跳转到教程. Java 从入门到高级学习路线 <一>1.Jvm 部分 Jvm 内存模型.Jvm 内存结 ...
- Java Cache 入门
什么是缓存 术语缓存在计算机中无处不在.在应用程序设计的上下文中,它经常被用来描述应用程序开发人员利用单独的内存或低延迟的数据结构.缓存,用于临时存储或缓存信息的副本或引用,应用程序可能会在稍后的某个 ...
- Java 基础入门,小白提升路线图
1000+最新Java面试题 获取学习路线资料啦 Java的基础知识就像我们所住的房子的地基,如果地基不稳,上面所盖的楼房再宏伟,也是没人敢去入住的,同理Java的基础不牢固,以后也很难成为真正意义上 ...
最新文章
- Flask+gunicorn部署HTTP服务
- 【 FPGA 】抢占式优先级译码器电路
- 里程碑Droid/Milestone/XT702官方正式2.2ROM刷机教程及刷机失败解决方法(含2.1底包)
- mybatisplus查询今天的数据_MybatisPlus(CRUD)
- 如何在VS2008中添加WM_INITDIALOG消息映射
- 12款白帽子用于黑客渗透测试的操作系统
- 自动化运维环境搭建过程
- eclipse里source的快捷方法_Eclipse快捷键大全
- Data Exfiltration via Blind OS Command Injection
- 操作系统中的fork()函数对应的进程创建过程
- 2012.5.4号--关于125k(简易读卡和低频唤醒)
- 高德地图与百度地图的经纬度偏差纠正
- 超级终端连接华为交换机_小编解决win8系统使用超级终端连接华为交换机的设置步骤...
- Java类汽车,JAVA 建立一个汽车AutoMobile类......
- 留学目的地选择之伊利诺伊州
- 如何利用计算机画立体几何图形,[转载]谈谈用Word2003画立体几何图形的技巧
- express : 无法加载文件 C:\Users\HP\AppData\Roaming\npm\express.ps1,因为在此系统上禁止运行脚本.
- Qt中使用DirectX
- 正式发售超两周 iPhone7部分机型仍然缺货
- 如何隐藏CAD图纸中的部分图形对象?CAD局部隐藏
热门文章
- u盘安装LINUX键盘失灵,U盘装Win7系统进入pe后鼠标键盘失灵不能用怎么办?
- MySQL - 5.7.31 - winx64 安装教程
- DbVisualizer常见问题解答(ddl标签不存在)
- mysql 1273错误
- Java实现可换行文字转图片
- qq空间把android改成iphone,装逼时代 教你如何修改QQ微信小尾巴为来自iphone6
- SV绿皮书笔记(九)暂时完结
- 专家推荐面渣逆袭:JVM经典五十问,这下面试稳了
- html 5新增技术,HTML5新增元素,标签总结
- 人工智能的高层建筑取决于数据基础设施