注解学习笔记文章目录
- 1 注解简介
- 2 生成Java类的doc文档
- 3 JDK内置注解
- 3.1 @Override
- 3.2 @Deprecated
- 3.3 @SuppressWarnings
- 4 自定义注解
- 4.1 注解格式
- 4.2 注解本质
- 4.3 注解属性
- 4.4 元注解
- 4.4.1 ==@Target==
- 4.4.2 ==@Retention==
- 4.4.3 @documented
- 4.4.4 @Inherited
- 4.4.5 元注解总结
- 5 解析注解
- 6 注解案例
- 6.1 需求
- 6.2 代码实现
- 6.2.1 定义注解
- 6.2.2 使用注解
- 6.2.3 解析注解
- 6.3 小结
注释:用文字描述程序的,给程序员看的
注解:说明程序的,给计算机看的
Annotation,也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。
它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。
。JDK1.5之后的新特性
。说明程序的
作用分类:
1.编写文档:通过代码里标识的注解生成文档【生成java doc文档】
2.代码分析:通过代码里标识的注解对代码进行分析【使用反射】
3.编译检查:通过代码里标识的注解让编译器能够实现基本的编译检查【override】
注解作用:
注解大多数时候都是用来替代配置文件使用的,不用在配置文件中配置,直接注解赋值
2 生成Java类的doc文档1.编写Java类
AnnotationDemo1.java
package com.tangguanlin.annotation; public class AnnotationDemo1 { public int add(int a,int b ){ return a+b; } }
2.将AnnotationDemo1.java复制到桌面文件夹annotation下,编码为ANSI格式:
3.打开命令行,到annotation路径下,
输入:javadoc AnnotationDemo1.java 回车
4.用浏览器打开index.html,就能看到该类的doc文档
3 JDK内置注解 3.1 @Override@Override : 检测该注解标注的方法是否是继承自父类(接口)的
package com.tangguanlin.annotation; public class AnnotationDemo2 { @Override //@Override:检测该被注解标注的方法是否是继承自父类 public String toString() { return super.toString(); } }3.2 @Deprecated
@Deprecated:该注解标注的内容,表示已过时
@Deprecated //@Deprecated 标注show1()方法已过时,不建议用 public void show1(){ //有缺陷 }
例:
Date日期类不建议使用了,建议使用Calendar日期类:
3.3 @SuppressWarnings@SuppressWarnings(“all”):压制警告
@SuppressWarnings("all") public class AnnotationDemo2 { }
例:
show2()方法有警告信息“Method show2() is never used”.
加上注解@SuppressWarnings(“all”)后,警告消失
一般放在类上:
4 自定义注解 4.1 注解格式格式:
public @interface 注解名称{};
自定义注解@MyAnnotation
package com.tangguanlin.annotation; public @interface MyAnnotation { }
编译命令:
javac MyAnnotation.java
生成MyAnnotation.class字节码文件
反编译命令:
javap MyAnnotation.class
命令行生成原java代码
public interface com.tangguanlin.annotation.MyAnnotation extends java.lang.annotation.Annotation { }
截图如下:
4.2 注解本质注解本质上就是一个接口,该接口默认继承Annotation接口
public interface MyAnnotation extends Annotation { }4.3 注解属性
属性:接口中可以定义的抽象方法
1.属性的返回值类型:
基本数据类型
String
枚举
注解
以上类型的数组
package com.tangguanlin.annotation; public @interface MyAnnotation { public abstract String show1(); //自定义属性 }
使用注解:
@MyAnnotation(show1 = "1") public void show2(){ //替代show1()方法 }
一般都将注解的属性方法定义成真正的属性名字:比如age
package com.tangguanlin.annotation; public @interface MyAnnotation { public abstract String age(); //将注解的属性方法定义成真正的属性名字 public String username(); }
使用,见名知意:
@MyAnnotation(age = "23",username = "zhangsan") //使用注解 public void show2(){ //替代show1()方法 }
2.定义了属性,在使用时需要给属性赋值
。如果定义属性时,使用default关键字给属性默认初始值,则使用注解时,可以不进行属性的赋值
。如果只有一个属性需要赋值,并且属性的名称是value,则value可以省略,直接定义值即可
。数组赋值时,值使用{}包裹。如果数组中只有一个值,则{}省略。
定义:
package com.tangguanlin.annotation; public @interface MyAnnotation { public int value(); }
使用:比如: @SuppressWarnings(“all”)
@MyAnnotation(2) //value属性直接给值 简化写法 public void show2(){ //替代show1()方法 }4.4 元注解
元注解:用于描述注解的注解
4.4.1 @Target@Target: 描述注解能够作用的位置
ElementType.TYPE : 表示该MyAnnotation注解只能作用在类上 ElementType.METHOD: 表示该MyAnnotation注解只能作用在方法上 ElementType.FIELD: 表示该MyAnnotation注解只能作用在成天变量上 使用: @Target(value = ElementType.TYPE) public @interface MyAnnotation2 { }
定义:
package com.tangguanlin.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Target; @Target(value = ElementType.TYPE) //表示该MyAnnotation注解只能作用在类上 public @interface MyAnnotation2 { }4.4.2 @Retention
@Retention: 描述注解被保留的阶段
RetentionPolicy.SOURCE : 表示该MyAnnotation注解只能作用在代码上 RetentionPolicy.CLASS: 表示该MyAnnotation注解只能作用在类上 RetentionPolicy.RUNTIME: 表示该MyAnnotation注解 会保留到class字节码文件中并被JVM读取到 我们定义的注解,一般都是取RUNTIME值 使用: @Retention(RetentionPolicy.RUNTIME) public @interface MyAnnotation2 { }
定义:
package com.tangguanlin.annotation; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @Retention(RetentionPolicy.RUNTIME) public @interface MyAnnotation2 { //表示该MyAnnotation注解 会保留到class字节码文件中并被JVM读取到 }4.4.3 @documented
@documented:描述注解是否被抽取到api文档中
使用: @documented public @interface MyAnnotation2 { }
例:
定义:
package com.tangguanlin.annotation; import java.lang.annotation.*; @Target(value = ElementType.METHOD) @Retention(RetentionPolicy.CLASS) @documented //描述注解是否被抽取到api文档中 public @interface MyAnnotation2 { }
使用:
package com.tangguanlin.annotation; import com.tangguanlin.annotation.MyAnnotation; public class AnnotationDemo2 { @MyAnnotation2 public void show2(){ //替代show1()方法 } }
生成java doc文档:
4.4.4 @Inherited@Inherited:描述注解是否被子类继承
//使用 @Inherited public @interface MyAnnotation2 { }
定义:
package com.tangguanlin.annotation; import java.lang.annotation.*; @Inherited //描述注解是否被子类继承 public @interface MyAnnotation2 { }4.4.5 元注解总结
比较常用的元注是:
@Target 描述注解能够作用的位置
@Retention 描述注解被保留的阶段
5 解析注解解析注解:获取注解中定义的属性值
1.获取注解定义的位置对象(Class,Method,Field)
ClassreflectTestClass = ReflectTest.class;
2.获取指定的注解
ProAnnatation proAnnatation = reflectTestClass.getAnnotation(ProAnnatation.class);
其实就是在内存中生成了一个该注解接口的子类实现对象
public class ProAnnatationImpl implements Pro{ public String classname(){ return "com.tangguanlin.annotation.Student"; } public String method(){ return "sleep"; } }
3.调用注解中的抽象方法获取配置的属性值
String className = proAnnatation.classname();
案例:
需求:框架类 写一个“框架”,不能改变该类的任何代码的前提下,可以帮我们创建任意类的对象,并且执行其中任意方法
实现:
Student.java
package com.tangguanlin.annotation; public class Student { public void sleep(){ System.out.println("sleep..."); } }
ProAnnatation.java 注解
package com.tangguanlin.annotation; 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 ProAnnatation { public String classname(); public String method(); }
ReflectTest.java
package com.tangguanlin.annotation; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @ProAnnatation(classname = "com.tangguanlin.annotation.Student",method = "sleep") public class ReflectTest { public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException { //1.解析注解 //1.1 获取该类的字节码文件对象 ClassreflectTestClass = ReflectTest.class; //1.2.获取上边的注解对象 //其实就是在内存中生成了一个该注解接口的子类实现对象 ProAnnatation proAnnatation = reflectTestClass.getAnnotation(ProAnnatation.class); //1.3.调用注解对象中定义的抽象方法,获取返回值 String className = proAnnatation.classname(); String methodName = proAnnatation.method(); //3.加载该类进内存 Class c1= Class.forName(className); //4.创建对象 Object object = c1.newInstance(); // 5.获取方法对象 Method method = c1.getMethod(methodName); //6.执行方法 method.invoke(object); } }
运行结果:
sleep...6 注解案例 6.1 需求
写一个简单的测试框架,
当主方法执行后,会自动被检测的所有方法(加了@check注解的方法),判断方法是否有异常,记录到文件中
6.2 代码实现 6.2.1 定义注解注解类Check.java:定义注解
package com.tangguanlin.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface Check { }6.2.2 使用注解
计算器类Calculator.java:使用注解
package com.tangguanlin.annotation; public class Calculator { //加法 @Check public void add(){ String str =null; str.toString(); 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)); } public void show(){ System.out.println("永无bug..."); } }6.2.3 解析注解
TestCheck.java: 解析注解,利用注解实现功能
package com.tangguanlin.annotation; 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 InvocationTargetException, IllegalAccessException, IOException { //1.创建计算器对象 Calculator calculator = new Calculator(); //2.获取字节码文件对象 ClasscalculatorClass = Calculator.class; //3.获取所有方法 Method[] methods = calculatorClass.getMethods(); int number = 0; //出现异常的次数 BufferedWriter bw = new BufferedWriter(new FileWriter("bug.txt")); for(Method method:methods){ //4.方法上是否有@check注解 Check annotation = method.getAnnotation(Check.class); if(annotation!=null){ //5.执行方法 try { method.invoke(calculator); }catch (Exception e){ number++; //6.捕获异常,记录到文件 bw.write(method.getName()+"方法出异常了"); bw.newline(); bw.write("异常的名称:"+e.getCause()); bw.newline(); bw.write("异常的原因:"+e.getCause().getMessage()); bw.newline(); bw.write("-----------------------------"); } } } bw.newline(); bw.write("本次测试一共出现"+number+"次异常"); bw.flush(); bw.close(); } }
运行结果:
bug.txt文件内容:
add方法出异常了 异常的名称:java.lang.NullPointerException 异常的原因:null -----------------------------div方法出异常了 异常的名称:java.lang.ArithmeticException: / by zero 异常的原因:/ by zero ----------------------------- 本次测试一共出现2次异常6.3 小结
1.以后大多数时候,我们会使用注解,而不是自定义注解
2.注解给谁用?
2.1 编译器
2.2 给解析程序用 比如:TestCheck.java
3.注解不是程序的一部分,可以理解为注解就是一个标签
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)