注解

来源:互联网 发布:光学透镜设计软件 编辑:程序博客网 时间:2024/05/23 17:30


在学习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()//获取指定类型的注解,没有返回nullpublic <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中注解的知识点。




原创粉丝点击