注解
一、注解(注释,标注,Annotation)及注解的作用
1、注解Annotation是一种引用数据类型。编译之后也是生成xxx.class文件。
2、如果要对于注解的作用进行分类,我们可以根据它所起的作用,大致可分为三类:
(1)编写文档:通过代码里标识的元数据生成文档。
(2)代码分析:通过代码里标识的元数据对代码进行分析。
(3)编译检查:通过代码里标识的元数据让编译器能实现基本的编译检查。
二、怎么自定义注解呢?语法格式?
1、自定义注解
[修饰符列表] @interface 注解类型名{
}
2、注解怎么使用,用在什么地方?
第一:注解使用时的语法格式是:@注解类型名
第二:注解可以出现在类上、属性上、方法上、变量上等…
注解还可以出现在注解类型上。
public @interface MyAnnotation {
String value();
}
public class MyAnnotationTest {
@MyAnnotation(value="jdk-9")
public void doSome(){
}
@MyAnnotation("jdk-8")
public void doOther(){
}
}
三、JDK内置了哪些注解呢?
java.lang包下的注释类型:
掌握:
Deprecated 用 @Deprecated 注释的程序元素,
不鼓励程序员使用这样的元素,通常是因为它很危险或存在更好的选择。
掌握:
Override 表示一个方法声明打算重写超类中的另一个方法声明。
不用掌握:
SuppressWarnings 指示应该在注释元素(以及包含在该注释元素中的
所有程序元素)中取消显示指定的编译器警告。
四、元注解
1、什么是元注解?
用来标注“注解类型”的“注解”,称为元注解。
2、常见的元注解有哪些?
Target
Retention
(1)Target注解用来标注“被标注的注解”可以出现在哪些位置上。
如:@Target(ElementType.METHOD):表示“被标注的注解”只能出现在方法上。
在定义 Annotation 类型时,使用 java.lang.annotation.Target 可以定义其适用的时机,在定义时要指定java.lang.annotation.ElementType 的枚举值之一。
public enum ElementType{
TYPE,//适用class,interface,enum
FIELD,//适用于field
METHOD,//适用于method
PARAMETER,//适用method上之parameter
CONSTRUCTOR,//适用constructor
LOCAL_VARIABLE,//适用于区域变量
ANNOTATION_TYPE,//适用于annotation类型
PACKAGE//适用于package
}
表示该注解可以出现在:构造方法上 字段上 局部变量上 方法上 …
举例,假设定义 Annotation 类型时,要限定它只能适用于构造函数与方法成员,则:
@Target({ElementType.CONSTRUCTOR,ElementType.METHOD})
public @interface MethodAnnotation{}
将 MethodAnnotation 标示于方法之上,如:
public class SomeoneClass{
@MethodAnnotation
public void doSomething(){}
}
Target的源代码
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
ElementType[] value();
}
(2)这个Retention注解用来标注“被标注的注解”最终保存在哪里。
@Retention(RetentionPolicy.SOURCE):表示该注解只被保留在java源文件中。
@Retention(RetentionPolicy.CLASS):表示该注解被保存在class文件中。
@Retention(RetentionPolicy.RUNTIME):表示该注解被保存在class文件中,并且可以被反射机制所读取。
Retention的源代码
//元注解
public @interface Retention {
//属性
RetentionPolicy value();
}
RetentionPolicy的源代码:
public enum RetentionPolicy {
SOURCE,
CLASS,
RUNTIME
}
//@Retention(value=RetentionPolicy.RUNTIME)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation{}
(3)@Deprecated 表示标注的元素已过时,是为了告知已过时,有更好的方案。
@Deprecated
public class AnnotationTest02 {
public static void main(String[] args) {
AnnotationTest02 a=new AnnotationTest02();
a.doSome();
AnnotationTest02.doOther();
}
//表示该方法已过时
@Deprecated
public static void doOther(){
System.out.println("do other...");
}
@Deprecated
public void doSome(){
System.out.println("do something...");
}
@Override
public String toString() {
return super.toString();
}
}
class T {
public static void main(String[] args) {
AnnotationTest02 an=new AnnotationTest02();
an.doSome();
AnnotationTest02.doOther();
}
}
五、反射注解
package Annotation4;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//只允许标注类和方法
@Target({ElementType.TYPE,ElementType.METHOD})
//希望这个注解可以被反射
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
String value();
}
package Annotation4;
@MyAnnotation(value="河南省南阳市")
public class MyAnnotationTest {
int i;
}
package Annotation4;
/**
* @author 古藤老人
*/
public class ReflectMyAnnotationTest {
public static void main(String[] args) throws Exception {
//获取这个类
Class c=Class.forName("Annotation4.MyAnnotationTest");
//判断类上是否有@MyAnnotation
System.out.println(c.isAnnotationPresent(MyAnnotation.class));
//结果:true
if(c.isAnnotationPresent(MyAnnotation.class)){
//获取该注解对象
MyAnnotation myAnnotation=(MyAnnotation)c.getAnnotation(MyAnnotation.class);
System.out.println("类上的注解对象"+myAnnotation);
//获取注解对象的属性
String value=myAnnotation.value();
System.out.println(value);
}
Class stringClass=Class.forName("java.lang.String");
System.out.println(stringClass.isAnnotationPresent(MyAnnotation.class));
//结果:false
}
}
六、注解在开发中有什么用呢?
需求:
假设有这样一个注解,叫做:@Id
这个注解只能出现在类上面,当这个类上有这个注解的时候,
要求这个类中必须有一个int类型的id属性。如果没有这个属性
就报异常。如果有这个属性则正常执行!
package com.bjpowernode.java.annotation7;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
// 表示这个注解只能出现在类上面
@Target(ElementType.TYPE)
// 该注解可以被反射机制读取到
@Retention(RetentionPolicy.RUNTIME)
public @interface MustHasIdPropertyAnnotation {
}
// 这个注解@Id用来标注类,被标注的类中必须有一个int类型的id属性,没有就报异常。
package com.bjpowernode.java.annotation7;
/*
自定义异常
*/
public class HasNotIdPropertyException extends RuntimeException {
public HasNotIdPropertyException(){
}
public HasNotIdPropertyException(String s){
super(s);
}
}
package com.bjpowernode.java.annotation7;
@MustHasIdPropertyAnnotation
public class User {
int id;
String name;
String password;
}
package com.bjpowernode.java.annotation7;
import java.lang.reflect.Field;
public class Test {
public static void main(String[] args) throws Exception{
// 获取类
Class userClass = Class.forName("com.bjpowernode.java.annotation7.User");
// 判断类上是否存在Id注解
if(userClass.isAnnotationPresent(MustHasIdPropertyAnnotation.class)){
// 当一个类上面有@MustHasIdPropertyAnnotation注解的时候,要求类中必须存在int类型的id属性
// 如果没有int类型的id属性则报异常。
// 获取类的属性
Field[] fields = userClass.getDeclaredFields();
boolean isOk = false; // 给一个默认的标记
for(Field field : fields){
if("id".equals(field.getName()) && "int".equals(field.getType().getSimpleName())){
// 表示这个类是合法的类。有@Id注解,则这个类中必须有int类型的id
isOk = true; // 表示合法
break;
}
}
// 判断是否合法
if(!isOk){
throw new HasNotIdPropertyException("被@MustHasIdPropertyAnnotation注解标注的类中必须要有一个int类型的id属性!");
}
}
}
}