首页 > 编程语言 > 详细

java学习-反射-泛型

时间:2020-11-19 14:19:34      阅读:45      评论:0      收藏:0      [点我收藏+]

根据java language 中对于泛型的定义为

 

The Java Language Specification, Java SE 8 Edition

 https://docs.oracle.com/javase/specs/

8.1.2 Generic Classes and Type Parameters

A class is generic if it declares one or more type variables (§4.4).

 

 

4.4 Type Variables
A type variable is an unqualified identifier used as a type in class, interface, method,
and constructor bodies.

 

对于一个定义的class上存在相关字段定义称为泛型;

从 since 1.5 的 java.lang.reflect.Type 接口开始 对于 普通的java.lang.Class 和 泛型类型 java.lang.reflect.ParameterizedType 就有了明显的区分

对比java.lang.Class#getGenericInterfaces 和 java.lang.Class#getInterfaces 的区别

 

  • 从返回值角度对比: Type[] 和 Class[], 对于Class信息中是不包含泛型相关信息,而Type[] 中包含 ParameterizedType 和 Class 两种类型,对于泛型类获取到的就是ParameterizedType类型的数据而非普通的Class

对于泛型存在运行使用时擦写的特性,对于运行时使用实际就是统一的Object类型而非具象化的类型;

例如在spring-data-jpa 中的Repository 或CRUDRepository<T,ID>, 需要动态生成相关sql,因此需要获取到泛型的具体类型,对于当前场景支持使用反射的方式来进行实现

/*
 * Copyright (c) 2020, guoxing, Co,. Ltd. All Rights Reserved
 */
package com.xingguo.reflection.application;

import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.io.Serializable;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Stream;

/**
 * GenericDemo
 * 反射泛型相关
 *
 * @author guoxing
 * @date 2020/11/17 8:56 PM
 * @since
 */
@Slf4j
public class GenericDemo {

    public static void main(String[] args) throws URISyntaxException {
        // 解析当前目录下使用@Repository注解的实现类
        // 获取当前class所在路径
        URL location = GenericDemo.class.getProtectionDomain().getCodeSource().getLocation();
        // 获取当前前端编译输出路径
        String dependencyPath = location.getPath();
        // 获取当前类的包路径
        String packageName = GenericDemo.class.getPackage().getName();
        // 组合完整的文件路径
        String folder = dependencyPath.concat(packageName.replace(".", File.separator));
        // 扫描当前系统下的class文件
        File file = new File(folder);
        if (file.isDirectory()) {
            // 过滤当前文件夹下的全部class文件名称
            String[] classNames = file.list((dir, name) -> name.endsWith(".class"));
            if (Objects.isNull(classNames)) {
                return;
            }
            // 获取当前线程类加载器
            ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
            // 存储使用Repository注解的类
            List<Class<?>> repositoryAnnotationClass = new LinkedList<>();
            // 加载当前Class
            Arrays.stream(classNames)
                    // 转换当前className为全路径
                    .map(className -> packageName.concat(".").concat(className.substring(0, className.lastIndexOf("."))))
                    .forEach(reference -> {
                        // 加载class并进行筛选
                        try {
                            Class<?> aClass = contextClassLoader.loadClass(reference);
                            // 判断当前类是否使用@Repository
                            if (aClass.isAnnotationPresent(Repository.class)) {
                                repositoryAnnotationClass.add(aClass);
                            }
                        } catch (ClassNotFoundException e) {
                            e.printStackTrace();
                        }
                    });
            // 解析当前类
            repositoryAnnotationClass.stream()
                    .filter(c ->
                            // 获取当前类全部实现的接口
                            !Modifier.isAbstract(c.getModifiers()) && UserRepository.class.isAssignableFrom(c)// 判断当前类是否实现了当前接口
                    ).forEach(c -> {
                // 解析当前类的接口中的泛型字段的具体类型
                Arrays.stream(c.getGenericInterfaces())
                        .filter(type -> type instanceof ParameterizedType) // 过滤当前接口类型为执行泛型的接口 , 对于UserRepositoryImpl实现的三个接口类型可参考一下相关解释
                        .map(type -> (ParameterizedType) type) // 将当前类型转换为ParameterizedType
                        .forEach(parameterizedType -> {
                            if (UserRepository.class.equals(parameterizedType.getRawType())) {
                                // 获取当前泛型类型的泛型参数("<>"中的实际定义)
                                Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
                                // 遍历当前泛型定义的参数
                                // 对于当前数据的作用
                                // 类似于 spring-data 中的 "org.springframework.data.repository.CrudRepository<T, ID>" 根据 泛型 <T> 来实现动态sql生成
                                Stream.of(actualTypeArguments)
                                        .forEach(type -> {
                                            String typeName = type.getTypeName();
                                            log.info("{}", typeName);
                                            try {
                                                contextClassLoader.loadClass(typeName);
                                            } catch (ClassNotFoundException e) {
                                                e.printStackTrace();
                                            }
                                        });
                            }
                        });

            });
        }

    }
}


// 参考spring-data repository

interface UserRepository<T> {

}

/**
 * 实际执行
 */
@Repository(tableName = "user")
class UserRepositoryImpl implements UserRepository<User>,// 对于当前接口的类型实际属于 ParameterizedType 继承至Type ,对于java.lang.reflect.ParameterizedType.getActualTypeArguments 实际就是 UserRepository<User> 中的 "<>"中的User类型
        Comparable<UserRepositoryImpl>,//和UserRepository<User>类型一样都是ParameterizedType
        Serializable // 对于当前类型而言,其为 Class类型
{
    @Override
    public int compareTo(UserRepositoryImpl o) {
        return 0;
    }
}

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@interface Repository {
    String tableName() default "";
}

class User {
    private String name;

    private Integer age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

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

 

java学习-反射-泛型

原文:https://www.cnblogs.com/xingguoblog/p/14005053.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!