1、注解是什么?
- 注解,或者叫做注释类型,英文单词是:Annotation。
- 注解Annotation是一种引用数据类型。编译之后也是生成xxx.class文件。
2、怎么自定义注解呢?语法格式?
[修饰符列表] @interface 注解类型名{
}
3、注解怎么使用,用在什么地方?
3.1、注解使用时的语法格式
@注解类型名
3.2、注解可以出现的地方
- 注解可以出现在类上、属性上、方法上、变量上等…
- 注解还可以出现在注解类型上。
eg.
package javase.annotation1;
// 默认情况下,注解可以出现在任意位置。
@MyAnnotation
public class AnnotationTest01 {
@MyAnnotation
int no;
@MyAnnotation
public AnnotationTest01(int no) {
this.no = no;
}
@MyAnnotation
public void m1(){
@MyAnnotation
int i;
}
public void m2(@MyAnnotation String name, @MyAnnotation boolean sex){
}
}
@MyAnnotation
interface MyInterface{
}
@MyAnnotation
enum Season{
@MyAnnotation SPRING, @MyAnnotation SUMMER,AUTUMN,WINTER
}
@MyAnnotation
abstract class a{
}
----------------------------------------------
package javase.annotation1;
//注解修饰注解
@MyAnnotation
public @interface OtherAnnotation {
}
4、JDK内置了哪些注解呢?
java.lang包下的注释类型:
注解 | 解释 | 备注 |
---|---|---|
Deprecated | 表示不鼓励程序员使用这样的元素,通常是因为它很危险或存在更好的选择。 | 掌握 |
Override | 表示一个方法声明打算重写超类中的另一个方法声明。 | 掌握 |
SuppressWarnings | 指示应该在注释元素(以及包含在该注释元素中的所有程序元素)中取消显示指定的编译器警告。 | 不用掌握 |
5、元注解
5.1、什么是元注解?
用来标注“注解类型”的“注解”,称为元注解。
5.2、常见的元注解有哪些?
- Target
- Retention
5.3、关于Target注解
- 这是一个元注解,用来 标注“注解类型” 的“注解”
- 这个Target注解用来标注“被标注的注解”可以出现在哪些位置上。
eg.
@Target(ElementType.METHOD):表示“被标注的注解”只能出现在方法上。
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, MODULE, PARAMETER, TYPE})
表示该注解可以出现在:
构造方法上
字段上
局部变量上
方法上
....
类上...
5.3.1、关于Target注解的常量
表示该注解可以出现在什么位置上
常量名 | 位置 |
---|---|
TYPE | 类 |
FIELD | 属性 |
METHOD | 方法 |
CONSTRUCTOR | 构造方法 |
LOCAL_VARIABLE | 局部变量 |
PACKAGE | 包 |
MODULE | 模块 |
PARAMETER | 方法参数 |
5.4、关于Retention注解
- 这是一个元注解,用来 标注“注解类型” 的“注解”
- 这个Retention注解用来标注“被标注的注解””最终保存在哪里。
eg.
@Retention(RetentionPolicy.SOURCE):表示该注解只被保留在java源文件中。
@Retention(RetentionPolicy.CLASS):表示该注解被保存在class文件中。
@Retention(RetentionPolicy.RUNTIME):表示该注解被保存在class文件中,并且可以被反射机制所读取。
5.4.1、关于Retention注解的常量
表示该注解保存在什么地方
常量名 | 位置 |
---|---|
SOURCE | 表示该注解只被保留在java源文件中 |
CLASS | 表示该注解被保存在class文件中 |
RUNTIME | 表示该注解被保存在class文件中,并且可以被反射机制所读取。 |
6、关于JDK lang包下的Override注解
6.1、源代码
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
6.2、解释
- 标识性注解,给编译器做参考的。
- 编译器看到方法上有这个注解的时候,编译器会自动检查该方法是否重写了父类的方法。如果没有重写,报错。
- 这个注解只是在编译阶段起作用,和运行期无关!
- @Override这个注解只能注解方法。
7、关于JDK lang包下的Deprecated注解
7.1、源代码
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
public @interface Deprecated {
}
7.2、解释
- Deprecated这个注解标注的元素已过时。
- 这个注解主要是向其它程序员传达一个信息,告知已过时,有更好的解决方案存在。
eg.
8、注解的属性
我们通常在注解当中可以定义属性,以下这个是MyAnnotation的name属性。
看着像1个方法,但实际上我们称之为属性name。
public @interface MyAnnotation {
String name();//名字属性
String color();//颜色属性
int age() default 25; //属性指定默认值
}
注:如果一个注解当中有属性,那么必须给属性赋值。(除非该属性使用default指定了默认值。)
eg.
public class AnnotationTest {
// 报错的原因:如果一个注解当中有属性,那么必须给属性赋值。(除非该属性使用default指定了默认值。)
/*@MyAnnotation
public void doSome(){
}*/
//以下两种都可以
// @MyAnnotation(name = "张三", color = "红色", age = 30)//覆盖掉默认值25
@MyAnnotation(name = "张三", color = "红色")
public void doSome(){
}
}
8.1、属性赋值语法格式:
@注解(属性名=属性值,属性名=属性值,属性名=属性值)
8.2、★注解的value属性
注:如果一个注解的属性的名字是value,并且只有一个属性的话,在使用的时候,该属性名可以省略。(数据value属性名也可以省略)
eg.
public @interface MyAnnotation {
String value();
}
---------------------------------------------
public class AnnotationTest {
//以下两种都可以
// @MyAnnotation(value = "123")
@MyAnnotation("123")
public void doSome(){
}
}
8.3、注解属性的数据类型
八大基本数据类型 + 3大引用类型【String、Class、enum】(包括这些类型的数组形式!)
- bite
- short
- int
- long
- float
- double
- boolean
- char
- String
- Class
- enum枚举类型
8.4、注解属性数组的注意事项
数组是大括号 , 如果数组中只有1个元素:大括号可以省略。*
eg.
public @interface MyAnnotation {
/*
注解当中的属性可以是哪一种类型?
属性的类型可以是:
byte short int long float double boolean char String Class 枚举类型
以及以上每一种的数组形式。
*/
int no() default 1;
int[] score();
String name() default "null";
String[] email();//邮箱地址属性,支持多个
Season[] seasonArray();//季节数组,Season是枚举类型
Class parameter1() default Date.class;
Class[] parameter2();
}
------------------------------------------------------------
public class AnnotationTest {
// 数组是大括号
@MyAnnotation(no = 1900129, score = {90, 98, 70},
email = {"192@qq.com", "ouw@sgu.com"},
seasonArray = {Season.SPRING, Season.SUMMER},
parameter2 = {int.class, String.class})
public void doSome(){
}
// 如果数组中只有1个元素:大括号可以省略。
@MyAnnotation(score = 90, email = "ouw@sgu.com",
seasonArray = Season.SUMMER, parameter2 = String.class)
public void doOther(){
}
}
9、反射类上的注解
四步骤:
- 获取这个类
- 判断类上面是否有注解
- 获取注解对象
- 获取注解对象的属性
eg.
//反射类上的注解
public class ReflectAnnotationTest {
public static void main(String[] args) throws Exception{
// 获取这个类
Class c = Class.forName("javase.annotation5.AnnotationTest");
// 判断类上面是否有@MyAnnotation
// System.out.println(c.isAnnotationPresent(MyAnnotation.class));
if (c.isAnnotationPresent(MyAnnotation.class)){
// 获取注解对象的属性怎么办?和调接口没区别。
MyAnnotation myAnnotation = (MyAnnotation)c.getAnnotation(MyAnnotation.class);
// 获取注解对象的属性怎么办?和调接口没区别。
String value = myAnnotation.value();
System.out.println(value);
}
// 判断String类上面是否存在这个注解
Class stringClass = Class.forName("java.lang.String");
System.out.println(stringClass.isAnnotationPresent(MyAnnotation.class)); // false
}
}
----------------------------------------------
@MyAnnotation("zhangSan")
public class AnnotationTest {
@MyAnnotation
public void doSome(){
}
}
10、反射方法上的注解
五步骤:
- 获取这个类
- 获取这个类的方法
- 判断类的方法上面是否有注解
- 获取注解对象
- 获取注解对象的属性
eg.
public class MyAnnotationTest {
@MyAnnotation(name = "admin", pwd = "123")
public void doSome(){
}
public static void main(String[] args) throws Exception{
// 获取MyAnnotationTest的doSome()方法上面的注解信息。
Class c = Class.forName("javase.annotation6.MyAnnotationTest");
// 获取doSome()方法
Method method = c.getDeclaredMethod("doSome");
// 判断该方法上是否存在这个注解
if (method.isAnnotationPresent(MyAnnotation.class)){
MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);
String name = annotation.name();
String pwd = annotation.pwd();
System.out.println(name + " " + pwd);
}
}
}