一、什么是注解
1、语法:@注解名称
2、注解的作用:代替xml配置文件,servlet3.0中就可以不再使用web.xml,而是使用注解代替,注解是有框架来读取使用的。
3、注解的使用
- 定义注解类:框架的工作
- 使用注解:我们的工作
- 读取注解:框架的工作
二、java中的注解
@Override
:作用在方法上,当方法不是重写父类的方法时会报错@Deprecated
:作用在方法上。标记该方法为作废方法SuppressWarning
:作用在方法上,压制警告
三、注解的作用目标
- 类
- 方法
- 构造器
- 参数
- 局部变量
- 包
四、自定义注解
1、定义注解类
所有的注解都是Annocation接口的实现,不用标明。
@interface A {
}
2、注解的属性
- 定义属性:
语法:类型 属性名();
@interface MyAnno {
int age();
String name();
}
- 使用注解时给属性赋值
@MyAnno(age=100, name="lala")
public class AClass {
}
- 注解属性的默认值
在使用注解时,可以不给带有默认值的属性赋值。
@MyAnno(name="lala")
public class AClass {
}
@interface MyAnno {
int age() default 100;
String name();
}
- 名为
value
的属性的特权
在使用注解时,如果只给名为value
的属性赋值,那么可以不给出属性名称直接赋值。
@MyAnno(100)
public class AClass {
}
@interface MyAnno {
int value();
String name() default "lala";
}
- 注解属性的类型:8种基本类型,String,Enum,Class,注解,以上类型的一维数组类型
@MyAnno(
a=100,
b="hello",
c=myEnum.ONE,
d=String.class,
e=@YouAnno,
f= {"dsa","das"}//给数组赋值时,若数组元素的个数为1时,可以省略大括号
)
public class AClass {
}
enum myEnum {
ONE,TWO,THREE
};
@interface YouAnno {
}
@interface MyAnno {
int a();
String b();
myEnum c();
Class d();
YouAnno e();
String[] f();
}
3、注解的作用目标限定以及保存策略限定
让一个注解的作用目标只能在类上,不能再方法上,这就是目标限定。
@MyAnno(a=100,b="hello")
public class AClass {
public void fun() {
}
}
@Target(value= {ElementType.TYPE})
@interface MyAnno {
int a();
String b();
}
JDK中的Target的源码和ElementType的源码
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
/**
* Returns an array of the kinds of elements an annotation type
* can be applied to.
* @return an array of the kinds of elements an annotation type
* can be applied to
*/
ElementType[] value();
}
public enum ElementType {
/** Class, interface (including annotation type), or enum declaration */
TYPE,
/** Field declaration (includes enum constants) */
FIELD,
/** Method declaration */
METHOD,
/** Formal parameter declaration */
PARAMETER,
/** Constructor declaration */
CONSTRUCTOR,
/** Local variable declaration */
LOCAL_VARIABLE,
/** Annotation type declaration */
ANNOTATION_TYPE,
/** Package declaration */
PACKAGE,
/**
* Type parameter declaration
*
* @since 1.8
*/
TYPE_PARAMETER,
/**
* Use of a type
*
* @since 1.8
*/
TYPE_USE,
/**
* Module declaration.
*
* @since 9
*/
MODULE
}
保留策略:
- 源代码文件(
SOURCE
):注解只在源码中存在,当编译时就被忽略了 - 字节码文件(
CLASS
):注解在源代码中存在,探后编译时会把注解信息放到class文件中,但是JVM在加载类时,会忽略注解 - JVM中(
RUNTIME
):注解在源代码中存在,探后编译时会把注解信息放到class文件中,在JVM加载类时也会被加载到内存(唯一可被反射)
限定注解的保留策略
@Target(value= {ElementType.TYPE})
@Retention(RetentionPolicy.CLASS)
@interface MyAnno {
int a();
String b();
}
JDK中RetentionPolicy的源码
public enum RetentionPolicy {
/**
* Annotations are to be discarded by the compiler.
*/
SOURCE,
/**
* Annotations are to be recorded in the class file by the compiler
* but need not be retained by the VM at run time. This is the default
* behavior.
*/
CLASS,
/**
* Annotations are to be recorded in the class file by the compiler and
* retained by the VM at run time, so they may be read reflectively.
*
* @see java.lang.reflect.AnnotatedElement
*/
RUNTIME
}
4、读取注解(反射)
(1)反射泛型信息
Class类中有一个public Type getGenericSuperclass()
函数,该函数返回Type
,我们查阅JDK文档可以发现:
然后我们看一下Type
的子接口ParameterizedType
:
可以看到ParameterizedType
就是参数化类型 ,它等同于A<String>
这个部分,该类型提供了Type[] getActualTypeArguments()
方法,可以得到类型参数就是A<String>中的String
,它返回一个Type[]
等同于Class[]
。
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
public class BClass<T> {
public BClass() {
Class clazz = this.getClass();//得到子类的类型
//它就是BClass<String>
ParameterizedType ptype = (ParameterizedType) clazz.getGenericSuperclass();
Type[] t = ptype.getActualTypeArguments();
Class c = (Class)t[0];
System.out.println(c.getName());
}
public static void main(String[] args) {
new C();
}
}
class C extends BClass<String> {
}
class D extends BClass<Integer> {
}
运行结果
(2)反射注解
要求:这个注解的保留策略必须为RUNTIME
反射注解需要从作用目标上返回:
- 类上的注解,需要使用
Class
来获取 - 方法上的注解,需要
Method
来获取 - 构造器上的注解,需要
Construcator
来获取 - 成员上的注解,需要
Filed
来获取
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Method;
@MyAnno(a=100,b="hello")
public class AClass {
public static void main(String[] args) throws NoSuchMethodException, SecurityException {
//1、得到作用目标
Class c = AClass.class;
@SuppressWarnings("unchecked")
Method m = c.getMethod("fun");
//2、获取指定类型的注解
MyAnno myAnno = (MyAnno) c.getAnnotation(MyAnno.class);
MyAnno myAnno2 = m.getAnnotation(MyAnno.class);
System.out.println(myAnno.a()+" "+myAnno.b());
System.out.println(myAnno2.a()+" "+myAnno.b());
}
@MyAnno(a=200,b="world")
public void fun() {
}
}
@Target(value= {ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnno {
int a();
String b();
}