注解与反射

本文介绍了Java中的注解和反射机制。注解用于提供编译时和运行时的元数据,可以用于生成文档、代码检查和替代配置文件。文章讨论了内置注解如@Override、@Deprecated和@SuppressWarnings,以及元注解如@Retention和@Target。同时,阐述了自定义注解的创建。反射机制允许在运行时获取类和对象的信息,动态调用方法和访问属性,但也带来了性能损失。最后,提到了如何通过反射获取注解信息,以实现类和表结构的映射。
摘要由CSDN通过智能技术生成

注解的定义

注解(Annotation)和注释(Comment)一样都不是程序本身,而是对程序作出解释,而注解与注释不同的点在于,注解可以被其他程序,比如编译器读取。

注解的作用

  1. 生成 javadoc 文档;
  2. 跟踪代码依赖性,实现代替配置文件功能;
  3. 在编译时进行格式检查。

注解的分类

三个内置注解

  • @Override:表示重写的注解;
  • @Deprecated:表示即将废弃的注解,可以用来修饰方法,属性,类;
  • @SuperWarnings:表示抑制警告信息的注解,在写代码时,可能会出现一些黄色的警告,但是并不影响运行,我们可以用这个注解来隐藏这些警告。与前两个注解不同的是我们必须给这个注解参数才能正确使用。参数如下:
参数说明
deprecation使用了过时的类或方法的警告
unchecked执行了未检查的转换时的警告 如:使用集合时未指定泛型
fallthrough当在 switch 语句使用时发生 case 穿透
serial当在序列化的类上缺少 serialVersionUID 定义时的警告
path在类路径、源文件路径中有不存在路径的警告
finally任何 finally 子句不能完成时的警告
all包括以上所有的警告

四个元注解

元注解的作用就是负责注解其它注解。

  • @Target:用于表示注解的使用范围的元注解;其中的可选参数如下:
使用范围取值 ElementType
PACKAGE
类、接口、枚举、注解TYPE
类型成员FIELD:用于描述域;CONSTRUCTOR:用于描述构造器;METHOD:用于描述方法。
其它LOCAL_VARIABLE:用于描述局部变量;PARAMETER:用于描述参数。
  • @Retention:用于描述注解的生命周期的元注解,作用是告诉编译器该注解信息的保存级别,其中的可选参数如下:
    | 参数 | 取值 RetentionPolicy |
    | :-----: | :------------------: |
    | SOURCE | 在源代码中有效 |
    | CLASS | 在类文件中有效 |
    | RUNTIME | 在运行时有效 |

一般情况下我们使用 RUNTIME 参数,因为这样我们可以在程序运行时通过反射 机制来读取该注解。

  • @Document:说明该注解将被包含在 javadoc 中;
  • @Inherited:说明子类可以继承父类中的该注解。

自定义注解

通过如下的代码,以及对应的注释可以很好的掌握自定义注解,同时注解的强大作用就需要之后和的反射一起结合起来看。

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

public class Test {
    // 现学先用,直接使用下面自己创建的注解
    // 多个参数使用 “,” 隔开
    @CustomizeAnnotation(age = 24, schools = {"浙江工业大学", "兰溪市第三中学"})
    public void method(){
        System.out.println("That`s all.");
    }
}

// 当然还可以用元注解修饰注解
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
/**
 * 这是一个自定义的名为 CustomizeAnnotation 的注解
 * 注解是用 @interface 修饰的:(public) @interface 注解名(定义内容)
 * @author sharm
 */
@interface CustomizeAnnotation{
    // 注解参数的形式为:参数类型 + 参数名();
    // 若参数没有默认值,因此在使用时必须给定参数
    int age();
    // 若参数存在默认值,则在使用时可以不给定参数,而使用默认参数
    String name() default "sharm";
    // 参数类型只能是八大基本数据类型、String、Enum、Class、Annotation 以及它们对应的类型数组之一
    String[] schools();
}

参考文献一:传送门

参考文献二:传送门


反射机制介绍

在运行期间,通过 Java 的反射机制,对于任何一个类,都能够知道这个类的属性和方法;对于任何一个对象,都能够调用这个对象的属性和方法。Java 的反射机制可以让用户动态地获取类的信息以及动态调用对象的功能

反射的原理就是利用 Java 虚拟机通过类的字节码文件反向获取该类或者对象中的属性和方法。

反射机制优缺点

  • 优点: 动态加载类,提高代码灵活度;
  • **缺点:**因为反射相当于一系列解释操作,因此性能比直接的 java 代码要慢;使用反射会模糊程序内部逻辑。

反射的实现方式

Class 类是基于反射机制的,Class 由 final 修饰,一个 Class 类的实例表示这个类的类型信息。

  • 通过Class c1 = 类名.class
  • 通过Class c2 = 对象名.getClass()
  • 通过Class c3 = Class.forName(类的全名的字符串)

通过反射获取注解的信息

任务:利用注解和反射完成类和表结构的映射关系,即:
请添加图片描述
代码实现并运行,注意点在注释中:

import java.lang.annotation.*;
import java.lang.reflect.Field;

public class ReflectAnnotation {
    // 接下来可以通过反射得到对应的注解信息,以此来完成通过类得到数据库表中的信息
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
        // 首先通过反射得到对应的 class 对象
        Class person = Class.forName("Person");
        // 1.通过反射获取类的全部注解信息
        Annotation[] annotations = person.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println(annotation);
        }

        // 2.通过反射获取类的具体注解信息
        ClassAnnotation classAnnotation = (ClassAnnotation)person.getAnnotation(ClassAnnotation.class);
        System.out.println(classAnnotation.value());

        //3.通过反射获得类中属性(域)的具体注解信息
        // getDeclaredField 的是不包括从父类继承的注解
        Field field = person.getDeclaredField("age");
        FiledAnnotation filedAnnotation = field.getAnnotation(FiledAnnotation.class);
        System.out.println(filedAnnotation.columnName());
        System.out.println(filedAnnotation.type());
        System.out.println(filedAnnotation.length());

    }
}

// 该注解表明该对象对应的表名为 dataset_person
@ClassAnnotation(value = "dataset_person")
class Person{
    // 域对应数据库表中的属性
    @FiledAnnotation(columnName = "dataset_id", type = "int", length = 10)
    int id;
    @FiledAnnotation(columnName = "dataset_name", type = "varchar", length = 10)
    String name;
    @FiledAnnotation(columnName = "dataset_age", type = "int", length = 3)
    int age;

    public Person() {
    }

    public Person(int id, String name, int age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }

    public int getId() {
        return id;
    }

    public void setId(int 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;
    }

    @Override
    public String toString() {
        return "Person{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

// 对应类名(数据库表名)的注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface ClassAnnotation{
    String value();
}

// 对应域(数据库字段)的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FiledAnnotation{
    String columnName();
    String type();
    int length();
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值