java 注解数组初始化_javaSE第十三部分 Java注解

注解(Annotation)是放在Java源码的类、方法、字段、参数前的一种特殊“注释”。

注解是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在类、方法等的前面,用来对这些元素进行说明,注释。

与注释不同的是,注释会被编译器直接忽略,注解则可以被编译器打包进入class文件,因此,注解是一种用作标注的“元数据”。

从JVM的角度看,注解本身对代码逻辑没有任何影响,如何使用注解完全由工具决定。

Java的注解可以分为三类:

第一类是由编译器使用的注解,例如:

@Override:让编译器检查该方法是否正确地实现了覆写;

@SuppressWarnings:告诉编译器忽略此处代码产生的警告。

@Deprecated:该注解标注的内容,表示已过时

这类注解不会被编译进入.class文件,它们在编译后就被编译器扔掉了。

第二类是由工具处理.class文件使用的注解,

比如有些工具会在加载class的时候,对class做动态修改,实现一些特殊的功能。

这类注解会被编译进入.class文件,但加载结束后并不会存在于内存中。这类注解只被一些底层库使用,一般我们不必自己处理。

第三类是在程序运行期能够读取的注解,它们在加载后一直存在于JVM中,这也是最常用的注解。

例如,一个配置了@PostConstruct的方法会在调用构造方法后自动被调用(这是Java代码读取该注解实现的功能,JVM并不会识别该注解)。

自定义注解:

格式:

元注解

public @interface 注解名称{

属性列表;

}

其中,必须设置@Target和@Retention,@Retention一般设置为RUNTIME,因为我们自定义的注解通常要求在运行期读取。

注解本质上就是一个接口,该接口默认继承Annotation接口

public interface MyAnno extends java.lang.annotation.Annotation {}

属性的返回值类型有下列取值

1.基本数据类型

2.String

3.枚举

4.注解

5.以上类型的数组

定义了属性,在使用时需要给属性赋值

1. 如果定义属性时,使用default关键字给属性默认初始化值,则使用注解时,可以不进行属性的赋值。

2. 如果只有一个属性需要赋值,并且属性的名称是value,则value可以省略,直接定义值即可。

3. 数组赋值时,值使用{}包裹。如果数组中只有一个值,则{}可以省略

比如:

public class Hello {

@Check(min=0, max=100, value=55)

public int n;

@Check(value=99)

public int p;

@Check(99) // @Check(value=99)public int x;

@Check

public int y;

}

@Check就是一个注解。第一个@Check(min=0, max=100, value=55)明确定义了三个参数,

第二个@Check(value=99)只定义了一个value参数,它实际上和@Check(99)是完全一样的,

最后一个@Check表示所有参数都使用默认值。

元注解:

有一些注解可以修饰其他注解,这些注解就称为元注解(meta annotation)

@Target:描述注解能够作用的位置

ElementType.TYPE:可以作用于类上

ElementType.METHOD:可以作用于方法上

ElementType.FIELD:可以作用于成员变量上

ElementType.CONSTRUCTOR:可以作用在构造方法上

ElementType.PARAMETER:可以作用在方法的参数上

@Retention:定义了Annotation的生命周期

RetentionPolicy.SOURCE:仅编译期

RetentionPolicy.CLASS:仅class文件

RetentionPolicy.RUNTIME:运行期

SOURCE类型的注解主要由编译器使用,因此我们一般只使用,不编写。

CLASS类型的注解主要由底层工具库使用,涉及到class的加载,一般我们很少用到。

只有RUNTIME类型的注解不但要使用,还经常需要编写。

@Inherited:定义子类是否可继承父类定义的Annotation。

@Inherited仅针对@Target(ElementType.TYPE)类型的annotation有效,并且仅针对class的继承,对interface的继承无效。

@Documented:描述注解是否被抽取到api文档中

@Repeatable:描述这个元注解修饰的Annotation是否可重复。

使用注解:

判断某个注解是否存在于Class、Field、Method或Constructor:

Class.isAnnotationPresent(Class)

Field.isAnnotationPresent(Class)

Method.isAnnotationPresent(Class)

Constructor.isAnnotationPresent(Class)

使用反射API读取Annotation:

Class.getAnnotation(Class)

Field.getAnnotation(Class)

Method.getAnnotation(Class)

Constructor.getAnnotation(Class)

例子:

/*** 我们来看一个@Range注解,我们希望用它来定义一个String字段的规则:字段长度满足@Range的参数定以*/

package demo.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(ElementType.FIELD)

public @interface Range {

int min() default 0;

int max() default 255;

}

/*** 在Person这个JavaBean中使用Range注解*/

package demo.annotation;

public class Person {

@Range(min = 3,max = 10)

public String name;

public int age;

@Range(min = 5,max = 20)

public String address;

@Override

public String toString() {

return "Person{" +

"name='" + name + '\'' +

", age=" + age +

'}';

}

}

//写一个测试类package demo.annotation;

import org.junit.Assert;

import org.junit.Test;

import java.lang.reflect.Field;

import java.util.ArrayList;

public class PersonTest {

@Test

public void testPersonRange() throws Exception {

/*** 测试 isAnnotationPresent()和getAnnotation()*/

Field name = Person.class.getField("name");

Field age = Person.class.getField("age");

Field address = Person.class.getField("address");

/**判断某个注解是否存在于Class、Field、Method或Constructor* Field.isAnnotationPresent(Class)* 这里判断 Range 注解是否存在于 Field 中*/

Assert.assertEquals(true,name.isAnnotationPresent(Range.class));

Assert.assertEquals(false,age.isAnnotationPresent(Range.class));

Assert.assertEquals(true,address.isAnnotationPresent(Range.class));

/**通过Class、Field、Method或Constructor来获取修饰它的注解* Field.getAnnotation(Class)*这里我们获取修饰 Field 的注解 Range */

Range rangeName = name.getAnnotation(Range.class);

System.out.println(rangeName);

Assert.assertEquals(3,rangeName.min());

Assert.assertEquals(10,rangeName.max());

Range rangeAddress = address.getAnnotation(Range.class);

System.out.println(rangeAddress);

Assert.assertEquals(5,rangeAddress.min());

Assert.assertEquals(20,rangeAddress.max());

Range rangeAge = age.getAnnotation(Range.class);

Assert.assertEquals(null,rangeAge);

}

/**这里,我们编写一个Person实例的检查方法check,它可以检查Person实例的String字段长度是否满足@Range的定义*/

public ArrayList check(Person person) throws Exception{

ArrayList fieldList = new ArrayList<>();

// 遍历所有Fieldfor (Field field : person.getClass().getFields()) {

// 获取Field定义的@RangeRange range = field.getAnnotation(Range.class);

// 如果@Range存在if (range != null){

// 获取Field的值Object fieldValue = field.get(person);

// 如果Field的值是String,因为我们只对Person类中String类型的字段修饰了range注解if (fieldValue instanceof String){

//将Object强转为StringString value = (String)fieldValue;

//不符合Range注解的判断条件if (value.length() < range.min() || value.length() > range.max()){

System.out.println("Illegal field: " + field.getName());

fieldList.add(field.getName());

}

}

}

//如果@Range不存在,那么该Field没有注解else{

System.out.println("field do not have Annotation: : " + field.getName());

}

}

System.out.println(fieldList);

return fieldList;

}

@Test

public void testCheck() throws Exception {

Person person = new Person();

person.name = "tom";

person.age = 23;

person.address = "china beijing beijing";

ArrayList actualList = check(person);

//我们期望得到的结果是["address"]ArrayList expectedList = new ArrayList();

expectedList.add("address");

//断言通过,说明我们的测试通过Assert.assertEquals(expectedList,actualList);

}

}

输出:

@demo.annotation.Range(max=10, min=3)

@demo.annotation.Range(max=20, min=5)

field do not have Annotation: : age

Illegal field: address

[address]

本文参考:注解​www.liaoxuefeng.comd201df6b58fcfc96e1caf67e334a2e2e.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值