类工具-ClassUtil
ClassUtil是Hutool反射模块中的核心工具类,提供了丰富的类操作功能,包括类信息获取、类扫描、类路径获取、类型判断、类加载和类层次遍历等。
# 主要功能
- 类信息获取:获取类名、包名、父类、接口等信息
- 类扫描:扫描指定包下的类
- 类路径获取:获取ClassPath和资源路径
- 类型判断:判断是否为基本类型、包装类型、序列化类型等
- 类加载:加载指定名称的类
- 类层次遍历:遍历类的继承层次和接口
- 类序列化判断:判断类是否实现了序列化接口
- 类默认值获取:获取基本类型的默认值
# 核心方法
# 类信息获取
# getClass(T obj)
null安全的获取对象类型。
# getEnclosingClass(clazz)
获得外围类,返回定义此类或匿名类所在的类,如果类本身是在包中定义的,返回null。
# isTopLevelClass(clazz)
是否为顶层类,即定义在包中的类,而非定义在类中的内部类。
# getClassName(clazz, isSimple)
getClassName(String className, boolean isSimple)的重载方法,用于获取Class对象的类名。
# getClassName(clazz, isSimple)
获取类名,isSimple为true时返回不带包名的简单类名。
# getShortClassName(className)
获取完整类名的短格式,如cn.hutool.v7.core.StrUtil -> c.h.c.u.StrUtil。
# getClasses(objects)
获得对象数组的类数组。
# equals(clazz, className, ignoreCase)
指定类是否与给定的类名相同,支持全类名和简单类名比较,支持忽略大小写。
# 类扫描
# scanPackageByAnnotation(packageName, annotationClass)
扫描指定包路径下所有包含指定注解的类。
# scanPackageBySuper(packageName, superClass)
扫描指定包路径下所有指定类或接口的子类或实现类。
# scanPackage(packageName)
扫描指定包路径下所有class文件。
# scanPackage(packageName, classFilter)
扫描指定包路径下满足class过滤器条件的所有class文件。
# 类路径获取
# getClassPathResources()
获得ClassPath,不解码路径中的特殊字符。
# getClassPathResources(isDecode)
获得ClassPath,可选择是否解码路径中的特殊字符。
# getClassPaths(packageName)
获得指定包的ClassPath路径字符串集合,不解码路径中的特殊字符。
# getClassPaths(packageName, isDecode)
获得指定包的ClassPath路径字符串集合,可选择是否解码路径中的特殊字符。
# getClassPath()
获得ClassPath,将编码后的中文路径解码为原字符。
# getClassPath(isEncoded)
获得ClassPath,可选择是否编码路径中的中文。
# 类型判断
# isAllAssignableFrom(types1, types2)
比较判断两组类,如果types1中所有的类都与types2对应位置的类相同,或者是其父类或接口,则返回true。
# isPrimitiveWrapper(clazz)
是否为包装类型。
# isBasicType(clazz)
是否为基本类型(包括包装类和原始类)。
# isBasicTypeMatch(class1, class2)
是否为基本类型的包装类匹配或反之,如int匹配Integer,long匹配Long等。
# isSimpleTypeOrArray(clazz)
是否为简单值类型或简单值类型的数组。
# isSimpleValueType(clazz)
是否为简单值类型,包括原始类型、枚举、String、Number、Date等。
# isAssignable(targetType, sourceType)
检查目标类是否可以从原类转化。
# isSerializable(clazz)
给定类是否实现了序列化接口Serializable。
# isNormalClass(clazz)
是否为标准的类,即非接口、非抽象类、非Enum枚举、非数组、非注解、非原始类型。
# isEnum(clazz)
判断类是否为枚举类型。
# isJdkClass(clazz)
是否为JDK中定义的类或接口。
# 类加载
# forName(name, isInitialized, loader)
加载指定名称的类,支持替换"/"为".",自动查找内部类。
# 类层次遍历
# getSuperClasses(clazz)
获取指定类的所有父类,结果不包括指定类本身。
# getInterfaces(cls)
获取指定类及其父类所有的实现接口。
# traverseTypeHierarchy(root, filter, consumer, includeRoot)
按广度优先遍历包括root在内,其层级结构中的所有类和接口。
# 其他方法
# getTypeArgument(clazz)
获得给定类的第一个泛型参数。
# getDefaultValue(clazz)
获取指定类型的默认值。
# getPrimitiveDefaultValue(clazz)
获取指定原始类型的默认值。
# getLocation(clazz)
获取class类路径URL。
# getLocationPath(clazz)
获取class类路径。
# 示例代码
# 类信息获取
// 获取对象类型
String str = "Hello Hutool";
Class<?> strClass = ClassUtil.getClass(str); // String
// 获取类名
String className = ClassUtil.getClassName(strClass, false); // java.lang.String
String simpleName = ClassUtil.getClassName(strClass, true); // String
// 获取短格式类名
String shortName = ClassUtil.getShortClassName("cn.hutool.v7.core.StrUtil"); // c.h.c.u.StrUtil
// 判断类是否相同
boolean isSame = ClassUtil.equals(String.class, "java.lang.String", false); // true
boolean isSameSimple = ClassUtil.equals(String.class, "String", false); // true
# 类扫描
// 扫描指定包下所有类
Set<Class<?>> classes = ClassUtil.scanPackage("cn.hutool.v7.core");
// 扫描指定包下带有特定注解的类
Set<Class<?>> annotatedClasses = ClassUtil.scanPackageByAnnotation("cn.hutool.v7.core", Component.class);
// 扫描指定包下指定类的子类
Set<Class<?>> subClasses = ClassUtil.scanPackageBySuper("cn.hutool.v7.core", Serializable.class);
# 类路径获取
// 获取ClassPath
String classPath = ClassUtil.getClassPath();
// 获取所有ClassPath资源
Set<String> classPathResources = ClassUtil.getClassPathResources();
// 获取指定包的ClassPath
Set<String> paths = ClassUtil.getClassPaths("cn.hutool.v7.core");
# 类型判断
// 判断是否为基本类型
boolean isBasic = ClassUtil.isBasicType(int.class); // true
boolean isBasicWrapper = ClassUtil.isBasicType(Integer.class); // true
// 判断是否为包装类型
boolean isWrapper = ClassUtil.isPrimitiveWrapper(Integer.class); // true
// 判断是否为简单值类型
boolean isSimple = ClassUtil.isSimpleValueType(String.class); // true
boolean isSimpleEnum = ClassUtil.isSimpleValueType(Enum.class); // true
// 判断是否为序列化类型
boolean isSerializable = ClassUtil.isSerializable(String.class); // true
// 判断是否为标准类
boolean isNormal = ClassUtil.isNormalClass(String.class); // true
boolean isNormalInterface = ClassUtil.isNormalClass(Runnable.class); // false
# 类加载
// 加载指定名称的类
Class<?> clazz = ClassUtil.forName("cn.hutool.v7.core.StrUtil", false, null);
// 加载内部类
Class<?> innerClass = ClassUtil.forName("java.lang.Thread.State", false, null);
# 类层次遍历
// 获取所有父类
List<Class<?>> superClasses = ClassUtil.getSuperClasses(HashMap.class);
// 获取所有接口
List<Class<?>> interfaces = ClassUtil.getInterfaces(HashMap.class);
// 遍历类层次
ClassUtil.traverseTypeHierarchy(HashMap.class,
t -> !t.isPrimitive(), // 过滤掉基本类型
t -> Console.log(t.getName()), // 打印类名
true); // 包括根类
# 注意事项
- 类扫描性能:扫描大量类时可能会影响性能,建议在应用启动时执行一次并缓存结果。
- 类加载安全:动态加载类时应注意安全问题,避免加载不可信的类。
- 内部类加载:加载内部类时,需要使用$分隔符,如java.lang.Thread$State。
- JDK类限制:某些方法对JDK类有限制,如getLocation和getLocationPath方法不能用于JDK中的类。
- 类路径编码:不同操作系统的类路径编码可能不同,使用时注意编码问题。
# 最佳实践
- 缓存类扫描结果:类扫描是一个开销较大的操作,建议在应用启动时执行一次并缓存结果。
- 使用类过滤器:在扫描类时,使用合适的过滤器可以减少返回的类数量,提高性能。
- 优先使用类型判断方法:使用ClassUtil提供的类型判断方法可以提高代码的可读性和可维护性。
- 避免频繁类加载:类加载是一个开销较大的操作,建议缓存加载结果。
- 使用类层次遍历简化代码:对于需要遍历类层次的场景,使用traverseTypeHierarchy方法可以简化代码。
# 总结
ClassUtil是Hutool反射模块中的核心工具类,提供了丰富的类操作功能,可以大大简化Java反射相关的开发工作。通过ClassUtil,开发者可以方便地获取类信息、扫描类、判断类型、加载类和遍历类层次,提高开发效率和代码质量。
在使用ClassUtil时,需要注意类扫描性能、类加载安全和类路径编码等问题,遵循最佳实践可以提高代码的性能和可靠性。