一、Java注解概述
为什么学习注解?学习注解有什么好处?学完能做什么?
能够读懂别人写的代码,特别是框架相关的代码
让编码更加简洁,代码更加清晰
让别人高看一眼
注解的概念: Java提供了一种原程序中的元素关联任何信息和任何元数据的途径和方法。
二、Java中的常见注解
1、JDK中的注解
@Override:一般在实现了接口的方法上标识,作用是告诉编译器该方法是接口的方法。
@Deprecated:一般在接口中的方法上进行标识,作用是该方法过时了。
@Suppvisewarnings:忽视警告,@SuppressWarnings("deprecation")
创建一个Java工程来详细说明:
创建工程为AnnTest.java:
创建Person.java类:
public interface Person
{
public String name();
public int age();
@Deprecated
public void sing();
}
创建Child.java类,并实现Person.java类:
public class Child implements Person {
@Override
public String name() {
return null;
}
@Override
public int age() {
return 0;
}
@Override
public void sing() {
}
}
创建测试类Test.java
public class Test {
public void sing(){
Person p = new Child();
p.sing();
}
}
注意:此时调用的sing()会有一条横切线标识,标识当前方法即将过期或失效。
此时为了解决这个问题,可以在方法明上添加一个@SuppressWarnings('deprecation')注解,用于标识忽略这个警告。
注意:sing()是过期的方法,一般都是旧版本jdk中使用的,在新的jdk版本中虽然还能用,但是,类似这样的方法大部分存在是为了保证其它旧的项目能够正常运行,而新开发的项目已经不再使用或使用可替代的方法
2、Java第三方注解
第三方的注解(Spring、Mybatis框架中的注解),这些也是比较常见的,功能相对也比较简单,但是对于编程而言,大大的减少代码量,简化了,程序在形式上的编写。
Spring:@Autowired @Service @Repository
@Autowired:可以对成员变量、方法和构造函数进行标注,来完成自动装配的工作。通过 @Autowired的使用来消除 set ,get方法。
用法:
public class UserManagerImpl implements UserManager {
@Autowired
private UserDao userDao;
}
@Service:用于标注业务层组件。定义某个类为一个bean,则在这个类的类名前一行使用@Service("XXX"),就相当于讲这个类定义为一个bean,bean名称为XXX。而无需去xml文件内去配置。
@Repository:用于标注数据访问组件,即DAO组件。
三、注解的分类
注解的分类:
1、按照运行机制分为
源码注解:注解只在源码中存在,编译成.class文件就不存在了
编译时注解:注解在源码和.class文件中都存在(如:JDK内置系统注解:@Override、@Deprecated、@Suppvisewarnings)
运行时注解:在运行阶段还起作用,甚至会影响运行逻辑的注解(如:Spring中@Autowried,程序运行时,把成员变量自动注入)
2、按照来源分为:
JDK内置系统注解、自定义注解、第三方注解
3.元注解:
给注解进行注解,注解的注解
四、自定义注解
1、Java自定义注解
【1】、自定义注解的语法要求
a、使用@interface关键字定义注解
b、成员以无参无异常方式声明
c、可以用default为成员指定一个默认值
d、如果注解只有一个成员,则成员名必须取名value(),在使用时可以忽略成员名和赋值
号(=);
e、成员类型是受限的,合法的类型包括原始类型String,Class,Annotation,Enumeration
f、注解类可以没有成员,没有成员的注解称为标识注解
【2】元注解
@Documented 生成javadoc时包含注解
@Inherited 允许子类继承
@Retention(RetentionPolicy.RUNTIME):声明周期
[SOURCE只在源码显示,编译时会丢弃;
CLASS编译时会记录到class中,运行时忽略;
RUNTIME运行时存在,可以通过反射读取]
@Target({ElementType.METHOD})
[CONSTRUCTOR构造方法声明;
FIELD字段声明;
LOCAL_VARIABLE局部变量声明;
METHOD方法声明;
PACKAGE包声明;
PARAMETER参数声明;
RYPE类接口]
2、使用自定义注解
自定义注解的使用
@(=,=,...)
示例:
@Description(desc="I am eyeColor",author="Mooc boy,age=18)
public String eyeColor(){
return "red";
}
@Description注解在eyeColor()方法上使用。
3、关于自定义注解的代码演示说明
自定义注解时,如果注解只有一个成员,则成员名必须为value(),在使用是可以忽略成员名称赋值号(=)
【1】. 虽然
public @interface Description{
String desc();
}
@Description(desc="the name method")
不会报错。
但不符合规范,既然只有一个成员,就要使用value作为成员名,改成:
public @interface Description{
String value();
}
然后在使用注解的时候,直接赋值,不写成员名和等号:
@Description("the name method")
以上方式,约定俗成,比较直观。
【2】. 没有成员的注解——标志注解(比如常见的@Override),在使用的时候不加括号。
【3】. 当一个方法被规定为({ElementType.METHOD})就表示只能用于方法的注解,如果用在类上面,就会报错(添加 ElementType.TYPE 则可适用于类)。这里没有包含关系,例如只写ElementType.TYPE 则不能对方法进行注解,只能对类或接口进行注解。
【4】. @Documented(属于标识注解,生成javadoc时会包含注解)
创建一个Javadoc :右击项目--> Export --> Java --> Javadoc --> next -->Browser 选择要存放的文件夹。点击finish就生成成功了。
打开这个文件夹,点击index.html,就能查看该项目的一些摘要。
4、解析注解
概念:通过反射获取类、函数或成员的运行时注解信息,从而实现动态控制程序运行的逻辑。
@Inherited 只能实现类的继承,而接口是无法继承的。即接口的注解无法影响到实现接口的类上面。另外,父类的方法的注解也无法被子类继承。
核心代码:
//1. 使用类加载器加载类
Class c = Class.forName("anno.test.Child");
//2. 找到类上面的注解
boolean isExist=c.isAnnotationPresent(Description.class);//isAnnotationParse()判断类上是否存在Description这样的注解
if(isExist){
//3.获得注解实例
Description d = (Description)c.getAnnotation(Description.class);
System.out.println(d.value());
}
//4.找到方法上的注解
//获取方法上的注解,首先,遍历所有方法,通过方法对象的isAnnotation查看是否有自定义注解,如果存在则输出方法的自定义注解的信息。
Method[] mts = c.getMethods();
for (Method mt : mts) {
if(mt.isAnnotationPresent(Description.class)){
Description d2 = (Description)mt.getAnnotation(Description.class);
System.out.println(d2.value());
}}
第二种解析方法:获取这个方法的所有注解,Annotation [] as=m.getAnnotations();然后遍历该注解,如果遍历的注解是Description类型,则把遍历的注解强转为Description类型,并进行输出value()信息。
//另外一种获取类上的注解的途径
Annotation[] annos = c.getAnnotations();
for (Annotation anno : annos) {
if(anno instanceof Description){
System.out.println(((Description) anno).value());
}}
//另一种获取方法上的注解的途径
for (Method mt : mts){
Annotation[] annos2 = mt.getAnnotations();
for (Annotation anno : annos2) {
if(anno instanceof Description){ System.out.println(同上);
}}}