java学习笔记:注解Annotation
注解Annotation
----
1.注解的概念:
注解也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、抽象类是在同一个层次,同属于数据类型。
注释是给开发人员阅读的,注解是给计算机提供相应信息的。
2.作用:
(1)编译检查:通过代码里标识的注解,让编译器能够实现基本的编译检查。例如:
@Override
Person{ void getSalray(){} }
(2)充当配置文件
如果配置的信息不会发生频繁的修改,采用注解的配置,例如:
@WebServlet("/ServletDemo01")
如果配置的信息可能会发生频繁的修改,采用web.xml/properties的配置。例如:
mysql的用户名和密码不推荐采用注解配置形式
@MyAnn(name="user",pass="1234")
class JDBCUtils{}
(3)javadoc编写文档:辅助生成帮助文档。例如:
@author @see @since
-encoding utf-8 -charset utf-8
3.JDK的三种注解
@Override :当前方法是重写父类的方法/重写接口的方法
@Deprecated当前方法是过时的方法
@SuppressWarnings("all")告诉编译器,当前类内不要报任何警告信息
(1)注释的位置:注解可以加载在变量上,方法上,类上
(2)注解的形式
*_没有任何成员的注解
@Override
*_有多个成员的注解
@SuppressWarnings({ "rawtypes", "unused" })
(3)注解的作用范围
1_源码上有效:eg:String类中@author ,将java源码转换为帮助文档期间起作用
2_编译期间有效:eg: override deprecated SuppressWarnings("all")
3_运行期间有效
4.定义注解(理解并代码实现)
1_定义没有属性成员注解:
public @interface MyAnno01{}
2_定义有1个属性成员注解
public @interface MyAnno02{
public String value();
}
3_定义有多个属性成员注解
public @interface 注解名称{
public 类型名称 属性名称() default 默认值;
public 类型名称 属性名称() default 默认值;
//注解支持的类型:基本类型(4类8种),String,Class(字节码类型),
//annotaion(注解),enumeration(枚举),以上类型支持的一维数组类型
}
public @interface MyAnno03 {
//定义多个属性的注解
public String username() default "tom";
//public Father f();
//Invalid type Father for the annotation attribute MyAnno03.f;
//only primitive type, String, Class, annotation, enumeration are permitted
//or 1-dimensional arrays thereof
//非法的注解属性f,仅仅是原始(基本)类型,String ,Class,annotation,
//枚举类型是被允许的或者以上的一维数组类型是允许的
//注解支持的类型:基本类型(4类8种),String,Class(字节码类型),
//annotaion(注解),enumeration(枚举),以上类型支持的一维数组类型
public int age();
public double weight() default 2342.23;
public Class clazz();
public MyAnno01 my01();
}
5_使用自定义注解(理解实现代码)
没有任何属性的注解
有1个属性的注解
有多个属性的注解
@MyAnno01
@MyAnno02(value="testtest")
@MyAnno03(age=18,clazz=String.class,username="tom",weight=23.23,my01=@MyAnno01)
public class MyClass {}
注意:如果注解只有一个属性,而且这个属性的名称是value,那么在使用这个注解的使用,可以采用如下形式: 直接为属性赋值,不需要采用key=”vaule”的形式
@MyAnno02("testtest")
public class MyClass02 {}
注解的作用:实现配置
注意:如果配置信息不经常修改,用注解形式。如果配置的信息需要频繁修改,推荐properties或者XML
6.通过反射获取方法上的注解信息(理解并实现代码)
1_理解反射的本质
反射本质上是在做什么事情?
前提:实现JAVA代码,将JAVA编译为class文件.编译完之后class文件在硬盘上,
当需要执行class文件中的代码时,JDK内置程序(类加载器):
通过IO流的形式将字节码的内容读取到内存. 字节码在内存中形成的对象就是Class对象
通过Class对象创建对象,获取字节码对象上所有的方法,调用这些方法使其执行
类加载器:JDK中内置的一类程序,这类程序专业用于将硬盘上的字节码文件加载到内存中.
类加载器有3种: 应用类加载器,扩展类加载,根类加载器
2_测试通过反射获取注解信息的API
常用方法:
boolean isAnnotationPresent(Class annotationClass) 判断当前对象上是否有指定类型的注解
3_JAVA中的元注解
元注解:用于修饰注解的注解
Jdk提供4种元注解
(1)@Retention 用于确定被修饰的自定义注解生命周期,确定自定义注解的生命周期的
可能取值:
RentionPolicy.SOURCE,被修饰的注解只能用于源码中,字节码class没有。用途:提供给编译器使用
RentionPolicy.CLASS 被修饰的注解只能存在于源代码或字节码中,运行时内存中没有。用途:JVM java虚拟机使用
RentionPolicy.RUNTIME 被修饰的注解存在于源码,字节码,内存(运行时)。用途:取代XML充当配置信息
(2)@Target 用于确定被修饰自定义注解使用位置
可能取值
ElementType.TYPE 修饰类,接口
ElementType.CONSTRUCTOR 修饰构造函数
ElementType.METHOD 修饰方法
ElementType.FIELD 修饰字段
(3)@Documented 使用javadoc生成api文档是,是否包含此注解(了解)
代码如下:
//file name: MyAnno.java
package com.study.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(value = ElementType.METHOD)
public @interface MyAnno {
}
//file name: AAA.java
package com.study.annotation;
public class AAA {
@MyAnno
public void test01(){}
@MyAnno
public void test02(){}
public void test03(){}
}
//file name: TestMyAnnotationRead.java
package com.study.annotation;
import java.lang.reflect.Method;
public class TestMyAnnotationRead {
public static void main(String[] args) {
Class clazz = AAA.class;
Method[] methods = clazz.getMethods();
for (Method m : methods) {
if(m.isAnnotationPresent(MyAnno.class)){
System.out.println(m.getName());
}
}
}
}
7.案例_模拟Junit(动手实现)
*_案例分析
1_首先需要编写自定义注解@MyTest,并添加元注解,
保证自定义注解只能修饰方法,且在运行时可以获得。
2_其次编写目标类(测试类),然后给目标方法(测试方法)使用@MyTest注解
3_最后编写测试类,使用main方法模拟Junit的右键运行。
*_案例代码
步骤1:编写自定义注解类@MyTest
package com.study.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 MyTest{
}
步骤2:编写目标类AnnotationDemo
package com.study.annotation;
public class AnnotationDemo {
@MyTest
public void demo01(){
System.out.println("demo01 执行了……");
}
@MyTest
public void demo02(){
System.out.println("demo02 执行了……");
}
public void demo03(){
System.out.println("demo03 执行了……");
}
}
步骤3:编写测试方法
package com.study.annotation;
import java.lang.reflect.Method;
public class App {
public static void main(String[] args) {
try{
//1.1 反射:获得类的字节码对象.Class
Class clazz = AnnotationDemo.class;
//1.2 获得实例对象
Object obj = clazz.newInstance();
//2 获得目标类所有的方法
Method[] allMethod = clazz.getMethods();
//3 遍历所有的方法
for (Method method : allMethod) {
//3.1 判断方法是否有MyTest注解
boolean flag = method.isAnnotationPresent(MyTest.class);
if(flag){
//4 如果有注解,运行指定的类
method.invoke(obj, args);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
====