注解:是一种注释类型。英文单词AnnotationTest。是一种引用数据类型,编译后生成也xxx.class文件。
自定义注解语法格式:
[修饰符列表] @interface 注解类型名{ }
注解使用语法格式:@ 注解类型名
注解可以出现在类上、属性上、方法上、变量上……
public @interface MyAnnotation { }
//注解或者叫注释
@MyAnnotation
public class AnnotationTest01 {
@MyAnnotation
private int no;
@MyAnnotation
public AnnotationTest01(){ }
@MyAnnotation
public AnnotationTest01(@MyAnnotation int no){
@MyAnnotation
int i = 100;
}
}
@MyAnnotation
interface MyInterface{ }
@MyAnnotation
enum Season{
SPRING,SUM,FALL,WINTER
}
@MyAnnotation
public @interface OtherAnnotation { }
JDK的lang包下的Override注解
源代码:public @interfoace Override{ }
这个注解只能注解方法,这个注解是给编译器参考的,和运行阶段没有关系。
带有@Override注解的方法,编译器会进行编译检查,如果不是重写父类方法编译器报错。
public class AnnotationTest {
@Override //这里是重写父类的toString方法,可以标记
public String toString(){
return "toString";
}
//@Override不是重写父类方法,这里报错
public String tostring(){
return "toString";
}
}
用来标注“注解类型”的注解,称为元注解。
常用的元注解:
@Target:用来标注“注解类型”的注解,用来标注被标注的注解可以出现在哪些位置上。
@Target(ElementType.METHOD)
//这句表示这个注解类型只能出现在方法上
@Target(value={FIELD,METHOD,……})
//这句表示这个注解可以出现在属性、方法……
@Retention:用来标注“注解类型”的注解,用来标注被标注的注解最终保存哎哪里。
@Retention(RetentionPolicy.SOURCE)//表示该注解只被保留在java源文件中
@Retention(RetentionPolicy.CLASS)//表示该注解只被保留在class文件中
@Retention(RetentionPolicy.RUNTIME)//表示该注解只被保留在class文件中,并且可以被反射机制所读取
@Deprecated//表示这个类已过时
public class AnnotationTest02 {
public static void main(String[] args) {
}
@Deprecated
public void doSome(){
System.out.println("do something...");
}
@Deprecated
public static void doOther(){
System.out.println("do other...");
}
}
class T {
public static void main(String[] args) {
AnnotationTest02 at = new AnnotationTest02();//在编译器中这里会出现一个横线
at.doSome(); //在编译器中这里会出现一个横线
//在运行时,会出现一个警告,提醒作用。
}
}
public @interface MyAnnotation {
/**
* 以下是MyAnnotation的name属性
* @return
*/
String name();
/*
颜色属性
*/
String color();
/*
年龄属性
*/
int age() default 25; //属性指定默认值,指定默认值后使用该注解可以不写
}
public class MyAnnotationTest {
//@MyAnnotation如果一个注解当中有属性,必须给属性赋值
//@MyAnnotation(属性名=属性值,属性名=属性值……)
@MyAnnotation(name="coffee",color = "黄色")
public void doSome(){
}
}
public @interface MyAnnotation {
String value();
//注解属性可以是基本数据类型、String、Class、枚举类型
//以及以上类型的数组
}
public class MyAnnotationTest {
@MyAnnotation("coffee")//属性是value值,可以不用写属性名
public void doSome(){
}
}
注解属性可以是基本数据类型、String、Class、枚举类型、以及以上类型的数组
属性作为数组,使用时需要大括号括起来,只有一个时可以省略大括号。
public enum Season {
SPIRING,SUMMER,FALL,WINTER
}
public @interface OtherAnnotation {
int age();
String[] email();
Season[] season();
}
public class OtherAnnotationTest {
//数组是大括号
@OtherAnnotation(age = 23,email = {"123456@123.com","icecoffee.@123.com"},season = {Season.SPIRING,Season.SUMMER})
public void doSome(){ }
//数组中只有一个元素,大括号可以省略
@OtherAnnotation(age = 23,email = "123456@123.com",season = Season.SPIRING)
public void doOther(){ }
}
//只允许该注解可以标注类、方法
@Target({ElementType.TYPE,ElementType.METHOD})
//希望这个注解可以被反射RUNTIME
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
String value() default "咖啡";
}
@MyAnnotation
public class MyAnnotationTest {
int i;
public MyAnnotationTest(){ }
@MyAnnotation
public void doSome(){
int i;
}
}
package annotation3;
public class ReflectAnnotationTest {
public static void main(String[] args) throws Exception {
//获取这个类
Class c = Class.forName("annotation3.MyAnnotationTest");
//判断类上是否有@MyAnnotation这个注解
//如果注解上元注解@Retention(RetentionPolicy.RUNTIME)的属性不是RUNTIME,则反射不到,这里为false
System.out.println(c.isAnnotationPresent(MyAnnotation.class)); //true
if(c.isAnnotationPresent(MyAnnotation.class)){
//获取该注解对象
MyAnnotation myAnnotation = (MyAnnotation)c.getAnnotation(MyAnnotation.class);
System.out.println("类上面的注解对象" + myAnnotation); //类上面的注解对象@annotation3.MyAnnotation(value=咖啡)
//获取注解属性
System.out.println(myAnnotation.value());//咖啡
}
//判断String类上是否有这个注解
Class c2 = Class.forName("java.lang.String");
System.out.println(c2.isAnnotationPresent(MyAnnotation.class));//false
}
}
注解在程序当中等同于一种标记,给程序员参考的作用。
练习:编写一个需求,一个类被@Id注解标记需要有一个int类型的id属性,如果没有抛出异常。
//编写一个@Id注解
//表示这个注解只能在类上面
@Target(ElementType.TYPE)
//表示这个注解可以被反射
@Retention(RetentionPolicy.RUNTIME)
public @interface Id {
}
//编写一个User类
@Id
public class User {
int id; //这个如果不在抛出异常,在运行正常
String name;
String password;
}
//自定义一个异常,用来抛出没有int类型的id属性异常
//自定义异常
public class HasNotIdPropertyException extends RuntimeException{
public HasNotIdPropertyException(){ }
public HasNotIdPropertyException(String s){
super(s);
}
}
public class Test {
public static void main(String[] args) throws Exception{
//获取类
Class userClass = Class.forName("Test.User");
//判断类上是否有@Id注解
if(userClass.isAnnotationPresent(Id.class)){
//当一个类上有@Id注解时,要求必须存在int类型属性
//如果没有int类型属性报异常
Field[] fields = userClass.getDeclaredFields();
//一个默认标记是否有int属性的id
boolean isOK = false;
for (Field field:
fields) {
//判断是否有一个int类型的id,如果有修改标记
if("id".equals(field.getName()) && "int".equals(field.getType().getSimpleName())){
isOK = true;
break;
}
}
//如果没有int类型的id,抛出异常
if(!isOK){
throw new HasNotIdPropertyException("被@Id注解标注的类中必须有一个int类型的id属性");
}
}
}
}
——本章节为个人学习笔记。学习视频为动力节点Java零基础教程视频:动力节点—JAVA零基础教程视频