目录
注解
概念:
-
JDK1.5的新特性
-
说明程序
作用分类
编写文档:
通过代码里标识的注解生成文档【生成文档doc文档】 就是我们才学java看的api文档
1.编写注解:
/**
* 注解java doc演示
*
* @author mxp
* @version 1.0
* @since 1,5
*/
public class AoonDemo1 {
/**
* 计算两数之和
* @param a
* @param b
* @return 两数之和
*/
public int add(int a,int b){
return a+b;
}
}
2.打开终端
3.输入javadoc .\xxx.java
4.效果
代码分析:
通过代码里标识的注解对代码进行分析【使用反射】
编译检查
通过代码里标识的注解让编译器能够实现基本的编译检查【override】
JDK中预定义的一些注解
@Override : 检测被该注解标注的方法是否是继承自父类(接口)的 @Deprecated: 该注解标注的内容,表示已过时 @Suppresswarnings: 压制警告
自定义注解
格式:
元注解 public @interface 注解名称{
属性列表
}
本质:
package com.company.annotation;
public @interface MyAnno {
}
进行反编译
public interface com.company.annotation.MyAnno extends java.lang.annotation.Annotation { }
可以看出就是一个接口
属性:就是接口中的抽象方法
要求:
1.属性返回值的类型
基本数据类型 String 枚举 注解 以上的数组类型
2.定义了属性,在使用时需要给属性赋值
使用注解使,里面的方法需要赋值,除非定义的时候,使用default
有默认值 方法名叫value,在使用时,如果你就用这一个,可以省略 数组赋值时,值使用门包裹。如果数组中只有一个值,则{}省略
元注解:用于描述注解的注解
@Target:描述注解能够作用的位置
TYPE, 能够在类上使用 FIELD, 在属性上使用 METHOD, 在方法上使用
@Retention:描述注解被保留的阶段
SOURCE, 源码阶段
CLASS, 字节码阶段
RUNTIME 运行时阶段
一般我们自定义的注解 使用运行时阶段 @Retention(RetentionPolicy.RUNTIME)
@Documented :描述注解是否被抽取到api文档中
@Inherited :描述注解是否被子类继承
在程序中使用(解析)注解
如何获取注解中定义的属性值
1.获取注解所在的位置的对象(Class,Method,Field)
2.获取指定的注解 getAnnotation(注解类.class)
3.调用注解中抽象类的方法,获取属性值
案例1
需求:不修改任何代码,可以创建任意对象,执行任意方法
Pro.java
package com.company.anli;
import java.lang.annotation.*;
/**
* @描述:获取需要执行的类名,方法名
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Pro {
String className();
String methodName();
}
/**
*
* 执行 Pro an=reflectTestClass.getAnnotation(Pro.class);
* 相当于生产了
* public class ProImpl implements Pro{
* public String className(){
* return "com.company.anli.Dog";
* }
* public void methodName(){
* return "eat"
* }
* }
*/
Dog.java
package com.company.anli;
public class Dog {
public void eat() {
System.out.println("狗吃肉");
}
public void sleep() {
System.out.println("狗睡觉");
}
}
ReflectTest.java
package com.company.anli;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* 1.可以看出来最主要的作用就是,替代properties文件
*/
@Pro(className = "com.company.anli.Dog", methodName = "sleep")
public class ReflectTest {
/**
* @param args
* @描述 不修改任何代码,可以创建任意对象,执行任意方法
*/
public static void main(String[] args) throws Exception {
//1.解析注解
//1.1获取该类的字节码文件对象
Class<ReflectTest> reflectTestClass = ReflectTest.class;
//2.获取上边的注解对象
//其实就是在内存中生成了一个该注解接口的子类实现对象
Pro an = reflectTestClass.getAnnotation(Pro.class);
//3.调用注解对象中定义的抽象方法,获取返回值
String className = an.className();
String methodName = an.methodName();
// 加载该类进内存
Class cls = Class.forName(className);
Object obj = cls.newInstance();
Method method = cls.getMethod(methodName);
method.invoke(obj);
}
}
案例2
需求:添加 @Check 就判断,这个方法是否有异常,且记录
Calculator.java
package com.company.anli2;
/**
* 小明定义的计算器类
*/
public class Calculator {
//加法
@Check
public void add() {
System.out.println("1+0=" + (1 + 0));
}
//减法
@Check
public void sub() {
System.out.println("1-0=" + (1 - 0));
}
//乘法
@Check
public void mul() {
System.out.println("1*0=" + (1 * 0));
}
//除法
@Check
public void div() {
System.out.println("1/0=" + (1 / 0));
}
@Check
private void shwo() {
System.out.println("永无bug......");
}
}
Check.java
package com.company.anli2;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Check {
}
TestCheck.java
package com.company.anli2;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* 简单的测试框架
*/
public class TestCheck {
public static void main(String[] args) throws IOException {
//1.创建计算器对象
Calculator c = new Calculator();
//2.获取字节码文件对象
Class<? extends Calculator> ccls = c.getClass();
//3.获取所有public修饰的方法
Method[] methods = ccls.getMethods();
int number = 0;//异常出现的次数
BufferedWriter bw = new BufferedWriter(new FileWriter("bug.txt"));
for (Method method : methods) {
//4.判断方法上是否有Check注解
if (method.isAnnotationPresent(Check.class)) {
//5.有,执行
try {
method.invoke(c);
} catch (Exception e) {
//6.捕获异常
//记录到文件中
number++;
bw.write(method.getName() + "方法出现了异常");
bw.newLine();//换行
bw.write("异常的名称:" + e.getCause().getClass().getSimpleName());
bw.newLine();
bw.write("异常的原因:" + e.getCause().getMessage());
bw.newLine();
bw.write("--------------------------------------------");
bw.newLine();
}
}
}
bw.write("本次测试一共出现" + number + "次异常");
bw.flush();//刷新
bw.close();
}
}
总结
-
以后大多数时候,我们会使用注解,而不是自定义注解
注解给谁用? 编译器:识别注解,检查编译有没有问题。如 @Override这个里面肯定也有解析程序的存在
给解析程序用:如果没有解析的存在那么这个注解加在上面毫无意义