java注解
2021-01-17 01:15
标签:java 注解 字节码 成员变量 案例 package 指定 组类型 参数 注释是给开发者看的,可以提升代码的可阅读性和可维护性,但是对于java编译器和虚拟机来说是没有意义的,编译后的字节码文件中没有任何注释信息。 而注解和注释有些类似,不过注解是给编译器和虚拟机看的。编译器和虚拟机可以在运行过程中获取注解信息,然后根据注解信息做各种想做的事。 下面定义了一个自定义注解: 注解的定义需要注意: 使用target注解标注注解的使用范围: ElementType取值: 使用Retention注解表示该注解的生效范围 RetentionPolicy的取值: 正常情况下,自定义注解上都要标注target和retention注解。 jdk8新增了TYPE_PARAMETER和TYPE_USE类型 为了运行时能准确获取注解的信息,Java在java.lang.reflect反射包下新增了AnnotatedElement接口,他主要用于表示目前正在虚拟机中运行的程序中已 使用注解的元素,通过该接口提供的方法可以利用反射技术读取注解信息。 首先看这个注解的源码: 根据ElementType的值可以知道这个注解是专门作用在注解上的。 自定义一个注解。首先来看不加这个注解的效果 可以看到我们获取不到父类的注解信息。下面在试试加上这个注解: 再次执行上面的main方法: 再试下在接口上使用该注解: 定义注解: 看下面一段代码: 默认情况下,注解是不允许重复使用的,如果我们想像上面一样重复使用注解,需要添加Repeatable注解 看一下Repeatable注解: 注意value是没有默认值的,因此使用时要对value属性赋值。值是一个容器注解。容器注解的定义要求如下: 容器注解必须有一个value参数,参数类型为子注解类型的数组。 使用Repeatable注解: 此时使用重复注解就不会报错了。 要先导入spring-core的依赖。 首先我们来看一个问题: AnnotatedElementUtils是spring封装的工具类。此时有个问题,如果我们像要在给B1赋值的时候同时给B1上的A1设置值,是没有办法的,这是由于注解定义 无法继承导致的。Spring通过Aliasfor注解解决了这个问题。 通过Aliasfor解决上面的问题: 运行结果: 我们看一下使用Aliasfor的地方的代码: annatation表示要给哪儿个注解赋值,value表示注解的方法,本例中我们要将a1Value()的值赋值给A1注解的value方法。 看一下Aliasfor注解: 在value和attribute方法上使用了Aliasfor注解,说明给value赋值时同时就会给attribute赋值,给attribute赋值时同时会给value赋值 java注解 标签:java 注解 字节码 成员变量 案例 package 指定 组类型 参数 原文地址:https://www.cnblogs.com/Zs-book1/p/12916281.htmljava注解篇
什么是注解?
注解如何使用?
定义注解
public @interface Anno0 {
String value() default "";
}
@interface
。
public @interface Anno1 {
String value();
String name() default "";
}
public @interface Anno2 {
String name();
}
// 注解的使用
@Anno1(value = "value属性没有默认值必须要传值")
public class AnnoTest {
}
@Anno1(value = "value属性没有默认值必须要传值",name = "覆盖掉默认的name属性值")
public class AnnoTest {
}
@Anno0("不写赋值的属性名称时,默认给value赋值,必须保证有value这个属性")
public class AnnoTest {
}
@Anno2(name = "必须有属性名为value()时,才可以忽略不写属性名,括号内直接赋值")
public class AnnoTest {
}
使用注解
@Target(ElementType.TYPE)
public @interface Anno0 {
String value() default "";
}
public enum ElementType {
/** 类、接口(包括注解类型)、枚举类上 */
TYPE,
/** 字段(包括常量)上 */
FIELD,
/** 方法上 */
METHOD,
/** 方法参数上 */
PARAMETER,
/** 构造方法上 */
CONSTRUCTOR,
/** 本地变量上 */
LOCAL_VARIABLE,
/** 注解上 */
ANNOTATION_TYPE,
/** 包上 */
PACKAGE,
/**
* 类型参数上
*
* @since 1.8
*/
TYPE_PARAMETER,
/**
* 使用到类型的任意语句中
* @since 1.8
*/
TYPE_USE
}
@Retention(RetentionPolicy.RUNTIME)
public @interface Anno0 {
String value() default "";
}
public enum RetentionPolicy {
/**
* 只在源码中生效,编译及运行时就丢失了,也就是class文件中就不存在了。
*/
SOURCE,
/**
* 注解会被保留在编译后的class文件中,但是不会被保留在VM虚拟机在运行阶段
*/
CLASS,
/**
* 注解在源码,class字节码以及运行阶段都存在
* @see java.lang.reflect.AnnotatedElement
*/
RUNTIME
}
无参数
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Anno2 {
}
// 使用注解
@Anno2
public class AnnoTest {
}
一个参数的
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Anno0 {
String value() default "";
}
@Anno0("属性名为value可以省略")
public class AnnoTest {
}
多个参数
public @interface Anno1 {
String value();
String name() default "";
}
@Anno1(value = "属性名为value可以省略",name = "多个参数注解要指定属性名")
public class AnnoTest {
}
数组类型参数
public @interface Anno3 {
String[] name() default {};
}
@Anno3(name = {"数组类型", "以逗号分隔", "大括号{}包裹"})
public class AnnoTest {
}
// 当只有一个值时可以省略大括号
@Anno3(name= "数组类型")
public class AnnoTest {
}
// 当属性名为value时,可以省略
@Anno3({"数组类型", "属性值为value省略"})
public class AnnoTest {
}
// 只有一个值
@Anno3("数组类型")
public class AnnoTest {
}
不同ElementType的用法
// Type 类型可以用在类,接口,注解,枚举类型上
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Anno4 {
String name();
}
@Anno4(name = "用在注解上")
public @interface AnnoTest{}
@Anno4(name = "用在类上")
class TypeTest{}
@Anno4(name = "用在接口上")
interface InterfaceTest{}
@Anno4(name = "用在枚举上")
enum EnumTest{}
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR,
ElementType.PARAMETER, ElementType.LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Anno5 {
String name();
}
public class AnnotationTest {
@Anno5(name = "作用在字段上")
private String name;
@Anno5(name = "作用在构造方法上")
AnnotationTest(){}
@Anno5(name = "作用在方法上")
void fun1(@Anno5(name = "作用在参数上") String param) {
@Anno5(name = "作用在本地变量")
int i = 1;
}
}
@Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Anno6 {
String value() default "";
}
abstract class Test{
abstract K fun1(V v);
}
class Test1{
public static void main(String[] args) {
Test test = new Test
注解信息的获取
AnnonatedElement常用方法
返回值
方法名称
说明
A extends Annotation
getAnnotation(Class AnnotationClass)
该元素如果存在指定类型的注解,则返回该注解,否则返回null
Annotation[]
getAnnotations()
返回此元素上的所有注解,包括从父类上继承的
boolean
isAnnotationPresent(Class extends Annotation> annotationClass)
如果指定类型的注解存在此元素上,则返回true,否则false
Annotation[]
getDeclaredAnnotations()
返回直接存在此元素上的所有注解,不包括父类继承的注解。
使用案例:
public class AnnotationUseTest {
public static void main(String[] args) {
Anno4 anno4 = A.class.getAnnotation(Anno4.class);
System.out.println("获取类A上的Anno4注解信息:" + anno4.name());
Annotation[] annotations = A.class.getAnnotations();
System.out.println("获取类A上的所有注解:");
for (Annotation annotation : annotations) {
System.out.println("类A上的注解:" + annotation);
}
Anno4 annotation = AnnoTest.class.getAnnotation(Anno4.class);
System.out.println("获取AnnoTest注解上的Anno4注解的信息:" + annotation);
Field desc = ReflectionUtils.findField(A.class, "desc");
Optional.ofNullable(desc).ifPresent(a -> {
System.out.println("字段上的注解:" + a.getAnnotation(Anno5.class));
System.out.println(a.getAnnotatedType().getAnnotation(Anno6.class));
});
Constructor> constructor = A.class.getDeclaredConstructors()[0];
Anno5 annotation1 = constructor.getAnnotation(Anno5.class);
System.out.println("构造方法上的注解:" + annotation1);
Method setDesc = ReflectionUtils.findMethod(A.class, "setDesc", String.class);
Optional
@Inherit 类之间注解的继承
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Inherited {
}
作用:让子类可以继承父类中被@Inherited修饰的注解。注意是继承父类的,如果接口上的注解也用@Inherited修饰了,那么接口的实现类无法继承这个注解 首先我们看不加这个注解:@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Anno7 {
String[] notes() default {};
String desc() default "";
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Anno7 {
String[] notes() default {};
String desc() default "";
}
@Anno7(desc = "不加Inherited")
abstract class AbstractAnno7{
}
public class Anno7Test extends AbstractAnno7 {
public static void main(String[] args) {
Annotation[] annotations = Anno7Test.class.getAnnotations();
// annotations数组为空数组,因此无结果打印
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
}
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface Anno7 {
String[] notes() default {};
String desc() default "";
}
@Anno7(desc = "加Inherited")
abstract class AbstractAnno7{
}
public class Anno7Test extends AbstractAnno7 {
public static void main(String[] args) {
Annotation[] annotations = Anno7Test.class.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation);//@com.xiazhi.annocation.Anno7(desc=加Inherited, notes=[])
}
}
}
@Anno7(desc = "使用在接口上")
interface IAnno7{}
public class Anno7Test implements IAnno7 {
public static void main(String[] args) {
Annotation[] annotations = Anno7Test.class.getAnnotations();
// 无结果
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
}
}
Repeatable 重复使用注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Anno8 {
}
@Anno8
@Anno8 // 这里会报错
public class Anno8Test {
}
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Repeatable {
/**
* Indicates the containing annotation type for the
* repeatable annotation type.
* @return the containing annotation type
*/
Class extends Annotation> value();
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Anno8s {
Anno8[] value();
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(Anno8s.class)
public @interface Anno8 {
}
@Anno8
@Anno8
public class Anno8Test {
}
spring对于注解的增强
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface A1{
String value() default "a1";
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@A1
@interface B1{
String value() default "b1";
}
@B1("hello")
public class DemoTest {
public static void main(String[] args) {
System.out.println(AnnotatedElementUtils.getMergedAnnotation(DemoTest.class, B1.class));
System.out.println(AnnotatedElementUtils.getMergedAnnotation(DemoTest.class,A1.class));
}
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface A1{
String value() default "a1";
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@A1
@interface B1{
String value() default "b1";
@AliasFor(value = "value",annotation = A1.class)
String a1Value();
}
@B1(value = "hello", a1Value = "给A1的value赋值")
public class DemoTest {
public static void main(String[] args) {
System.out.println(AnnotatedElementUtils.getMergedAnnotation(DemoTest.class, B1.class));
System.out.println(AnnotatedElementUtils.getMergedAnnotation(DemoTest.class, A1.class));
}
}
@com.xiazhi.annocation.B1(value=hello, a1Value=给A1的value赋值)
@com.xiazhi.annocation.A1(value=给A1的value赋值)
@AliasFor(value = "value",annotation = A1.class)
String a1Value();
Aliasfor 注解
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Documented
public @interface AliasFor {
@AliasFor("attribute")
String value() default "";
@AliasFor("value")
String attribute() default "";
Class extends Annotation> annotation() default Annotation.class;
}
在同一个注解中使用Aliasfor
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface An{
@AliasFor("value")
String name() default "";
@AliasFor("name") //如果不指定annotation属性,则默认是当前注解,如果不指定value和attribute,则自动将修饰的参数作为value和attribute的值
String value() default "";
}
@An(value = "hello")//同一个注解内设置Aliasfor注解时,如果给两个属性都赋值会报错
public class DemoTest2 {
public static void main(String[] args) {
An mergedAnnotation = AnnotatedElementUtils.getMergedAnnotation(DemoTest2.class, An.class);
System.out.println(mergedAnnotation);
}
}