文章目录
- 注解
- 注解的作用
- 注解的语法
- 注解的使用
- 元注解
- 注解处理器
- 案例
- 注解VS配置文件
- 注解的应用
注解
- Annotation是代码里的特殊标记,这些标记可以在编译、类加载、运行时被读取,并执行相应的处理
- 可以把Annotation理解为一个标签
- 注解是不允许继承的
注解的作用
- 通过使用Annotation,程序开发人员可以在不改变原有逻辑的情况下,在源文件嵌入一些补充信息
- Annotation就像修饰符一样被使用,可用于修饰类、构造器、方法、成员变量、参数…,这些信息被存储在Annotation的“属性名=属性值”对中。
注解 VS 注释
- 相同点
- 都是用来传递额外信息的
- 不同点
- 注解可以参与编译,注释不行
- 注解有使用范围,注释没有(想咋写咋写)
- 注解作为一种数据类型,跟class interface具有同等地位
注解的语法
权限修饰符 @interface 注解名字{
// 注解体定义
属性类型 属性名();
属性类型 属性名();
属性类型 属性名();
......
}
属性类型:
基本数据类型
String类型
Class类型
注解类型
枚举类型
以及以上类型的数组形式
eg:
public @interface MyAnnotation {
int a1();
double a2();
String a3();
Class a4();
MyAnnotation2 a5();
String[] str();
Season a6();
}
@interface MyAnnotation2{
}
enum Season{
SPRING,
SUMMER,
AUTUMN,
WINTER
}
注解的使用
@注解名(属性1=属性值,属性2=属性值)
注意事项:
-
每个属性都要赋值
-
可以不赋值,但是要有默认值, default
-
数组形式赋值
{}
-
如果只有1个属性, 名字叫value, 可以简化赋值
-
如果属性类型是引用类型, 不能是null
eg:
public class Demo {
public static void main(String[] args) {
}
@MyAnno0(hobby = {"football", "basketball", "tennis"})
@MyAnno1("zs")
public static void func() {
}
}
@interface MyAnno0 {
// 注解体
int age() default 0;
String name() default "zs";
String[] hobby();
}
@interface MyAnno1 {
// 注解体
String value();
}
元注解
- 描述注解的注解(注解的注解)
- 元数据 meta data
常用元注解:
-
@Retention
元注解,来定义我们自己定义的注解的保留级别-
RetentionPolicy.RUNTIME
-
RetentionPolicy.CLASS
默认 -
RetentionPolicy.SOURCE
-
-
@Target
元注解,注解可以作用的目标-
对于注解而言,可以作用的目标:
-
- 整个类
ElementType.TYPE
- 整个类
-
- 成员变量
ElementType.FIELD
- 成员变量
-
- 构造方法
ElementType.CONSTRUCTOR
- 构造方法
-
- 成员方法
ElementType.METHOD
- 成员方法
-
-
eg:
注解处理器
eg:
public class Demo {
public static void main(String[] args)
throws ClassNotFoundException, NoSuchMethodException {
// 获取字节码文件对象
Class<?> c = Class.forName("com.csdn.Demo");
// 得到方法对象
Method loginMethod = c.getDeclaredMethod("login");
// 判断方法上面是否使用注解了
boolean annotationPresent = loginMethod.isAnnotationPresent(Login.class);
if(annotationPresent){
// 获取注解实例
Login loginAnnotation = loginMethod.getAnnotation(Login.class);
// 获取注解信息
String password = loginAnnotation.password();
String name = loginAnnotation.name();
// 打印
System.out.println("password = " + password);
System.out.println("name = " + name);
}
else{
System.out.println("未使用注解");
}
}
@Login
public static void login(){
}
}
// 定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface Login{
// 属性值
String name() default "admin";
String password() default "admin";
}
案例
定义2个注解 :
-
AgeLimit 属性 maxAge minAge
-
NameLimit 属性 length
定义学生类Student 年龄18-25之间 名字长度不超过5
eg:
StudentFactory自己定义的类:
public class StudentFactory {
static Class studentUtils;
static {
try {
studentUtils = Class.forName("com.cskaoyan.Demo0112.Student");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
// 提供一个获取学生对象的方法
public static Student getInstance(String name, int age)
throws NoSuchFieldException, NoSuchMethodException,
InvocationTargetException,
InstantiationException, IllegalAccessException {
// 通过字节码文件获取对象
// 判断名字
judgeName(name);
// 判断年龄
judgeAge(age);
// 获取构造方法
Constructor declaredConstructor =
studentUtils.getDeclaredConstructor(String.class, int.class);
// 破解
declaredConstructor.setAccessible(true);
// newInstance 创建对象
Student student = (Student) declaredConstructor.newInstance(name, age);
// 最终返回一个学生对象
return student;
}
private static void judgeAge(int age) throws NoSuchFieldException {
// 获取age成员变量对象
Field ageField = studentUtils.getDeclaredField("age");
// 是否使用注解
boolean annotationPresent = ageField.isAnnotationPresent(AgeLimit.class);
if (annotationPresent) {
// 获取注解实例
AgeLimit ageLimit = ageField.getAnnotation(AgeLimit.class);
// 拿到注解信息
int min = ageLimit.minAge();
int max = ageLimit.maxAge();
// 是否在范围内
if (age < min || age > max) {
throw new IllegalArgumentException("age is illegal");
}
}
}
private static void judgeName(String name) throws NoSuchFieldException {
// 获取name成员变量
Field nameField = studentUtils.getDeclaredField("name");
// 是否使用注解
boolean annotationPresent = nameField.isAnnotationPresent(NameLimit.class);
if (annotationPresent) {
// 获取注解实例
NameLimit namelimit = nameField.getAnnotation(NameLimit.class);
// 拿到注解信息
int length = namelimit.length();
// 是否在范围内
if (name.length() > length) {
throw new IllegalArgumentException("name is illegal");
}
}
}
}
main函数:
public class Demo {
public static void main(String[] args)
throws NoSuchFieldException, InvocationTargetException,
NoSuchMethodException, InstantiationException,
IllegalAccessException {
StudentFactory.getInstance("zs",18);
StudentFactory.getInstance("ww",1);
}
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface AgeLimit{
int maxAge() default 25;
int minAge() default 18;
}
@interface NameLimit{
int length();
}
class Student{
@NameLimit(length = 5)
String name;
@AgeLimit
int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
注解VS配置文件
配置文件
优点:可配置,不用改源码。管理方便
缺点:不直观,开发效率低
注解
优点:直观开发效率高
缺点:硬编码,修改之后需要重新编译运行,难以和代码分开独立管理
注解的应用
SE :
@Test
@Override
(提供一个额外的信息,方法是重写父类中的方法)@Deprecated
(提供一个额外的信息,方法过时了)@FunctionalInterface
EE :
@WebService
框架:
@AutoWired
@Service
@Mapping
@Data
@Parm