注解+反射读取

一、注解

1.简介

  • JDK1.5引入的新技术,不是程序本身,可以对程序作出解释(跟注释也没什么区别)
  • 注解可以被其它程序(如:编译器读取(这是与注释最大的区别,它可以作为信息处理的处理流程

2.内置注解

@Override

  • 定义在java .lang.Override中,此注释只适用于修辞方法,表示一个方法声明打算重写超类中的另一个方法声明

@Deprecated

  • 定义在java.lang.Deprecated中,此注册可用于修辞方法、属性、类,表示不鼓励成员有使用这样的元素,通常是因为它很危险或者存在更好的选择,但是它也依旧能使用,只是不建议

@SuppressWarnings

  • 定义在java.lang.SuppressWarnings中,用来抑制编译时的警告信息
参数说明
deprecation使用了过时的类或方法的警告
unchecked执行了未检查的转换时的警告,如使用集合时未指定泛型
fallthrough当在switch语句时发生case穿透
path在类路径、源文件路径等中有不存在路径的警告
serial当在可序列化的类上缺少serialVersionUID定义时的警告
finally任何finally子句不能完成时的警告
all关于以上所有情况的警告

其实@SuppressWarnings注解用的也比较少,大多数人都是喜欢用all参数而已

二、自定义注解

1.使用@interface自定义注解

使用其注解会自动继承java.lang.annotation.Annotation接口

2.要点

2.1.@interface用来声明一个注解

  • 格式为:public @interface 注解名(定义体)

2.2.其接口内每个方法实际是声明一个配置参数

  • 方法的名称就是参数的名称
  • 返回值类型就是参数的类型(返回值类型只能是基本类型、Class、String、enum
  • 可以通default来声明参数的默认值
  • 如果只有一个参数成员,一般参数名为value

2.3.注意

  • 注解元素必须要有值!我们定义注解元素时,经常使用空字符串、0作为默认值
  • 也经常使用负数(比如:-1)表示不存在的含义

3.元注解

3.1介绍

  • 元注解是作用就是负责注解其他注解
  • Java定义了4个标准的meta-annotation类型,他们被用来提供对其它annotation类型作说明

3.2类型

这些类型和它们所支持的类在java.lang.annotation包中可以找到:

  1. @Target
    作用:用于描述注解的适用范围(即:被描述的注解可以用在什么地方)
所修饰范围取值 ElementType
package 包PACKAGE
类、接口、枚举、Annotation类型TYPE
类型成员(方法、构造方法、成员变量、枚举值)CONSTRUCTOR:用户描述构造器
FIELD:用于描述域
METHOD:用于描述方法
方法参数和本地变量LOCAL、VARIABLE::用于描述局部变量
METHOD:用于描述参数
package java.lang.annotation;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
    /**
     * Returns an array of the kinds of elements an annotation type
     * can be applied to.
     * @return an array of the kinds of elements an annotation type
     * can be applied to
     */
    ElementType[] value();
}

  1. @Retention
取值RetentionPolicy作用
SOURCE在源文件中有效(即源文件保留)
当Java文件编译成class文件注解被遗弃
CLASS在class文件中有效(即class保留)
但jvm加载class文件时候被遗弃
RUNTIME在运行时有效(即运行时保留)
注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在
Runtime可以被反射机制读取

这3个生命周期分别对应于:Java源文件(.java文件) —> .class文件 —> 内存中的字节码

首先要明确生命周期长度 SOURCE < CLASS < RUNTIME ,所以前者能作用的地方后者一定也能作用。一般如果需要在运行时去动态获取注解信息,那只能用 RUNTIME 注解;如果要在编译时进行一些预处理操作,比如生成一些辅助代码(如 ButterKnife),就用 CLASS注解;如果只是做一些检查性的操作,比如 @Override@SuppressWarnings,则可选用 SOURCE 注解。

package java.lang.annotation;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
    /**
     * Returns the retention policy.
     * @return the retention policy
     */
    RetentionPolicy value();
}
  1. @Document
  2. @Inherited

3.3实现

注解类:

package cn.edu.chan.test;

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

/**
 * @Author 蝉
 * @Date 2021/8/7 12:38
 */
@Target(value={ElementType.METHOD,ElementType.TYPE}) //能注解到方法和类上
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotationTest01 {

    String str() default "";  //若没有定义初始值,定义的注解上需要传入相应值,否则报错
    int integer1() default 0;
    int integer2() default -1;  //-1表示这个值不存在的含义
}

实现测试类:

package cn.edu.chan.test;

/**
 * @Author 蝉
 * @Date 2021/8/7 13:10
 */
//@AnnotationTest01
public class Test01 {

    @AnnotationTest01(str = "11",integer1 = 0,integer2 = 1)
    public void test01(){

    }
}

三、反射读取注解

1.什么是ORM(Object Relationship Mapping)

缩写如其名:对象关系映射
如:

  • 类与表结构对应
  • 属性和字段对应
  • 对象和记录对应

2.使用注解完成类与表结构的映射关系

类的注解类:

package cn.edu.chan.annotation;

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

/**
 * @author 蝉
 * @version 1.0
 * @date 2021/8/8 10:08
 */
@Target(value={ElementType.TYPE}) //能注解到类上
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotationTest02 {
        String value();
}

属性的注解类:

package cn.edu.chan.annotation;

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

/**
 * @author 蝉
 * @version 1.0
 * @date 2021/8/8 10:13
 */
@Target(value={ElementType.FIELD}) //能注解到属性上
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotationTest03 {
    String columName();

    String type();

    int length();

}

实体:

package cn.edu.chan.annotation;


/**
 * @author 蝉
 * @version 1.0
 * @date 2021/8/8 10:08
 */
@AnnotationTest02("user")
public class User {

    @AnnotationTest03(columName = "name", type = "varchar", length = 10)
    private String username;

    @AnnotationTest03(columName = "psw", type = "varchar", length = 15)
    private String password;

    @AnnotationTest03(columName = "age", type = "int", length = 3)
    private int age;

    public User() {
    }

    public User(String username, String password, int age) {
        this.username = username;
        this.password = password;
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", age='" + age + '\'' +
                '}';
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

反射测试类:

package cn.edu.chan.annotation;

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

/**
 *使用反射读取注解的信息,模拟处理注解信息的流程
 * @author 蝉
 * @version 1.0
 * @date 2021/8/8 10:08
 */
public class Test02 {

    public static void main(String[] args) throws ClassNotFoundException {
        Class clazz = Class.forName("cn.edu.chan.annotation.User");

        //获取类的所有的注解
        Annotation[] annotations = clazz.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println(annotation);
        }

        //获得类的指定的注解
        AnnotationTest02 annotation = (AnnotationTest02)clazz.getAnnotation(AnnotationTest02.class);
        System.out.println(annotation.value());

        //获得类的属性的注解
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            AnnotationTest03 annotationTest03 = field.getAnnotation(AnnotationTest03.class);
            System.out.println(annotationTest03.columName()+"___"+
                    annotationTest03.type()+"___"+annotationTest03.length());
        }

        //注解反射获取表名等信息,拼出SQL语句,然后执行相关SQL,在数据库中可生成相应实体类表
    }
}

四、反射机制

1.概述

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制

  1. 要解剖一个类,必须先要获取到该类的字节码文件对象,而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象
  2. 对象是表示或封装一些数据。
  3. 一个类被加载后,JVM会创建一个对应该类的Class对象,类的整个结构信息会放到对应的Class对象中。
  4. 这个Class对象就像一面镜子一样,通过这面镜子我可以看到对应类的全部信息。

2.Class对象的获取

Class对象的获取并没有那么高大上,主要的一些获取方法还是那些常用的,记住比如Class.forName(全限定类名)等方法就够用了

package cn.edu.chan.myclass;

/**
 * @author 蝉
 * @version 1.0
 * @date 2021/8/8 11:13
 */
public class Test01 {
    public static void main(String[] args) {
        String path = "cn.edu.chan.annotation.User";

        try {

            Class clazz = Class.forName(path);
            //对象是表示或封装一些数据.一个类被加载后,JVM会创建一个对应该类的Class对象
            // 类的整个结构信息会放到对应的Class对象中。
            //这个Class对象就像一面镜子一样,通过这面镜子我可以看到对应类的全部信息。
            System.out.println(clazz.hashCode());

            Class clazz2 = Class.forName(path); //一个类只对应一个Class对象
            System.out.println(clazz2.hashCode());

            Class strClazz = String.class;
            Class strClazz2 = path.getClass();
            System.out.println(strClazz==strClazz2);

            Class intClazz =int.class;

            int[] arr01 = new int[10];
            int[][] arr02 = new int[30][3];
            int[] arr03 = new int[30];
            double[] arr04 = new double[10];

            System.out.println(arr01.getClass().hashCode());
            System.out.println(arr02.getClass().hashCode());
            System.out.println(arr03.getClass().hashCode());
            System.out.println(arr04.getClass().hashCode());


        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

结果:

1163157884
1163157884
true
1956725890
356573597
1956725890
1735600054

Process finished with exit code 0

这里也很清楚的得出:一个类对应只同一个Clss对象,但是不同的维度对应的Class对象又不同。

3.应用反射的API,获取类的信息(类的名字、属性、方法、构造器等)

package cn.edu.chan.myConstructor;

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

/**
 * 应用反射的API,获取类的信息(类的名字、属性、方法、构造器等)
 *
 * @author 蝉
 * @version 1.0
 * @date 2021/8/8 23:47
 */
public class Test01 {
    public static void main(String[] args) {
        String path = "cn.edu.chan.annotation.User";

        try {
            Class clazz = Class.forName(path);

            //获取类的名字
            System.out.println(clazz.getName());    //获得包名+类名:cn.edu.chan.annotation.User
            System.out.println(clazz.getSimpleName());  //获的类名:User

            //获取属性信息
            //   Field[] fields = clazz.getFields(); //只能获得public的field
            Field[] fields = clazz.getDeclaredFields(); //获得所有的field
            Field f = clazz.getDeclaredField("username");
            System.out.println(fields.length);
            for (Field temp : fields) {
                System.out.println("属性:" + temp);
            }
            //获取方法信息
            Method[] methods = clazz.getDeclaredMethods();
            Method m01 = clazz.getDeclaredMethod("getUsername", null);
            //如果方法有参,则必须传递参数类型对应的class对象
            Method m02 = clazz.getDeclaredMethod("setUsername", String.class);
            for (Method m : methods) {
                System.out.println("方法:" + m);
            }

            //获得构造器信息
            Constructor[] constructors = clazz.getDeclaredConstructors();
            Constructor c = clazz.getDeclaredConstructor(String.class, String.class, int.class);
            System.out.println("获得构造器:" + c);
            for (Constructor temp : constructors) {
                System.out.println("构造器:" + temp);
            }


        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

结果:

**cn.edu.chan.annotation.User
User
3
属性:private java.lang.String cn.edu.chan.annotation.User.username
属性:private java.lang.String cn.edu.chan.annotation.User.password
属性:private int cn.edu.chan.annotation.User.age
方法:public java.lang.String cn.edu.chan.annotation.User.toString()
方法:public void cn.edu.chan.annotation.User.setUsername(java.lang.String)
方法:public java.lang.String cn.edu.chan.annotation.User.getUsername()
方法:public int cn.edu.chan.annotation.User.getAge()
方法:public void cn.edu.chan.annotation.User.setPassword(java.lang.String)
方法:public void cn.edu.chan.annotation.User.setAge(int)
方法:public java.lang.String cn.edu.chan.annotation.User.getPassword()
获得构造器:public cn.edu.chan.annotation.User(java.lang.String,java.lang.String,int)
构造器:public cn.edu.chan.annotation.User()
构造器:public cn.edu.chan.annotation.User(java.lang.String,java.lang.String,int)**

4. 通过反射API动态的操作:构造器、方法、属性

package cn.edu.chan.myConstructor;

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

/**
 * 应用反射的API,获取类的信息(类的名字、属性、方法、构造器等)
 *
 * @author 蝉
 * @version 1.0
 * @date 2021/8/8 23:47
 */
public class Test01 {
    public static void main(String[] args) {
        String path = "cn.edu.chan.annotation.User";

        try {
            Class clazz = Class.forName(path);

            //获取类的名字
            System.out.println(clazz.getName());    //获得包名+类名:cn.edu.chan.annotation.User
            System.out.println(clazz.getSimpleName());  //获的类名:User

            //获取属性信息
            //   Field[] fields = clazz.getFields(); //只能获得public的field
            Field[] fields = clazz.getDeclaredFields(); //获得所有的field
            Field f = clazz.getDeclaredField("username");
            System.out.println(fields.length);
            for (Field temp : fields) {
                System.out.println("属性:" + temp);
            }
            //获取方法信息
            Method[] methods = clazz.getDeclaredMethods();
            Method m01 = clazz.getDeclaredMethod("getUsername", null);
            //如果方法有参,则必须传递参数类型对应的class对象
            Method m02 = clazz.getDeclaredMethod("setUsername", String.class);
            for (Method m : methods) {
                System.out.println("方法:" + m);
            }

            //获得构造器信息
            Constructor[] constructors = clazz.getDeclaredConstructors();
            Constructor c = clazz.getDeclaredConstructor(String.class, String.class, int.class);
            System.out.println("获得构造器:" + c);
            for (Constructor temp : constructors) {
                System.out.println("构造器:" + temp);
            }


        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

结果:

User{username='null', password='null', age='0'}
小明
小王
小红
小红

5.通过反射获取泛型信息

package cn.edu.chan.myConstructor;

import cn.edu.chan.annotation.User;

import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;

/**
 * 通过反射获取泛型信息
 * @author 蝉
 * @version 1.0
 * @date 2021/8/9 10:03
 */
public class Test03 {
    public void test01(Map<String, User> map, List<User> list){
        System.out.println("Test03.test01()");
    }
    public Map<Integer,User> test02(){
        System.out.println("Test03.test02()");
        return null;
    }
    public static void main(String[] args) {
        try {
            //获得指定方法参数泛型信息
            Method m = Test03.class.getMethod("test01", Map.class,List.class);
            //getGenericParameterTypes:返回-方法参数为泛型(参数化类型)的Type类型的数组 Type[]
            Type[] t = m.getGenericParameterTypes();
            for (Type paramType : t) {
                System.out.println("#"+paramType);
                //ParameterizedType是一个接口,这个类可以用来检验泛型是否被参数化
                if(paramType instanceof ParameterizedType){
                    //获取运行时期泛型的具体类型
                    Type[] genericTypes = ((ParameterizedType) paramType).getActualTypeArguments();
                    for (Type genericType : genericTypes) {
                        System.out.println("泛型类型:"+genericType);
                    }
                }
            }
            //获得指定方法返回值泛型信息
            Method m2 = Test03.class.getMethod("test02", null);
            //getGenericReturnType:返回-返回值为泛型(参数化类型)的Type类型的数组 Type[]
            Type returnType = m2.getGenericReturnType();
            //ParameterizedType是一个接口,这个类可以用来检验泛型是否被参数化
            System.out.println("###"+returnType);
            if(returnType instanceof ParameterizedType){
                //获取运行时期泛型的具体类型
                Type[] genericTypes = ((ParameterizedType) returnType).getActualTypeArguments();
                for (Type genericType : genericTypes) {
                    System.out.println("返回值,泛型类型:"+genericType);
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}


结果:

#java.util.Map<java.lang.String, cn.edu.chan.annotation.User>
泛型类型:class java.lang.String
泛型类型:class cn.edu.chan.annotation.User
#java.util.List<cn.edu.chan.annotation.User>
泛型类型:class cn.edu.chan.annotation.User
###java.util.Map<java.lang.Integer, cn.edu.chan.annotation.User>
返回值,泛型类型:class java.lang.Integer
返回值,泛型类型:class cn.edu.chan.annotation.User

Type 是所有类型的高级公共接口,当然也是Class的父类。
它们包括原始类型、参数化类型、数组类型、类型变量和基本类型。

Java注解是一种元数据,它可以为、方法、字段等元素添额外的信息。在Java中,可以使用自定义注解反射来实现导入导出Excel文档。 首先,定义一个自定义注解,用于标记需要导出的实体的字段: ```java @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface ExcelField { /** * 列名 */ public String name(); /** * 顺序 */ public int order(); } ``` 然后,在实体的字段上添注解: ```java public class User { @ExcelField(name = "姓名", order = 1) private String name; @ExcelField(name = "年龄", order = 2) private int age; // 省略其他字段和方法 } ``` 接着,定义一个工具,用于读取和写入Excel文档: ```java public class ExcelUtil { /** * 从Excel中读取数据 */ public static <T> List<T> readFromExcel(InputStream is, Class<T> clazz) { List<T> list = new ArrayList<>(); try { Workbook workbook = WorkbookFactory.create(is); Sheet sheet = workbook.getSheetAt(0); Map<Integer, String> headers = getHeaders(sheet.getRow(0)); for (int i = 1; i <= sheet.getLastRowNum(); i++) { Row row = sheet.getRow(i); T obj = clazz.newInstance(); for (int j = 0; j < row.getLastCellNum(); j++) { Cell cell = row.getCell(j); String value = getValue(cell); String fieldName = headers.get(j); Field field = clazz.getDeclaredField(fieldName); field.setAccessible(true); setValue(obj, field, value); } list.add(obj); } } catch (Exception e) { e.printStackTrace(); } return list; } /** * 写入数据到Excel中 */ public static <T> void writeToExcel(List<T> list, OutputStream os) { try { Workbook workbook = new XSSFWorkbook(); Sheet sheet = workbook.createSheet(); Row header = sheet.createRow(0); Map<String, Integer> fields = getFields(list.get(0).getClass()); List<String> fieldNames = new ArrayList<>(fields.keySet()); Collections.sort(fieldNames); for (int i = 0; i < fieldNames.size(); i++) { String fieldName = fieldNames.get(i); Cell cell = header.createCell(i); cell.setCellValue(fields.get(fieldName)); } for (int i = 0; i < list.size(); i++) { Row row = sheet.createRow(i + 1); T obj = list.get(i); for (int j = 0; j < fieldNames.size(); j++) { String fieldName = fieldNames.get(j); Field field = obj.getClass().getDeclaredField(fieldName); field.setAccessible(true); Object value = field.get(obj); Cell cell = row.createCell(j); cell.setCellValue(value.toString()); } } workbook.write(os); } catch (Exception e) { e.printStackTrace(); } } /** * 获取Excel中的列名 */ private static Map<Integer, String> getHeaders(Row row) { Map<Integer, String> headers = new HashMap<>(); for (int i = 0; i < row.getLastCellNum(); i++) { Cell cell = row.getCell(i); String value = getValue(cell); headers.put(i, value); } return headers; } /** * 获取实体中的字段名和顺序 */ private static <T> Map<String, Integer> getFields(Class<T> clazz) { Map<String, Integer> fields = new HashMap<>(); Field[] declaredFields = clazz.getDeclaredFields(); for (Field field : declaredFields) { if (field.isAnnotationPresent(ExcelField.class)) { ExcelField excelField = field.getAnnotation(ExcelField.class); fields.put(field.getName(), excelField.order()); } } return fields; } /** * 设置实体中的字段 */ private static <T> void setValue(T obj, Field field, String value) throws Exception { String typeName = field.getType().getName(); if ("int".equals(typeName)) { field.set(obj, Integer.parseInt(value)); } else if ("java.lang.String".equals(typeName)) { field.set(obj, value); } // 省略其他型的判断 } /** * 获取单元格中的 */ private static String getValue(Cell cell) { String value = ""; if (cell != null) { switch (cell.getCellType()) { case STRING: value = cell.getStringCellValue(); break; case NUMERIC: if (DateUtil.isCellDateFormatted(cell)) { Date date = cell.getDateCellValue(); value = new SimpleDateFormat("yyyy-MM-dd").format(date); } else { value = String.valueOf(cell.getNumericCellValue()); } break; case BOOLEAN: value = String.valueOf(cell.getBooleanCellValue()); break; case FORMULA: value = String.valueOf(cell.getCellFormula()); break; default: value = ""; } } return value; } } ``` 最后,可以使用该工具读取和写入Excel文档: ```java public class Main { public static void main(String[] args) { // 从Excel中读取数据 try (InputStream is = new FileInputStream("users.xlsx")) { List<User> list = ExcelUtil.readFromExcel(is, User.class); for (User user : list) { System.out.println(user.getName() + ", " + user.getAge()); } } catch (Exception e) { e.printStackTrace(); } // 写入数据到Excel中 List<User> list = new ArrayList<>(); list.add(new User("张三", 20)); list.add(new User("李四", 30)); list.add(new User("王五", 40)); try (OutputStream os = new FileOutputStream("users.xlsx")) { ExcelUtil.writeToExcel(list, os); } catch (Exception e) { e.printStackTrace(); } } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值