Java自定义注解应用与理解

一、自定义注解的案例分析

对于后端开发人员来说,我们在编写的程序的过程当中经常用到,例如现在JDK预定义的注解@Override,@Deprecated,@SuppressWarning。通用springmvc框架就包含的大量的注解内容,如@Controller,@Service,@Transactional等。

实际案例分析:

一、参数非空校验

常见的web请求需要首先对参数进行校验,必传参数不能为空,或者有特殊的格式需求。

1、以参数不能为空为例,首先我们需要自定义一个非空校验的注解:

@Documented
@Inherited
@Target(value = {ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface NotNull {
    boolean require() default true;
}

2、对该注解进行处理:

package reflect;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

import java.util.logging.Logger;

public class StudentParamValidate {
    //记录日志
    Logger logger = Logger.getLogger("JDKLog");

    public void validate() {
        Field[] fields = this.getClass().getDeclaredFields();
        for (Field field : fields) {
            //判断是否存在注解
            if (field.isAnnotationPresent(NotNull.class)) {
                //获取注解值
                NotNull nn = field.getAnnotation(NotNull.class);
                //如果需要参数校验
                if (nn.require()) {
                    if (field.getGenericType().toString().equals("class java.lang.String")
                            || field.getGenericType().toString().equals("class java.lang.Integer")) {
                        try {
                            //获取get方法
                            Method getter = this.getClass().getMethod("get" + getMethodName(field.getName()));
                            //执行get方法
                            String value = (String) getter.invoke(this);
                            //判断属性值是否为null
                            if (value == null) {
                                System.out.println(field.getName() + "不可为空");
                            }
                        } catch (Exception e) {
                            logger.info(e.getMessage());
                        }
                    }
                }
            }
        }
    }

    /**
     * 方法首字母改为大写
     *
     * @param filedName
     * @return
     * @throws Exception
     */
    public String getMethodName(String filedName) throws Exception {
        byte[] items = filedName.getBytes();
        items[0] = (byte) ((char) items[0] - 'a' + 'A');
        return new String(items);
    }
}

3、定义使用该注解的对象:

package reflect;

public class Student extends StudentParamValidate{
    @NotNull
    private String idNumber;
    @NotNull
    private String classId;
    private String sex;
    private String height;

    public String getIdNumber() {
        return idNumber;
    }

    public void setIdNumber(String idNumber) {
        this.idNumber = idNumber;
    }

    public String getClassId() {
        return classId;
    }

    public void setClassId(String classId) {
        this.classId = classId;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getHeight() {
        return height;
    }

    public void setHeight(String height) {
        this.height = height;
    }

    public void sleep() {
        System.out.println("sleep......");
    }
}

4、使用该对象:

package reflect;

public class NotNullTest {
    public static void main(String[] args) {
        Student student = new Student();
        student.validate();
    }
}

5、运行结果如下:

二、注解的定义和使用

注释:用文字描述程序,给程序员看的;

注解定义:用来说明程序的一个标识,给计算机看的。注解也叫元数据,是一种代码级别的说明。它是jdk1.5之后引入的一个特性,可以使用在字段、类、方法、包、参数等上面。

注意:注解本身并没有任何功能,仅仅起到一个标识性的作用,我们是通过反射去获取到注解,再根据是否有这个注解、注解中的一些属性去判断,执行哪种业务逻辑。

注解作用分类:

①编写文档:通过代码里的注解标识去生成API文档(Swagger);

②代码分析:通过注解去对代码进行逻辑分析(通过反射去操作业务);

③编译检查:通过注解让编译器实现基本的编译检查(Override等)

JDK预定义的一些注解:

①Override:检测该注解标识方法是否继承自父类(接口)

②Deprecated:标识该内容已经过时,后续版本可能会进行移除

③SuppressWarning:压制警告,指定警告级别,这个级别下的警告全部不显示

自定义注解:

在实际开发当中,可能存在一些代码极其复杂或者复用性很低的业务逻辑,比如导出Excel、缓存、将返回值转JSON、事物等等,此时可以使用自定义注解。

注解格式:

Public @interface 注解名称{

            属性列表;

}

本质:本质即为接口,该接口继承Annotation接口

属性:

本质:接口中的抽象方法

属性只能是以下几种数据类型:

  1. 基本数据类型

  2. String

  3. 枚举

  4. 注解

  5. 以上类型的数组

如果定义了属性,在使用的时候需要给属性赋值。如果只有一个属性需要赋值,并且这个属性叫value,那么可以省略属性名。数组赋值的事就,值用{}包住,如果数据中只有一个值,那么大括号可以省略。

元注解:

用于描述注解的注解

@Target:描述注解的作用范围

          ElementType取值:

                       TYPE:作用于类;

                       METHOD:作用于方法;

                       FIELD:作用于字段

@Rentention:描述注解被保留的阶段

                       RententionPolicy.RUNTIME:当前描述的注解,会保留到class字节码文件中,并且被JVM读取到

@Documented:描述注解是否被抽取到API文档中;

@Inherited:描述注解是否可以被继承

三、反射的基本原理

反射概念:框架设计的灵魂(框架:半成品软件,开发人员可以在框架的基础之上进行软件开发,简化编码),将类的各个组成部分分装为其他对象,这就是反射机制,注解的运行通过反射进行实现。

Java代码在计算机中经历的阶段:

  1. 源代码阶段:Hello.java--》(javac编译)--》Hello.class;
  2. Class类对象阶段:Hello.class--》(类加载器ClassLoader)--》Class类对象(成员变量Field[] fields,构造方法Constructor[] constructors,成员方法Method[] methods)

获取Class类对象的方式:

  1. Class.forName(“全类名”):将字节码文件加载进内存,返回Class对象,该方法多用于配置文件,将类名定义在配置文件中,读取文件,加载类;
  2. 类名.class:通过类名的属性class进行获取,多用于参数的传递
  3. 对象.getClass():getClass()方法在Object类中已定义,所以所有的对象都会有该方法。多用于通过对象获取字节码方式。

    同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪种方式获取的Class对象都是同一个。

使用Class对象功能:

获取功能(13个方法,带Declared的表示获取类中所有的成员变量或构造方法或成员方法,无Declared表示只获取类中有public修饰符的成员变量或构造方法或成员方法)

    获取成员变量:

                       Field[] getFields()//获取public成员变量

                       Field getField(String name)//获取指定名称的public变量

                       Filed[] getDeclaredFields() //获取所有成员变量

                       Field getDeclaredFiled(String name)//获取指定名称的成员变量

    获取构造方法:

                       Constructor<?>[] getConstructors()

                       Constructor<T> getConstructor(类<?>… paramterTypes)              

                       Constructor<?>[] getDeclaredConstructors()

                       Constructor getDeclaredConstrctor(类<?>… paramterTypes)

    获取成员方法:

                       Method[] getMethods()

                       Method getMethod(String name, 类<?>… paramterTypes)

                       Method [] getDeclaredMethods()

                       Method getDeclaredMethod (String name, 类<?>… paramterTypes)

   获取类名:

                     String getName()

反射的好处:在程序运行的过程中操作这些对象;解耦,提高程序的可拓展性

反射应用举例:

获取String等类java文件编译成字节码文件,通过将类中的方法放入Class类对象里面的method数组中,形成类的方法提示。Idea运行的程序会加载原有的代码,通过反射的方式获取了方法数组形成了如下图所示提示:

四、其他

学习视频

反射:https://www.bilibili.com/video/av56351262?from=search&seid=5718519849187580994

注解:https://www.bilibili.com/video/av62102209?from=search&seid=15039447101929918322

B站上有非常丰富的技术的视频讲解,尤其是每个视频按照标题进行了系统汇总,资源优质,学习便捷,深感B站是日常网上学习的好工具。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值