• Java 内置注解简单理解


    感谢原文作者:yejg1212
    原文链接
    https://www.cnblogs.com/yejg1212/p/3187362.html
    https://www.cnblogs.com/yejg1212/p/3188751.html
    https://www.cnblogs.com/yejg1212/p/3188791.html

    超通俗易懂的注解入门文章:https://blog.csdn.net/shengzhu1/article/details/81271409
    Bilibili:https://www.bilibili.com/video/av55440782

    Ⅰ. 简单介绍Jave的内置注解(7个:4个元注解)

    Java从JDK 5开始引入注解(annotation)。

    注解使得Java源代码中不但可以包含功能性的实现代码,还可以添加元数据。

    注解的功能类似于代码中的注释,所不同的是注解不是提供代码功能的说明,而是实现程序功能的重要组成部分。

    Java注解已经在很多框架中得到了广泛的使用,用来简化程序中的配置。

    下面先来看看java中常用的注解。

    一、常用注解

    ① @Override注解

    package java.lang;
    
    import java.lang.annotation.*;
    
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.SOURCE)
    public @interface Override {
    }
    

    @Override注解表示子类要重写父类的对应方法。

    如果方法利用此注释类型进行注解但没有重写超类方法,则编译器会生成一条错误消息。

    顺便说一句:@override注解在JDK 5环境下只能用于对继承的类的方法的重写,实现接口中的方法不能用@override注解。但是JDK1.6可以。

    ② @Deprecated注解

    package java.lang;
    
    import java.lang.annotation.*;
    
    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Deprecated {
    }
    

    @Deprecated注解表示方法是不被建议使用的。

    ③ @SuppressWarnings注解

    package java.lang;
    
    import java.lang.annotation.*;
    import java.lang.annotation.ElementType;
    import static java.lang.annotation.ElementType.*;
    
    @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
    @Retention(RetentionPolicy.SOURCE)
    public @interface SuppressWarnings {
        String[] value();
    }
    

    @SuppressWarnings注解表示抑制警告。

    例如下面的代码,声明了2个未使用的变量,加上2个@SuppressWarnings来抑制警告。

    @SuppressWarnings("unused")
    int a=10;
            
    @SuppressWarnings({ "rawtypes", "unused" })
    List list =new ArrayList();
    

    上面给出了Java自带的几个常用的注解,下面先来了解下代码中出现的诸如@Target,@Retention,@Documented(这些也叫元注解)的意义。

    二、元注解

    ① @Target

    @Target 表示该注解用于什么地方,可取的值包括:

    • ElemenetType.CONSTRUCTOR     构造器声明

    • ElemenetType.FIELD          域声明(包括 enum 实例)

    • ElemenetType.LOCAL_VARIABLE    局部变量声明

    • ElemenetType.METHOD         方法声明

    • ElemenetType.PACKAGE        包声明

    • ElemenetType.PARAMETER       参数声明

    • ElemenetType.TYPE          类,接口(包括注解类型)或enum声明

    • ElementType.ANNOTATION_TYPE   注解

    ② @Retention

    @Retention 表示在什么级别保存该注解信息。可选的 RetentionPolicy 参数包括:

    • RetentionPolicy.SOURCE       注解将被编译器丢弃
    • RetentionPolicy.CLASS        注解在class文件中可用,但会被VM丢弃
    • RetentionPolicy.RUNTIME       JVM将在运行期也保留注释,因此可以通过反射机制读取注解的信息。

    ③ @Documented

    @Documented 将此注解包含在 javadoc 中

    ④ @Inherited

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


    Ⅱ. 自定义注解及注射提取的简单介绍

    自定义注解其实很简单,直接上代码:

    import java.lang.annotation.Documented;
    import java.lang.annotation.Inherited;
    import java.lang.annotation.Retention;
    import java.lang.annotation.Target;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.RetentionPolicy;
    
    
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    /*
     1. 定义注解 Test
     2. 注解中含有两个元素 id 和 description
     3. description 元素 有默认值 "hello anntation"
     */
    public @interface Test {
        public int id();
        public String description() default "hello annotation";
    }
    

    根据上一篇对元注解的解释,我们知道:

    1. 这个注解可以用于方法
    2. JVM运行期间该注解都有效
    3. 该注解包含在 javadoc 中
    4. 该注解允许子类继承

    下面看下通过注解我们能取到什么

    public class TestMain {  
        /* 
         * 被注解的三个方法 
         */  
        @Test(id = 1, description = "hello methodA")  
        public void methodA() {  
        }  
      
        @Test(id = 2)  
        public void methodB() {  
        }  
      
        @Test(id = 3, description = "last method")  
        public void methodC() {  
        }  
      
        /* 
         * 解析注解,将类被注解方法 的信息打印出来 
         */  
        public static void main(String[] args) {  
            Method[] methods = TestMain.class.getDeclaredMethods();  
            for (Method method : methods) {  
                /* 
                 * 判断方法中是否有指定注解类型的注解 
                 */  
                boolean hasAnnotation = method.isAnnotationPresent(Test.class);  
                if (hasAnnotation) {  
                    /* 
                     * 根据注解类型返回方法的指定类型注解 
                     */  
                    Test annotation = method.getAnnotation(Test.class);  
                    System.out.println("Test( method = " + method.getName() + " , id = " + annotation.id() 
                            + " , description = " + annotation.description() + " )");
                }  
            }  
        }  
    }
    

    上面的Demo打印的结果如下:

    Test( method = methodA , id = 1 , description = hello methodA )
    Test( method = methodB , id = 2 , description = hello annotation )
    Test( method = methodC , id = 3 , description = last method )
    

    例其实也说明了,我们一般通过反射来取RUNTIME保留策略的注解信息


    Ⅲ. 简单实例

    目标:将实体bean保存到数据库

    先来定义一个实体注解

    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 Entity {
        String getTableName();
    }
    

    这个注解可用在类上,它有一个变量参数getTableName。

    其实意义很明显,就是一个实体类对应一张数据库的表,通过Entity注解将类和数据库表名关联起来

    那么,通过什么将类的参数和数据库表中的列关联起来呢?再来定义一个注解

    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Target(ElementType.FIELD) 
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Column {
        String getName();
    }
    

    有了Column注解,类里面的属性就和表中的列关联起来了。

    POJO(Plain Ordinary Java Object)简单的Java对象,实际就是普通JavaBeans,是为了避免和EJB混淆所创造的简称。
    EJB是的Enterprise Java Beans技术的简称, 又被称为企业Java Beans。这种技术最早是由美国计算公司研发出来的。

    下面来看看POJO中怎么用这两个注解:

    @Entity(getTableName = "user")
    public class User {
        @Column(getName = "user_id")
        private String id;
        @Column(getName = "user_name")
        private String name;
        @Column(getName = "user_age")
        private int age;
    
        public String getId() {
            return id;
        }
    
        public void setId(String id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    }
    

    通过Entity和Column注解,就将一个实体bean和一张数据库表连接起来了。很多ORM映射就是采取这种方式实现的。

    最后,来感受一下注解给我们带来的便利,来个方法见证下~~

    import java.lang.reflect.Field;
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    
    public class Session {
        public static void main(String[] args) {
            Session session = new Session();
            System.out.println(session.getInsertSql(new User()));
        }
    
        //在实际项目中,你可以save(obj)方法来保存一个bean
        public void save(Object obj) {
            // get a connection
            //PreparedStatement pstmt = getStatement(con, obj);
            //pstmt.execute();
        }
    
        //得到PreparedStatement
        public PreparedStatement getStatement(Connection con, Object obj)
                throws Exception {
            PreparedStatement pstmt = con.prepareStatement(getInsertSql(obj));
            Class<?> c = obj.getClass();
            Field[] fs = c.getDeclaredFields();
            for (int i = 0; i < fs.length; i++) {
                fs[i].setAccessible(true);
                pstmt.setObject(i + 1, fs[i].get(obj));
            }
            return pstmt;
        }
    
        //insert into tableName(ziduan1,ziduan2...) values(?,?...)
        public String getInsertSql(Object obj) {
            StringBuilder s = new StringBuilder();
            s.append("insert into ");
    
            Class<?> c = obj.getClass();
            String tableName = c.getSimpleName();//类名,不包含包名 User
            Entity entity = (Entity) c.getAnnotation(Entity.class);
            if (entity != null) {
                tableName = entity.getTableName();
            }
            s.append(tableName).append("(");
            Field[] fs = c.getDeclaredFields();
    
            for (int i = 0; i < fs.length; i++) {
                String fieldName = fs[i].getName();
                Column column = fs[i].getAnnotation(Column.class);
                if (column != null) {
                    fieldName = column.getName();
                }
                s = i == 0 ? s.append(fieldName) : s.append(",").append(fieldName);
            }
            s.append(") values").append(getString(fs.length));
            return s.toString();
    
        }
    
        //得到(?,?,?,...?,?)
        private String getString(int length) {
            StringBuilder s = new StringBuilder();
            s.append("(");
            for (int i = 0; i < length; i++) {
                s = i == 0 ? s.append("?") : s.append(",?");
            }
            s.append(")");
            return s.toString();
        }
    }
    

    OK,That’s all!

  • 相关阅读:
    自己常用网站记录
    css弹性布局指定显示行数多余文字去掉用省略号代替以及弹性布局中css 卡片阴影效果
    微信小程序页面传参被截取问题
    阴影效果 css3 为什么要加 -moz-box-shadow -webkit-box-shadow -o-box-shadow,直接用box-shadow不是都能识别吗?
    css常用清除浮动方式
    什么是微信小程序云开发 它的作用是什么
    JMeter压测“java.net.SocketException: Socket closed”解决方法
    Jmeter压力测试工具安装及使用教程
    OnActionExecuting和OnActionExecuted执行顺序
    C#循环下载多个文件(把多个文件压缩成一个文件可以一次性下载)
  • 原文地址:https://www.cnblogs.com/tfxz/p/12621503.html
Copyright © 2020-2023  润新知