how2j.cn


工具版本兼容问题
经过上个知识点自定义注解的学习之后,对自定义注解有了感性的认识,现在我们再来稍微深入了解各种元注解以及他们的含义。

步骤 1 : 元注解概念   
步骤 2 : @Target   
步骤 3 : @Retention   
步骤 4 : @Inherited   
步骤 5 : @Documented   
步骤 6 : @Repeatable (java1.8 新增)   
步骤 7 : @Repeatable 运用举例   

步骤 1 :

元注解概念

在讲解元注解概念之前,我们先建立元数据的概念。 元数据在英语中对应单词 metadata, metadata在wiki中的解释是:
Metadata is data [information] that provides information about other data
为其他数据提供信息的数据

这样元注解就好理解了,元注解 meta annotation用于注解 自定义注解 的注解。
元注解有这么几种:
@Target
@Retention
@Inherited
@Documented
@Repeatable (java1.8 新增)
接下来挨个讲解
步骤 2 :

@Target

@Target 表示这个注解能放在什么位置上,是只能放在类上?还是即可以放在方法上,又可以放在属性上。自定义注解@JDBCConfig 这个注解上的@Target是:@Target({METHOD,TYPE}),表示他可以用在方法和类型上(类和接口),但是不能放在属性等其他位置。 可以选择的位置列表如下:
ElementType.TYPE:能修饰类、接口或枚举类型
ElementType.FIELD:能修饰成员变量
ElementType.METHOD:能修饰方法
ElementType.PARAMETER:能修饰参数
ElementType.CONSTRUCTOR:能修饰构造器
ElementType.LOCAL_VARIABLE:能修饰局部变量
ElementType.ANNOTATION_TYPE:能修饰注解
ElementType.PACKAGE:能修饰包
package anno; import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.ElementType.TYPE; import java.lang.annotation.Documented; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target({METHOD,TYPE}) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented public @interface JDBCConfig { String ip(); int port() default 3306; String database(); String encoding(); String loginName(); String password(); }
步骤 3 :

@Retention

@Retention 表示生命周期,自定义注解@JDBCConfig 上的值是 RetentionPolicy.RUNTIME, 表示可以在运行的时候依然可以使用。 @Retention可选的值有3个:

RetentionPolicy.SOURCE: 注解只在源代码中存在,编译成class之后,就没了。@Override 就是这种注解。
RetentionPolicy.CLASS: 注解在java文件编程成.class文件后,依然存在,但是运行起来后就没了。@Retention的默认值,即当没有显式指定@Retention的时候,就会是这种类型。
RetentionPolicy.RUNTIME: 注解在运行起来之后依然存在,程序可以通过反射获取这些信息,自定义注解@JDBCConfig 就是这样。
大家可以试试把自定义注解@JDBCConfig的@Retention改成其他两种,并且运行起来,看看有什么不同
package anno; import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.ElementType.TYPE; import java.lang.annotation.Documented; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target({METHOD,TYPE}) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented public @interface JDBCConfig { String ip(); int port() default 3306; String database(); String encoding(); String loginName(); String password(); }
步骤 4 :

@Inherited

@Inherited 表示该注解具有继承性。如例,设计一个DBUtil的子类,其getConnection2方法,可以获取到父类DBUtil上的注解信息。
package util; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import anno.JDBCConfig; public class DBUtilChild extends DBUtil { public static Connection getConnection2() throws SQLException, NoSuchMethodException, SecurityException { JDBCConfig config = DBUtilChild.class.getAnnotation(JDBCConfig.class); String ip = config.ip(); int port = config.port(); String database = config.database(); String encoding = config.encoding(); String loginName = config.loginName(); String password = config.password(); String url = String.format("jdbc:mysql://%s:%d/%s?characterEncoding=%s", ip, port, database, encoding); return DriverManager.getConnection(url, loginName, password); } public static void main(String[] args) throws NoSuchMethodException, SecurityException, SQLException { Connection c = getConnection2(); System.out.println(c); } }
步骤 5 :

@Documented

@Documented 如图所示, 在用javadoc命令生成API文档后,DBUtil的文档里会出现该注解说明。

注: 使用eclipse把项目中的.java文件导成API文档步骤:
1. 选中项目
2. 点开菜单File
3. 点击Export
4. 点开java->javadoc->点next
5. 点finish
@Documented
步骤 6 :

@Repeatable (java1.8 新增)

当没有@Repeatable修饰的时候,注解在同一个位置,只能出现一次,如例所示:
@JDBCConfig(ip = "127.0.0.1", database = "test", encoding = "UTF-8", loginName = "root", password = "admin")
@JDBCConfig(ip = "127.0.0.1", database = "test", encoding = "UTF-8", loginName = "root", password = "admin")
重复做两次就会报错了。
使用@Repeatable之后,再配合一些其他动作,就可以在同一个地方使用多次了。
如何使用@Repeatable 单独拿出来讲解:@Repeatable运用举例
package util; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import anno.JDBCConfig; @JDBCConfig(ip = "127.0.0.1", database = "test", encoding = "UTF-8", loginName = "root", password = "admin") @JDBCConfig(ip = "127.0.0.1", database = "test", encoding = "UTF-8", loginName = "root", password = "admin") public class DBUtil { static { try { Class.forName("com.mysql.jdbc.Driver"); } catch (ClassNotFoundException e) { e.printStackTrace(); } } public static Connection getConnection() throws SQLException, NoSuchMethodException, SecurityException { JDBCConfig config = DBUtil.class.getAnnotation(JDBCConfig.class); System.out.println(config); String ip = config.ip(); int port = config.port(); String database = config.database(); String encoding = config.encoding(); String loginName = config.loginName(); String password = config.password(); String url = String.format("jdbc:mysql://%s:%d/%s?characterEncoding=%s", ip, port, database, encoding); return DriverManager.getConnection(url, loginName, password); } public static void main(String[] args) throws NoSuchMethodException, SecurityException, SQLException { Connection c = getConnection(); System.out.println(c); } }
步骤 7 :

@Repeatable 运用举例

比如在练习练习-查找文件内容 中有一个要求,即查找文件后缀名是.java的文件,我们把部分代码修改为注解,并且使用@Repeatable 这个元注解来表示,文件后缀名的范围可以是java, html, css, js 等等。

为了紧凑起见,把注解作为内部类的形式放在一个文件里。
1. 注解FileTypes,其value()返回一个FileType数组
2. 注解FileType,其@Repeatable的值采用FileTypes
3. 运用注解:在work方法上重复使用多次@FileType注解
4. 解析注解: 在work方法内,通过反射获取到本方法上的FileType类型的注解数组,然后遍历本数组
package annotation; import static java.lang.annotation.ElementType.METHOD; import java.lang.annotation.Repeatable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; public class FindFiles { @Target( METHOD) @Retention( RetentionPolicy.RUNTIME ) public @interface FileTypes { FileType[] value(); } @Target( METHOD ) @Retention( RetentionPolicy.RUNTIME ) @Repeatable( FileTypes.class ) public @interface FileType { String value(); }; @FileType( ".java" ) @FileType( ".html" ) @FileType( ".css" ) @FileType( ".js" ) public void work(){ try { FileType[] fileTypes= this.getClass().getMethod("work").getAnnotationsByType(FileType.class); System.out.println("将从如下后缀名的文件中查找文件内容"); for (FileType fileType : fileTypes) { System.out.println(fileType.value()); } System.out.println("查找过程略。。。"); } catch (NoSuchMethodException | SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public static void main(String[] args) { new FindFiles().work(); } }


HOW2J公众号,关注后实时获知布最新的教程和优惠活动,谢谢。


问答区域    
2017-06-16 元注解注解自己
zl7261



坛主你好,最近对JAVA元注解非常困惑, 有人说java注解的本质是接口因为@interface这个声明 但是我看了元注解的源码,感到十分不解。 附上代码, package java.lang.annotation; @Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Target { ElementType[] value(); } 为什么一个元注解可以用在自己本身? 注解的实现和接口的实现有什么区别吗?
/*
 * @(#)Target.java	1.6 05/11/17
 *
 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
 * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */

package java.lang.annotation;

/**
 * Indicates the kinds of program element to which an annotation type
 * is applicable.  If a Target meta-annotation is not present on an
 * annotation type declaration, the declared type may be used on any
 * program element.  If such a meta-annotation is present, the compiler
 * will enforce the specified usage restriction.
 *
 * For example, this meta-annotation indicates that the declared type is
 * itself a meta-annotation type.  It can only be used on annotation type
 * declarations:
 * <pre>
 *    &#064;Target(ElementType.ANNOTATION_TYPE)
 *    public &#064;interface MetaAnnotationType {
 *        ... 
 *    }
 * </pre>
 * This meta-annotation indicates that the declared type is intended solely
 * for use as a member type in complex annotation type declarations.  It
 * cannot be used to annotate anything directly:
 * <pre>
 *    &#064;Target({}) 
 *    public &#064;interface MemberType {
 *        ...
 *    }
 * </pre>
 * It is a compile-time error for a single ElementType constant to
 * appear more than once in a Target annotation.  For example, the
 * following meta-annotation is illegal:
 * <pre>
 *    &#064;Target({ElementType.FIELD, ElementType.METHOD, ElementType.FIELD})
 *    public &#064;interface Bogus {
 *        ...
 *    }
 * </pre>
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
    ElementType[] value();
}

							


1 个答案

mdls 答案时间:2017-12-27
同问




答案 或者 代码至少填写一项, 如果是自己有问题,请重新提问,否则站长有可能看不到





2017-01-26
预备程序员_
@Retention(RetentionPolicy.C) 的常量写得不对吧。哈哈。




1 个答案

how2j 答案时间:2017-01-27
谢谢提醒 :)




答案 或者 代码至少填写一项, 如果是自己有问题,请重新提问,否则站长有可能看不到








提问之前请登陆
关于 JAVA 高级-注解-元注解 的提问

尽量提供截图代码异常信息,有助于分析和解决问题。 也可进本站QQ群交流: 620943819
站长会在每个工作日早上尽量回答提问(如果有漏掉没有回答的,请进群提醒一下)
提问尽量提供完整的代码,环境描述,越是有利于问题的重现,您的问题越能更快得到解答。
对教程中代码有疑问,请提供是哪个步骤,哪一行有疑问,这样便于快速定位问题,提高问题得到解答的速度
站长是玻璃心,提问的时候请语气温柔些 kiss~
截止2017-5-19日累计提问 1638个,站长回答了 1546个
截止2017-8-15日累计提问 2788个,站长回答了 2544个

上传截图