注解

作者: 我不傻_cyy | 来源:发表于2019-10-11 22:13 被阅读0次

    文章来源http://how2j.cn/k/annotation/annotation-system/1060.html#nowhere

    1.@Override表示这个方法重写了父类的方法

    如果父类中没有该方法,就没有办法通过编译。

    package annotation;
     
    public class Hero {
     
        String name;
        @Override
        public String toString(){
            return name;
        }
        @Override
        public String fromString(){
            return name;
        }
    }
    

    2.@Deprecated表示这个方法已经国旗,不建议开发人员使用。

    package annotation;
     
    public class Hero {
     
        String name;
         
        @Deprecated
        public void hackMap(){
             
        }
        public static void main(String[] args) {
            new Hero().hackMap();
        }
     
    }
    

    3.@SuppressWarnings表示忽略警告信息

    @SupressWarnings常见的值有:
    @SuppressWarnings 有常见的值,分别对应如下意思
    1.deprecation:使用了不赞成使用的类或方法时的警告(使用@Deprecated使得编译器产生的警告);
    2.unchecked:执行了未检查的转换时的警告,例如当使用集合时没有用泛型 (Generics) 来指定集合保存的类型; 关闭编译器警告
    3.fallthrough:当 Switch 程序块直接通往下一种情况而没有 Break 时的警告;
    4.path:在类路径、源文件路径等中有不存在的路径时的警告;
    5.serial:当在可序列化的类上缺少 serialVersionUID 定义时的警告;
    6.finally:任何 finally 子句不能正常完成时的警告;
    7.rawtypes 泛型类型未指明
    8.unused 引用定义了,但是没有被使用
    9.all:关于以上所有情况的警告。

    package annotation;
     
    import java.util.ArrayList;
    import java.util.List;
     
    public class Hero {
        String name;
        @SuppressWarnings({ "rawtypes", "unused" })
        public static void main(String[] args) {
            List heros = new ArrayList();
        }
     
    }
    

    @SafeVarargs当使用可变数量的参数的时候,而参数的类型又是泛型T的话,就会出现警告。 这个时候,就使用@SafeVarargs来去掉这个警告

    @SafeVarargs注解只能用在参数长度可变的方法或构造方法上,且方法必须声明为static或final,否则会出现编译错误。一个方法使用@SafeVarargs注解的前提是,开发人员必须确保这个方法的实现中对泛型类型参数的处理不会引发类型安全问题。

    package annotation;
     
    public class Hero {
        String name;
     
        @SafeVarargs
        public static <T> T getFirstOne(T... elements) {
            return elements.length > 0 ? elements[0] : null;
        }
    }
    

    @FunctionInterface

    这是Java1.8 新增的注解,用于约定函数式接口。
    函数式接口概念: 如果接口中只有一个抽象方法(可以包含多个默认方法或多个static方法),该接口称为函数式接口。函数式接口其存在的意义,主要是配合Lambda 表达式来使用。

    package annotation;
     
    @FunctionalInterface
    public interface AD {
        public void adAttack();
    }
    

    自定义注解

    1.创建注解类型
    public @interface JDBCConfig
    2.元注解
    @Target({METHOD,TYPE})表示这个注解可以用在类/接口上,还是可以用在方法上。
    @Retention(RetentionPolicy.RUNTIME)表示这是一个运行时注解,即运行起来之后才获取注解的相关信息,而不像基本注解如@Override 那种不用运行,在编译时eclipse就可以进行相关工作的编译时注解。
    @Inherited表示这个注解可以被子类继承
    @Documented表示当执行javadoc时,本注解会生成相关文档。
    3.注解元素,这些注解元素用于存放注解信息,在解析的时候获取出来
    String ip();
    int port() default 3306;
    String database();
    String encoding();
    String loginName();
    String password();

    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();
    }
    

    非注解的方式

    package util;
       
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.SQLException;
       
    public class DBUtil {
        static String ip = "127.0.0.1";
        static int port = 3306;
        static String database = "test";
        static String encoding = "UTF-8";
        static String loginName = "root";
        static String password = "admin";
        static{
            try {
                Class.forName("com.mysql.jdbc.Driver");
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
       
        public static Connection getConnection() throws SQLException {
            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 SQLException {
            System.out.println(getConnection());
        }
    }
    

    自定义注解@JDBCConfig
    将非注解的方式改造为注解的方式

    package util;
     
    import anno.JDBCConfig;
     
    @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();
            }
        }
    }
    

    4.解析注解
    接下来通过反射,获取这个DBUtil这个类上的注解对象
    JDBCConfig config = DBUtil.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();
    后续就一样了,根据这些配置信息得到一个数据库连接Connection实例。

    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")
    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);
     
            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);
        }
    }
    

    元注解概念详细解析

    元注解有这么几种:
    @Target
    @Retention
    @Inherited
    @Documented
    @Repeatable (java1.8 新增)
    1.@Target表示这个注解能够放在什么位置,是只能放在类上,还是即可以放在方法上,又可以放在属性上。
    可以选择的位置有:
    ElementType.TYPE:能够修饰类、接口或者枚举类型。
    ElementType.FIELD:能够修饰成员变量
    ELementType.METHOD:能够修饰方法
    ELementType.PARAMETER:能够修饰参数
    ELementType.CONSTRUCTOR:能够修饰构造器
    ElementTYpe.LOCAL_VARIABLE:能够修饰局部变量
    ElementType.ANNOTATION_TYPE:能够修饰注解
    ElementType.PACKAGE:能够修饰包
    2.@Retention表示生命周期
    可选的值有:
    RetentionPolicy.SOURCE:注解只在源代码中存在,编译成class之后就没有了,@Override就是这种注解。
    RetentionPolicy.CLASS:注解在java文件编译成class文件之后仍然存在,但是在运行起来之后就没有了,是@Retention的默认值,也就是没有显示指定时,就会使这个值。
    @RetentionPolicy.RUNTIME:注解在运行后依然存在,可以通过反射获取这些信息。
    3.@Inherited
    表示这个注解可以被子类继承
    4.@Document表示这个注解在使用javaDoc命令生成API文档后,会在文档里出现该注解的说明。
    5.@Repeatable(java1.8新增)
    表示这个注解在同一个位置只能出现一次。

    演示hibernate注解方式如何工作

    参考hibernate的 注解配置方式,自定义5个注解,分别对应hibernate中用到的注解:
    hibernate_annotation.MyEntity 对应 javax.persistence.Entity
    hibernate_annotation.MyTable 对应 javax.persistence.Table
    hibernate_annotation.MyId 对应 javax.persistence.Id
    hibernate_annotation.MyGeneratedValue 对应 javax.persistence.GeneratedValue
    hibernate_annotation.MyColumn 对应 javax.persistence.Column

    package hibernate_annotation;
     
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
     
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface MyEntity {
     
    }
    
    package hibernate_annotation;
     
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
     
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface MyTable {
     
        String name();
    }
    
    package hibernate_annotation;
     
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
     
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface MyId {
     
    }
    
    package hibernate_annotation;
     
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
     
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface MyGeneratedValue {
        String strategy();
    }
    
    package hibernate_annotation;
     
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
     
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface MyColumn {
        String value();
    }
    

    在Hero类上运用这些自定义注解:
    当注解的方法是value的时候,给这个注解赋值时,本来应该是:

    @MyColumn(value="name_")

    现在可以简略一点,写为

    @MyColumn("name_")

    只有当名称是value的时候可以这样,其他名称如name,stratgy等不行

    package pojo;
     
    import hibernate_annotation.MyColumn;
    import hibernate_annotation.MyEntity;
    import hibernate_annotation.MyGeneratedValue;
    import hibernate_annotation.MyId;
    import hibernate_annotation.MyTable;
     
    @MyEntity
    @MyTable(name="hero_")
    public class Hero {
        private int id;
        private String name;
        private int damage;
        private int armor;
         
        @MyId
        @MyGeneratedValue(strategy = "identity")
        @MyColumn("id_")
        public int getId() {
            return id;
        }
        public void setId(int id) {
            this.id = id;
        }
        @MyColumn("name_")
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        @MyColumn("damage_")
        public int getDamage() {
            return damage;
        }
        public void setDamage(int damage) {
            this.damage = damage;
        }
        @MyColumn("armor_")
        public int getArmor() {
            return armor;
        }
        public void setArmor(int armor) {
            this.armor = armor;
        }
         
    }
    

    创建一个解析类ParseHibernateAnnotation ,获取Hero类上配置的注解信息,其运行结果如图所示。
    思路如下:

    1. 首先获取Hero.class类对象
    2. 判断本类是否进行了MyEntity 注解
    3. 获取注解 MyTable
    4. 遍历所有的方法,如果某个方法有MyId注解,那么就记录为主键方法primaryKeyMethod
    5. 把主键方法的自增长策略注解MyGeneratedValue和对应的字段注解MyColumn 取出来,并打印
    6. 遍历所有非主键方法,并且有MyColumn注解的方法,打印属性名称和字段名称的对应关系。
    package test;
     
    import java.lang.reflect.Method;
     
    import hibernate_annotation.MyColumn;
    import hibernate_annotation.MyEntity;
    import hibernate_annotation.MyGeneratedValue;
    import hibernate_annotation.MyId;
    import hibernate_annotation.MyTable;
    import pojo.Hero;
     
    public class ParseHibernateAnnotation {
     
        public static void main(String[] args) {
     
            Class<Hero> clazz = Hero.class;
            MyEntity myEntity = (MyEntity) clazz.getAnnotation(MyEntity.class);
            if (null == myEntity) {
                System.out.println("Hero类不是实体类");
            } else {
                System.out.println("Hero类是实体类");
                MyTable myTable= (MyTable) clazz.getAnnotation(MyTable.class);
                String tableName = myTable.name();
                System.out.println("其对应的表名是:" + tableName);
                Method[] methods =clazz.getMethods();
                Method primaryKeyMethod = null;
                for (Method m: methods) {
                    MyId myId = m.getAnnotation(MyId.class);
                    if(null!=myId){
                        primaryKeyMethod = m;
                        break;
                    }
                }
                 
                if(null!=primaryKeyMethod){
                    System.out.println("找到主键:" + method2attribute( primaryKeyMethod.getName() ));
                    MyGeneratedValue myGeneratedValue =
                    primaryKeyMethod.getAnnotation(MyGeneratedValue.class);
                    System.out.println("其自增长策略是:" +myGeneratedValue.strategy());
                    MyColumn myColumn = primaryKeyMethod.getAnnotation(MyColumn.class);
                    System.out.println("对应数据库中的字段是:" +myColumn.value());
                }
                System.out.println("其他非主键属性分别对应的数据库字段如下:");
                for (Method m: methods) {
                    if(m==primaryKeyMethod){
                        continue;
                    }
                    MyColumn myColumn = m.getAnnotation(MyColumn.class);
                    //那些setter方法上是没有MyColumn注解的
                    if(null==myColumn)
                        continue;
                    System.out.format("属性: %s\t对应的数据库字段是:%s%n",method2attribute(m.getName()),myColumn.value());
     
                }
                 
            }
             
        }
     
        private static String method2attribute(String methodName) {
            String result = methodName; ;
            result = result.replaceFirst("get", "");
            result = result.replaceFirst("is", "");
            if(result.length()<=1){
                return result.toLowerCase();
            }
            else{
                return result.substring(0,1).toLowerCase() + result.substring(1,result.length());
            }
             
        }
    }
    

    注解分类

    1.按照作用域分:
    RetentionPolicy.SOURCE:Java源文件注解
    RetentionPolicy.CLASS:class类文件上的注解
    RetnetionPolicy.RUNTIME:运行时的注解
    2.按照来源分:
    (1)内置注解
    例如@Override、@Deperecated等
    (2)第三方注解
    例如Hibernate、Spring中的注解
    (3)自定义注解
    例如上面的自定义注解。
    世纪

    相关文章

      网友评论

          本文标题:注解

          本文链接:https://www.haomeiwen.com/subject/jvtfmctx.html