3-5 注解

目录

一.注解分类

二.内置注解

三.定义注解(元注解)

四.自定义注解

五.仿Hibernate 的注解


一.注解分类

1.按照作用域分

根据注解的作用域@Retention,注解分为
RetentionPolicy.SOURCE: Java源文件上的注解
RetentionPolicy.CLASS: Class类文件上的注解
RetentionPolicy.RUNTIME: 运行时的注解

2.按照来源分

按照注解的来源,也是分为3类
1. 内置注解 如@Override @Deprecated 等等
2. 第三方注解,如Hibernate, Struts等等
3. 自定义注解,如仿hibernate的自定义注解

在工作中,大部分都是使用第三方注解, 当然第三方注解本身就是自定义注解。 本教程的主要作用是帮助大家理解这些第三方注解是如何工作的,让大家用得心里踏实一些。

二.内置注解

 @Override    
@Deprecated    
@SuppressWarnings    
@SafeVarargs    
@FunctionalInterface    

了解就好

三.定义注解(元注解)

在讲解元注解概念之前,我们先建立元数据的概念。 元数据在英语中对应单词 metadata, metadata在wiki中的解释是:
Metadata is data [information] that provides information about other data 为其他数据提供信息的数据
这样元注解就好理解了,元注解 meta annotation用于注解 自定义注解 的注解。
 

元注解有这么几种:
@Target 
@Retention 
@Inherited 
@Documented 
@Repeatable (java1.8 新增) 

常用习惯:
 Target:必须设置
 Retention:一般设置为RUNTIME
 通常不必写@Inherited, @Repeatable等等

当注解的方法是value的时候,给这个注解赋值时,本来应该是:@MyColumn(value="name_")
现在可以简略一点,写为@MyColumn("name_") 只有当名称是value的时候可以这样,其他名称如name,stratgy等不行


1.@Target 表示这个注解能放在什么位置上,是只能放在类上?还是即可以放在方法上,又可以放在属性上。
可以选择的位置列表如下:
ElementType.TYPE:能修饰类、接口或枚举类型
ElementType.FIELD:能修饰成员变量
ElementType.METHOD:能修饰方法
ElementType.PARAMETER:能修饰参数
ElementType.CONSTRUCTOR:能修饰构造器
ElementType.LOCAL_VARIABLE:能修饰局部变量
ElementType.ANNOTATION_TYPE:能修饰注解
ElementType.PACKAGE:能修饰包


2.@Retention 表示生命周期,自定义注解@JDBCConfig 上的值是 RetentionPolicy.RUNTIME, 表示可以在运行的时候依然可以使用。 
@Retention可选的值有3个:
RetentionPolicy.SOURCE: 注解只在源代码中存在,编译成class之后,就没了。@Override 就是这种注解。
RetentionPolicy.CLASS: 注解在java文件编程成.class文件后,依然存在,但是运行起来后就没了。@Retention的默认值,即当没有显式指定@Retention的时候,就会是这种类型。
RetentionPolicy.RUNTIME: 注解在运行起来之后依然存在,程序可以通过反射获取这些信息.


3.@Inherited 表示该注解具有继承性。子类可以获取被注解父类的注解

4.@Documented 在用javadoc命令生成API文档后,文档里会出现该注解说明。

5.当没有@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之后,再配合一些其他动作,就可以在同一个地方使用多次了。

四.自定义注解


使用反射API读取Annotation:

//判断是否存在注解
Class.isAnnotationPresent(Class)
Constructor.isAnnotationPresent(Class)
Field.isAnnotationPresent(Class)
Method.isAnnotationPresent(Class)
//获取注解
Class.getAnnotation(Class)
Constructor.getAnnotation(Class)
Field.getAnnotation(Class)
Method.getAnnotation(Class)

getParameterAnnotations()

1.不使用注解

//不是用注解
public class DbUtil {
    static String ip="127.0.0.1";
    static int port=3306;
    static String database="students";
    static String encoding="utf-8";
    static String loginName="root";
    static String password="12345678";

    static {
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    public static Connection getConnection(){
        Connection connection=null;
        try {
            String url=String.format("jdbc:mysql://%s:%d/%s?characterEncoding=%s",ip,port,database,encoding);
            connection= DriverManager.getConnection(url,loginName,password);
        }catch (Exception e){
            e.printStackTrace();
        }
        return connection;
    }

}

2.使用注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface JDBCConfig {
    String ip();
    int port() default 3306;
    String database();
    String encoding();
    String loginName();
    String password();
}
@JDBCConfig(ip="127.0.0.1",port = 3306,database = "students",encoding = "utf-8",loginName = "root",password = "12345678")
public class DbUtil {

    static {
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    public static Connection getConnection(){

        Class clazz=DbUtil.class;
        JDBCConfig config= (JDBCConfig) clazz.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 connection=null;
        try {
            String url=String.format("jdbc:mysql://%s:%d/%s?characterEncoding=%s",ip,port,database,encoding);
            connection= DriverManager.getConnection(url,loginName,password);
        }catch (Exception e){
            e.printStackTrace();
        }
        return connection;
    }

}

五.仿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

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyEntity {
}


@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyTable {
    String name();
}


@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyId {

}

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyGeneratedValue {
    String strategy();
}

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyColumn {
    String value();
}
@MyEntity
@MyTable(name ="student")
public class Student2 {
    private int id;
    private String name;
    private int age;

    @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("age_")
    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
public static void main(String[] args){

        Class clazz= Student2.class;

        MyEntity entity=(MyEntity) clazz.getAnnotation(MyEntity.class);
        if(entity==null){
            System.out.println("这个类不是实体类");
            return;
        }

        System.out.println(clazz.getSimpleName()+"是实体类");
        //否则是实体类
        MyTable table=(MyTable) clazz.getAnnotation(MyTable.class);
        System.out.println("其对应的表名为:"+table.name());

        Method[] methods=clazz.getMethods();
        for(Method method:methods){
            boolean isExistIdAnnotation=method.isAnnotationPresent(MyId.class);
            if(isExistIdAnnotation){
                System.out.println("找到主键为:"+ method2Field(method.getName()));
                MyGeneratedValue generatedValue=method.getAnnotation(MyGeneratedValue.class);
                System.out.println("其自增长策略为:"+generatedValue.strategy());
                MyColumn column=method.getAnnotation(MyColumn.class);
                System.out.println("对应的数据库列名为:"+column.value());
            }
        }


        for(Method method:methods){
            boolean isExistIdAnnotation=method.isAnnotationPresent(MyId.class);
            if(isExistIdAnnotation)continue;

            boolean isExistColumnAnnotation=method.isAnnotationPresent(MyColumn.class);
             if(isExistColumnAnnotation){
                MyColumn column=method.getAnnotation(MyColumn.class);
                System.out.println(method2Field(method.getName())+" 对应的数据库列名为:"+column.value());
            }

        }


    }

    
public static String method2Field(String methodName){
    String result="";
    result=methodName.replaceFirst("get","");
    return result.length()<=0?"":result.toLowerCase();
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值