注解 - 注解基础


在学习Effictive Java注解几节的内容之前,我们先看一下Java注解的基础知识。


1. Java的内置注解。

2. 定义注解和元注解。

3. 怎么使用注解。

4. 自定义注解实现依赖注入。


1. Java的内置注解。

a.@Override

这个我们非常熟悉,子类覆盖父类的方法是需要在子类方法上添加这个注解。如果你的方法拼写错误,编译器就会报错。


b.@Deprecated

这个注解我们很少会用到,当部分人肯定会碰到过。表示注解的元素过期了,不再使用了,如果使用的话,编译器会给警告。


c.@SuppressWarnings

这个我们也很熟悉,当我们需要编译器忽略掉这个警告的时候使用它。


总的来说,这三个注解其实并不会影响程序的运行,我们用到的功能比较强大的注解都是一些框架的自定义注解。


2. 定义注解和元注解。

我们看一下下面代码,这是注解@Override的定义。定义注解和接口的定义有点类似,只不过多了一个@符号。@Target, @Retention叫做元注解,就是用来定义注解的注解。我们来看一下各种元注解的作用。

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
a.Target

用来表示你的注解用在什么地方,上面的ElementType.METHOD,表示这个注解用在方法上。除了METHOD,还有很多,看下面代码,

public enum ElementType {
    /** Class, interface (including annotation type), or enum declaration */
    TYPE, 可以修饰类接口,包括注解类型,和枚举类型

    /** Field declaration (includes enum constants) */
    FIELD, 修饰域,也就是变量

    /** Method declaration */
    METHOD, 修饰方法

    /** Formal parameter declaration */
    PARAMETER, 修饰参数,比如我们Mybatis框架常用的@param

    /** Constructor declaration */
    CONSTRUCTOR, 修饰构造器

    /** Local variable declaration */
    LOCAL_VARIABLE, 修饰局部变量

    /** Annotation type declaration */
    ANNOTATION_TYPE, 修饰注解类型

    /** Package declaration */
    PACKAGE, 修饰包

    /**
     * Type parameter declaration
     *
     * @since 1.8
     */
    TYPE_PARAMETER, Java8添加的,有兴趣的可以了解一下

    /**
     * Use of a type
     *
     * @since 1.8
     */
    TYPE_USE Java8添加的,有兴趣的可以了解一下

}

b.Retention

@Retention表示注解信息保留到什么时候,取值只能有一个,类型为RetentionPolicy,它是一个枚举,有三个取值:

  • SOURCE:只在源代码中保留,编译器将代码编译为字节码文件后就会丢掉
  • CLASS:保留到字节码文件中,但Java虚拟机将class文件加载到内存时不一定会在内存中保留
  • RUNTIME:一直保留到运行时

如果没有声明@Retention,默认为CLASS。

@Override和@SuppressWarnings都是给编译器用的,所以@Retention都是RetentionPolicy.SOURCE,自定注解一般都为RUNTIME,程序运行的时候可以得到。

c.Documented - 将此注解包含在JavaDoc中

d.Inherited 允许子类继承父类中的注解

前面两个在自定义注解的时候用的比较多。


3. 怎么使用注解。

要使用注解,首先要取得注解的信息才行,看下面代码,Class中有下面这些供注解使用的方法。通过反射来获取注解信息。

//获取所有的注解
public Annotation[] getAnnotations()
//获取所有本元素上直接声明的注解,忽略inherited来的
public Annotation[] getDeclaredAnnotations()
//获取指定类型的注解,没有返回null
public <A extends Annotation> A getAnnotation(Class<A> annotationClass)
//判断是否有指定类型的注解
public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)

我们来看一个简单的例子,看下面代码,定义了一个DefaultValue注解,通过反射得到注解信息后,就可以做自己想做的很多事了。

public class Test{

    @Target(ElementType.PARAMETER) 修饰参数
    @Retention(RetentionPolicy.RUNTIME) 运行时候也可以得到注解信息
    static @interface DefaultValue {
        String value() default "";
    }
    
    public void hello(@DefaultValue("owen") String sort){
        ...
    }
    
    public static void main(String[] args) throws Exception {
        Class<?> cls = Test.class; 得到Class对象
        Method method = cls.getMethod("hello", String.class); 得到方法hello
        
        Annotation[][] annts = method.getParameterAnnotations(); 得到方法参数的注解
        for(int i=0; i < annts.length; i++){
            Annotation[] anntArr = annts[i];
            for(Annotation annt : anntArr){
                if(annt instanceof DefaultValue){
                    DefaultValue dv = (DefaultValue)annt; 得到DefaultValue注解
                    System.out.println(dv.annotationType().getSimpleName()+":"+ dv.value()); 打印注解的名字和设的值
                }
            }
        }
    }
}

4. 自定义注解实现依赖注入。

Spring框架中的依赖注入可以通过配置文件的方式注入,同样可以通过注解的方式注入,我们用注解来实现一个简单的依赖注入。

@Retention(RUNTIME) 运行时可以得到
@Target(FIELD) 修饰域的
public @interface autowired{
}

public class ServiceA {

    @autowired 注入b
    ServiceB b;
}

public class ServiceB {

}
ServiceA a = SimpleContainer.getInstance(ServiceA.class); 这个方法是关键

public static <T> T getInstance(Class<T> cls) {
    try {
        T obj = cls.newInstance(); 实例化对象
        Field[] fields = cls.getDeclaredFields(); 取得对象的域
        for (Field f : fields) {
            if (f.isAnnotationPresent(autowired.class)) { 判断是否被注解修饰
                if (!f.isAccessible()) {  让我们有操作这个字段的权限
                    f.setAccessible(true);
                }
                Class<?> fieldCls = f.getType(); 取得域的类型
                f.set(obj, getInstance(fieldCls)); 实例化类型并注入b,这个是真正起作用的语句
            }
        }
        return obj;
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

有了注解的基础,后面我们再看一下Effective Java中注解的知识点。




  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值