java 注解Annotation
1.注解的概念
- 注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。
2.注解的作用
- 编写文档:通过代码里标识的注解生成文档【生成文档doc文档】
- 代码分析:通过代码里标识的注解对代码进行分析【使用反射】
- 编译检查:通过代码里标识的注解让编译器能够实现基本的编译检查【override】
3.JDK中内置的注解
1.@Override
@Override 重写 检测被该注解标注的方法是否是继承自父类(接口)的方法
2.@Suppvisewarnings
@Suppvisewarnings 压制警告
3.@Deprecated
@Deprecated 该注解标注的内容,表示已过时
代码演示
package com.annotation.domain;
public class Penson {
public String name="一拳嘤嘤超人";
@Override
public String toString() {
return "通过jdk内置@Override注解 重写Penson [name=" + name + "]";
}
/**
* 此方法以弃用 可调用 watch2
*/
@Deprecated(since="1.5") // since 至...之后 放JDK版本
public void watch() {
System.out.println("看黑猫警长");
}
public void watch2() {
System.out.println("看熊出没");
}
}
package com.annotation.exercise;
import com.annotation.domain.Penson;
/**
* @author HeLang
* @Override 重写 检测被该注解标注的方法足否是继承自父类(接口)
* @Suppvisewarnings 压制警告
* @Deprecated 该注解标注的内容,表示已过时
*/
public class JdkAnoDemo {
@SuppressWarnings("all") //压制所有警告
public static void main(String[] args) throws Exception {
Penson person =new Penson();
//@Override
System.out.println(person.toString());
//@Suppvisewarnings
@SuppressWarnings("unused") // 压制未使用变量警告
int a=0;
@SuppressWarnings("rawtypes") // 压制泛型警告
Class jdkAnoClass=JdkAnoDemo.class;
@SuppressWarnings("deprecation") //压制过时方法警告
Object o1 =jdkAnoClass.newInstance();
System.out.println();
//@Deprecated
person.watch();
person.watch2();
}
}
运行结果
通过jdk内置@Override注解 重写Penson [name=一拳嘤嘤超人]
看黑猫警长
看熊出没
4.自定义注解
1.格式
public @interface 注解名 {
// 属性值类型
* 基本数据类型八种( 四种整数类型byte、short、int、long
* 两种浮点数类型float、double 一种布尔类型 boolean 一种字符类型char)
* String 枚举 注解 以及它们的数组类型
}
2.演示
package com.annotation.exercise;
/**
* @author HeLang
* 自定义注解
* 属性值:基本数据类型八种(四种整数类型byte、short、int、long
* 两种浮点数类型float、double 一种布尔类型 boolean 一种字符类型char)
* String 枚举 注解 以及它们的数组类型 修饰符只能是public abstract
* 使用:如果定义了注解的属性时,使用时要将注解中的属性赋初始值
* 也可以通过使用default可以设置默认初始值 在使用时则不用初始化赋值
* 如果属性只有一个 且属性名为value时 使用该注解初始化时可以省略属性名
* 如果属性时数组值应放入{}中 如果{}中只有一个属性值时 可以省略{}
*/
import com.annotation.domain.MyAnoEnum;
public @interface MyAnoDemo {
//基本数据类型八种
byte byteTest() default 0;
short shortTest() default 0;
int intTest() default 0;
long longTest() default 0;
float floatTest() default 0;
double doubleTest() default 0;
boolean booleanTest()default false;
char charTest() default '男';
//String
String stringTest() default "默认值";
//枚举
MyAnoEnum myAnoEnum()default MyAnoEnum.NAME;
//注解
MyAnoDemo2 myAnoDemo2() default @MyAnoDemo2 ;
//数组类型
String[] strs() default {"1","2"};
int [] ints()default {3,4};;
MyAnoEnum[] myAnoEnums() default { MyAnoEnum.NAME, MyAnoEnum.NAME2};
MyAnoDemo2 [] myAnoDemo2s() default {@MyAnoDemo2 };// 可以省略{}
}
3.使用
@MyAnoDemo(byteTest = 1, stringTest="Use",strs = {"aa","bb"})
5.元注解
1.概念
元注解: 用于描述注解的注解
2.常用元注解
1. @Target(ElementType) 描述作用域
- TYPE 类
- FIELD 成员变量
- METHOD 方法
- PARAMETER 方法参数
- CONSTRUCTOR 构造方法
- LOCAL_VARIABLE 局部变量
2. @Retention(RetentionPolicy) 描述保留阶段
- SOURCE 在编译器编译成class文件前就会被移除
- CLASS 会保留到class字节码文件中,不会被jvm读取到
- RUNTIME 会保留到class字节码文件中,并被jvm读取到
3. @Documented: 描述是否被抽取到api文档中
- javadoc xx.java(生成文档)
- javac xx.java(编译)
- javap xx.java(反编译)
4. @Inherited:描述是否被子类继承
- 被作用的类的子类也会继承@Inherited注解
- 被作用的类实现的接口 子接口不会继承@Inherited注解
- 被作用的接口的子接口 不会继承@Inherited注解
注意:如果出现元注解无法解析 可能是源文件损坏了 找到源文件路径去把他更换掉
6.解析注解
package com.annotation.project;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
/**
* @author HeLang
* 注解解析 Annotation_parsing
* 模拟框架类 在不改变该类的任何代码的情况下,可以创建任意类的对象,执行任意方法
* 使用注解代替配置文件
*
*/
@SuppressWarnings("all")
@Parse(className = "com.annotation.domain.Person", methodName = "watch2")
public class Annotation_parsing {
public static void main(String[] args) throws Exception {
// 获取该类的字节码文件对象
Class<Annotation_parsing> cls =Annotation_parsing.class;
// 获取该类上的注解对象(注解的实现类)
/*
* public class CheckImpl implements Check{
* String methodName(){
* }
* String className(){
* }
*/
Parse parsing=cls.getAnnotation(Parse.class);
// 获取注解中的属性值
String methodName= parsing.methodName();
String className =parsing.className();
System.out.println(methodName);
System.out.println(className);
// 根据属性值来需要执行的类对象和方法
Class person=Class.forName(className);
Method watch =person.getMethod(methodName);
// 执行方法
watch.invoke(person.newInstance());
}
}
package com.annotation.project;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
*
* @author HeLang
* 解析注解
*/
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Parse {
String methodName();
String className();
}
7.注解案例
package com.annotation.project;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* @author HeLang
* Annotation_case_execute 注解案例执行类
* 将添加@Check的方法 验证该方法是否存在bug
*/
@SuppressWarnings("all")
public class Annotation_case_execute {
public static void main(String[] args) throws IOException {
System.out.println("启动了");
//获取使用check注解类的字节码文件
Annotation_case annotation_case =new Annotation_case();
int number =0;
Class caseClass =annotation_case.getClass();
//获取被check注解的所有方法
Method [] method =caseClass.getDeclaredMethods();
BufferedWriter bw =new BufferedWriter(new FileWriter("bug.txt"));
for (Method method2 : method) {
method2.setAccessible(true); //开启暴力反射
// 判断该方法是否有check注解
if(method2.isAnnotationPresent(Check.class)) {
//执行该方法
try {
method2.invoke(annotation_case);
} catch (Exception e) {
number++;
bw.write("方法:"+method2.getName());
System.out.println("方法:"+method2.getName());
bw.newLine();
bw.write("异常名字:"+e.getCause().getClass().getSimpleName());
System.out.println("异常名字:"+e.getCause().getClass().getSimpleName());
bw.newLine();
bw.write("异常的原因:"+e.getCause().getMessage());
System.out.println("异常的原因:"+e.getCause().getMessage());
bw.newLine();
bw.write("------------------------------------");
}
}
}
bw.write("捕获异常次数:"+number);
System.out.println("捕获异常次数:"+number);
bw.flush();
bw.close();
}
}
方法:nullException
异常名字:NullPointerException
异常的原因:Cannot invoke "String.toString()" because "test" is null
方法:arithmeticException
异常名字:ArithmeticException
异常的原因:/ by zero
jin
方法:arithmeticException2
异常名字:ArithmeticException
异常的原因:/ by zero
捕获异常次数:3
package com.annotation.project;
/**
* @author HeLang
* 注解案列
* 使用check注解 来实现检查方法的异常 并记录起来
*/
@SuppressWarnings("all")
public class Annotation_case {
@Check()
private void nullException() {
String test= null;
test.toString();
}
@Check
protected void arithmeticException() {
int i =1/0;
}
@Check
public void arithmeticException2() {
int i =1/0;
}
}
目录