内容简介:Java注解入门
先上代码,再加以说明。这样不至于让初学者懵。
public class Dog extends Animal(){ @Override public void call(){ System.out.println("汪汪..."); } }
0.1 Java 自带注解 - @Override
方法call()上声明的@Override是Java自带的注解,它的作用是标记这个方法是重写的。当类继承的类或接口没有这个方法,编译时就会报错,因为你声明了这个注解的意图是希望重写某个方法。另外一个作用是在生成javadoc上这个方法也会显示@Override表示这个方法是重写的。
0.2 注解只是为代码提供描述
显然@Override并没有影响你的代码执行。你删注解,代码还是正常运行。这样我们就得出一个结论:Java注解只是为代码的元素(类,方法,方法参数等)提供描述。
0.3 注解处理
看到这里你可能觉得注解不没什么作用,但是想想看,上面讲到的编译时会报错,这是什么在起作用。虽然将注解本身并没有逻辑,但是你标注了注解这有助于其他程序执行。在这里,你标注了@Override,编译期发现你在这个方法标注了注解就会进行判断。
到这里你已经大概了解注解是用来干嘛的了。下面是正文部分,内容包括:
- 自定义注解
- Java自带注解
- 注解处理器
1.0 自定义注解
1.1元注解
我们打开@Override源码看看:
@Target(ElementType.METHOD) @Retention(RetentionPolicy.SOURCE) public @interface Override { }
注解源码非常简单,和接口的定义类似。它使用@interface修饰声明这是一个注解。另外面多了两个注解@Target和@Retention,我们将这些注解叫做元注解,它只用于自定义注解。
@Target
@Target表示你定义的这个注解能用在哪里。包括:
类型 | 描述 |
---|---|
ElementType.ANNOTATION_TYPE | 可以给一个注解进行注解 |
ElementType.CONSTRUCTOR | 构造方法 |
ElementType.FIELD | 类属性 |
ElementType.LOCAL_VARIABLE | 局部变量 |
ElementType.METHOD | 方法 |
ElementType.PACKAGE | 包 |
ElementType.PARAMETER | 方法参数 |
ElementType.TYPE | 类、接口、枚举等 |
可填多个,使用数组格式 {}
括起,并用 ,
隔开。
@Retention
@Retention表示自定义的注解的作用范围。可选
类型 | 描述 |
---|---|
RetentionPolicy.SOURCE | 只在源码时作用 |
RetentionPolicy.CLASS | 源码及编译期作用 |
RetentionPolicy.RUNTIME | 源码、编译期和运行时都起作用 |
另外还有两个可选元注解
@Documented
表示生成javadoc时也包括当前自定义注解
@Inherited
表示当前注解能被继承。但不是指继承自定义注解,是指某个类继承了一个使用了这个注解的类时,这个注解也被继承。
1.2 注解属性
接下来,我们来看看一个复杂一点的注解源码,这是Spring的@Bean源码:
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Bean { @AliasFor("name") String[] value() default {}; @AliasFor("value") String[] name() default {}; Autowire autowire() default Autowire.NO; String initMethod() default ""; String destroyMethod() default "(inferred)"; }
这个注解和上面最大的区别是注解体内多了很多方法。其实这些不是方法,而是注解的属性。有了这些属性,我们就可以进一步描述代码。
注解属性定义格式为 类型 属性名() default 初始值;
。
-
注解属性对类型是有限制的,只能是下面的类型:
- 8个基础类型
- Class
- String
- enum(上面Autowire 就是enum类型)
- Annotation
- 或上面类型的数组形式
-
default是一个修饰符,和
=
类似; -
初始值不为null,所以上面看到String类型用空字符串
""
; - 另外如果注解只有一个参数时属性名必须时value。
在使用注解时,可以像上面元注解@Target后面 ()
就是填写的属性。
- 当属性只有一个时,直接填写属性。即注解的value()属性;
-
如果多个需要用
@Target(属性名=属性值,属性名=属性值)
的形式填入;
2.0 Java自带注解
Java自带注解非常简单,只有三个。
@Override
用于标记方法是重写的。建议在重写的方法上标记,这有助与阅读和IDE对你的错误做出提示。
@Deprecated
用于声明被被标注的代码以过期,不建议使用。在编译时会得到错误导致编译失败。可以在除ANNOTATION_TYPE外的代码中标记。
@SupressWarning
虽然被标注了@Deprecated编译就会错误。当时有时久的程序代码,必须要使用这个类。这是可以使用@SupressWarning标注忽略@Deprecated导致编译错误。
注解处理
在开始我们讲到注解只是为代码提供描述,但是其他程序可以利用这些描述数据来判断如果执行操作。注解处理是使用Java反射来完成的。
注:反射简述。
类,方法,实例属性等本身也是对象,比如讲类定义的是什么修饰符,它有哪些方法,哪些实例属性,哪些注解。所以每个类其实都是Java的Class类型的实例,通过Class可以了解类本身的一切或操作某些特定功能。
比如讲,我们有一些动物类,我们创建了一个@Animal自定义注解表示他们的特性,例如脚数,咬不咬人。
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface AnimalTrait{ int footNum() default 0; boolean bitePeople default false; }
动物类
@AnimalTrait(footNum=4,bitePeople=true) class Dog extends Call{ public void call(){ System.out.println("汪汪..."); } } @AnimalTrait(footNum=4,bitePeople=false) class Cat extends Animal{ public void call(){ System.out.println("喵喵..."); } } @AnimalTrait(footNum=2,bitePeople=false) class Monkey extends Animal{ public void call(){ System.out.println("吖吖..."); } } //...其他动物类
假设我们有一个动物园集合,存放了全部动物的实例。我们现在要写一个类将咬人的动物和不咬人的动物分开到连个集合以便管理它们。
import java.util.ArrayList; public class Main { public static void main(String[] args) { ArrayList<Animal> zooAnimal = new ArrayList<>(); ArrayList<Animal> biteList = new ArrayList<>(); ArrayList<Animal> notbiteList = new ArrayList<>(); for(int i=0;i<8;i++){ zooAnimal.add(new Cat()); zooAnimal.add(new Dog()); } for(Animal animal:zooAnimal){ //主要部分,获取实例对应类型的@AnimalTrait注解的bitePeople属性 if(animal.getClass().getAnnotation(AnimalTrait.class).bitePeople()){ biteList.add(animal); } else { notbiteList.add(animal); } } System.out.println("咬人的动物叫声:"); for(Animal animal:biteList){ animal.call(); } System.out.println("不咬人的动物叫声:"); for(Animal animal:notbiteList){ animal.call(); } } }
其中主要的是的是获取注解信息的部分,条件中使用getClass获取实例类的Class实例,再用getAnnotation()获取类的@AnimalTrait的Annotation实例,最后通过.bitePeople()获取注解的属性值。
AnnotatedElement接口
所有反射类型Class、Constuctor、Method、Field等都继承了AnnotatedElement接口。接口的主要作用是获取注解的反射类型然后得到注解的属性。
AnnotatedElement接口常用方法
返回值 | 方法签名 | 描述 |
---|---|---|
<T extends Annotation> T | getAnnotation(Class<T> annotationClass) | 返回指定注解类型 |
Annotation[] | getAnnotations() | 返回全部注解的数组 |
default boolean | isAnnotationPresent(Class<? extends Annotation> annotationClass) | 判断是否存在指定类型的注解 |
Annotation类型
我们获得Annotation类型可以通过 .注解属性名()
的方式获取注解的属性。
总结
- Java注解只是对代码元素提供描述,它并不影响代码执行;
- 影响代码执行的是注解处理器,利用反射机制获取注解属性;
- 通过@interface定义注解,通过@Target、@Retention、@Documented和@Inherited元注解来设定注解的类型、生命周期、是否生成到Javadoc和是否被继承。
- 注解可以有属性,但属性只能是8种基础类型、String、Class、enum、Annotation和以上的数组形式。
以上所述就是小编给大家介绍的《Java注解入门》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- SpringMVC入门学习---使用注解开发
- Spring自定义注解从入门到精通
- Spring入门学习手册 2:怎么用注解来DI/IOC
- MyBatis从入门到精通(五):MyBatis 注解方式的基本用法
- MyBatis从入门到精通(五):MyBatis 注解方式的基本用法
- Spring Boot入门(六):使用MyBatis访问MySql数据库(注解方式)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。