ClassUtils
ClassUtils
CGLIB_CLASS_SEPARATOR = "$$";
#public static ClassLoader getDefaultClassLoader() 获取默认ClassLoader,获取结果通常是AppClassLoader。优先级:Thread.currentThread().getContextClassLoader(); -> ClassUtils.class.getClassLoader(); -> ClassLoader.getSystemClassLoader();
#public static ClassLoader overrideThreadContextClassLoader(@Nullable ClassLoader classLoaderToUse) 覆盖当前线程的ClassLoader,并返回覆盖前的ClassLoader,若无需覆盖(classLoaderToUse是null或新旧eq)则返回null
#public static Class<?> forName(String name, @Nullable ClassLoader classLoader) Class.forName的加强,允许name是java基本类型如int -> int.class,允许name的入参是数组形式,例如org.springframework.tests.sample.objects.TestObject[] -> TestObject[].class
##使用resolvePrimitiveClassName获取基本类型class,是null再从缓存中获取,若命中则返回
##若name以[]结尾(说明是数组形式),则截取到[]之前部分,再递归使用本方法取得class,使用Array.newInstance(elementClass, 0).getClass();响应数组[]形式的class
##若name以 [L 开头以 ; 结尾(说明是数组形式),如[Ljava.lang.String; ,则截取[L和;之间部分,再递归使用本方法取得class,使用Array.newInstance(elementClass, 0).getClass();响应数组[]形式的class
##若name以[开头(针对[[I 或 [[Ljava.lang.String; 形式的二维数组),则截取[之后部分,再递归使用本方法处理
##若以上都不符,则使用Class.forName(name, false, clToUse); ,若catch到ClassNotFoundException,尝试将最后的.号换成$后再一次Class.forName(name, false, clToUse); (为了应对可能是.号方式的内部类 如org.springframework.util.ClassUtilsTests.NestedClass),若还是没有则把ClassNotFoundException抛出
#public static Class<?> resolveClassName(String className, @Nullable ClassLoader classLoader) 委托使用forName并将异常包装为IllegalArgumentException
#public static boolean isPresent(String className, @Nullable ClassLoader classLoader) 委托使用forName检查类是否存在,不会抛出异常
#public static boolean isVisible(Class<?> clazz, @Nullable ClassLoader classLoader) 检查类对给定的ClassLoader是否可见。若classLoader是null->true;若clazz.getClassLoader() == classLoader -> true;最后使用isLoadable
#public static boolean isCacheSafe(Class<?> clazz, @Nullable ClassLoader classLoader) 检查clazz是由给定的类加载器加载还是由它的父类加载。参数classLoader可能为null,此时表示BootstrapClassLoader
##若clazz.getClassLoader() == classLoader 或 clazz.getClassLoader()是null(是null则说明该clazz是由BootstrapClassLoader加载的,如rt.jar下的String.class,BootstrapClassLoader是其他类加载器的父加载器) -> true
##若classLoader ==null -> false
##若clazz是由classLoader 加载或classLoader的parent加载的 -> true ; 否则false
#public static Class<?> resolvePrimitiveClassName(@Nullable String name) 根据name参数返回原始类型(基本类型),若name不属于基本类型则返回null
boolean -> boolean.class
byte -> byte.class
char->char.class
double -> double.class
float->float.class
int->int.class
long->long.class
short->short.class
void->void.class
{void=void, double=double, byte=byte, [B=class [B, [C=class [C, [D=class [D, [F=class [F, float=float, int=int, long=long, [I=class [I, [J=class [J, boolean=boolean, [S=class [S, char=char, short=short, [Z=class [Z}
#private static boolean isLoadable(Class<?> clazz, ClassLoader classLoader) 若clazz == classLoader.loadClass(clazz.getName()) -> true(说明classLoader可以加载该clazz并且加载后的class是同一个,因为JVM规范同一个classLoader加载同一个类,只会存在一个class);否则false
#public static boolean isPrimitiveWrapper(Class<?> clazz) 检查clazz是否包装类型 Boolean.class, Character.class, Byte.class, Short.class,Integer.class, Long.class, Float.class, Double.class, Void.class
#public static boolean isPrimitiveOrWrapper(Class<?> clazz) 检查clazz是否基本类型或包装类型 boolean, byte,char, short, int, long, float, double, void 以及 Boolean, Byte, Character, Short, Integer, Long, Float, Double, Void
#public static boolean isPrimitiveArray(Class<?> clazz) 检查clazz是否基本类型的数组
#public static boolean isPrimitiveWrapperArray(Class<?> clazz) 检查clazz是否包装类型的数组
#public static Class<?> resolvePrimitiveIfNecessary(Class<?> clazz) 获取类型的包装类型 int.class -> Integer.class, Integer.class -> Integer.class, 自定义.class -> 自定义.class
#public static boolean isAssignable(Class<?> lhsType, Class<?> rhsType) 检查左边是否对右边isAssignable。若lhsType.isAssignableFrom(rhsType) -> true;若左边是基本类型,则获取右边的基本类型进行==匹配;#否则获取右边的包装类型执行isAssignableFrom
#public static boolean isAssignableValue(Class<?> type, @Nullable Object value) 检查type是否isAssignable value的类型
#public static String convertResourcePathToClassName(String resourcePath) 把resourcePath中的路径分割符/ 替换成 包分隔符.
#public static String convertClassNameToResourcePath(String className) 把className中的包分隔符. 替换成 路径分割符/
#public static String addResourcePathToPackagePath(Class<?> clazz, String resourceName) 给resourceName追加clazz的package名作为前缀。例如clazz=java.lang.reflect.Proxy resourceName=xyzabc.xml -> java/lang/reflect/xyzabc.xml
#public static String classPackageAsResourcePath(@Nullable Class<?> clazz) 获取clazz的package名并以 / 分割
#public static String classNamesToString(Class<?>... classes) 对classes以数组方式toString,如ArrayList.class,Integer.class -> [java.util.ArrayList, java.lang.Integer]
#public static String classNamesToString(@Nullable Collection<Class<?>> classes) 同上
#public static Class<?>[] toClassArray(@Nullable Collection<Class<?>> collection) class集合转数组
#public static Class<?>[] getAllInterfaces(Object instance) 最终使用getAllInterfacesForClassAsSet获取所有接口
#public static Class<?>[] getAllInterfacesForClass(Class<?> clazz) 最终使用getAllInterfacesForClassAsSet获取所有接口
#public static Class<?>[] getAllInterfacesForClass(Class<?> clazz, @Nullable ClassLoader classLoader) 最终使用getAllInterfacesForClassAsSet获取所有接口
#public static Set<Class<?>> getAllInterfacesAsSet(Object instance) 最终使用getAllInterfacesForClassAsSet获取所有接口
#public static Set<Class<?>> getAllInterfacesForClassAsSet(Class<?> clazz) 最终使用getAllInterfacesForClassAsSet获取所有接口
#public static Set<Class<?>> getAllInterfacesForClassAsSet(Class<?> clazz, @Nullable ClassLoader classLoader) 获取对classLoader(classLoader为null时始终可访问)可访问的 clazz的所有Interface,可以获取到父类的Interfaces
#public static Class<?> createCompositeInterface(Class<?>[] interfaces, @Nullable ClassLoader classLoader) 把interfaces组合起来产生一个新的代理接口,在JDK9过时
#public static Class<?> determineCommonAncestor(@Nullable Class<?> clazz1, @Nullable Class<?> clazz2) 获取2个类的共同父类。例如 Integer和 Float ->Number,Runnable和List -> null
#public static boolean isJavaLanguageInterface(Class<?> ifc) 是否java语言的接口:Serializable.class, Externalizable.class,Closeable.class, AutoCloseable.class, Cloneable.class, Comparable.class
#public static boolean isInnerClass(Class<?> clazz) 检查是否是内部类,要求不是static class; return (clazz.isMemberClass() && !Modifier.isStatic(clazz.getModifiers()));
#public static Class<?> getUserClass(Object instance) 委托getUserClass
#public static Class<?> getUserClass(Class<?> clazz) 获取用户定义的类。
##若clazz含$$(CGLIB),则若其 superclass != null && superclass != Object.class 即return superclass;
##否则return clazz;
#public static String getDescriptiveType(@Nullable Object value) 获取实例对应的类描述。若value==null ,return null; 若value的class是代理类 -> clazz.getName() + "implementing"+","实现了哪些接口的名称(,号间隔);否则return clazz.getTypeName();
#public static boolean matchesTypeName(Class<?> clazz, @Nullable String typeName) typeName.equals(clazz.getTypeName()) || typeName.equals(clazz.getSimpleName()) 认为是匹配
#public static String getShortName(String className) 获取类的短名称。普通类:**.ClassUtilsTests -> ClassUtilsTests ; 内部类的名称: **.ClassUtilsTests$User -> ClassUtilsTests.User ; cglib的代理类:**.ClassUtilsTests$$User -> ClassUtilsTests 以父类呈现
#public static String getShortName(Class<?> clazz) 委托getShortName(String className)
#public static String getShortNameAsProperty(Class<?> clazz) 以属性名称方式返回短名称。getShortName后(若结果中包含.号,再截取.号之后部分),把首字母小写
#public static String getClassFileName(Class<?> clazz) 获取类的短名称+.class。java.lang.String -> String.class
#public static String getPackageName(Class<?> clazz) 委托getPackageName(String fqClassName)
#public static String getPackageName(String fqClassName) 获取clazz的包名,若fqClassName不包含.号返回空字符串
#public static String getQualifiedName(Class<?> clazz) 获取完整类名 return clazz.getTypeName(); 数组class -> org.springframework.util.ClassUtilsTests[]
#public static String getQualifiedMethodName(Method method) 委托getQualifiedMethodName(Method method, @Nullable Class<?> clazz)
#public static String getQualifiedMethodName(Method method, @Nullable Class<?> clazz) 获取完整 类名.方法。例如org.springframework.util.ClassUtilsTests.getQualifiedName
#public static boolean hasConstructor(Class<?> clazz, Class<?>... paramTypes) 是否有对应的构造方法。委托getConstructorIfAvailable(Class<T> clazz, Class<?>... paramTypes)
@Nullable
#public static <T> Constructor<T> getConstructorIfAvailable(Class<T> clazz, Class<?>... paramTypes) 获取对应的构造方法。不存在则catch并return null
#public static boolean hasMethod(Class<?> clazz, Method method) 检查clazz是否有 public 的这样的method。若method的class是入参的clazz -> true ; 尝试用method的methodName+paramTypes来获取clazz有没有这样的方法。
#public static boolean hasMethod(Class<?> clazz, String methodName, Class<?>... paramTypes) 委托getMethodIfAvailable(Class<?> clazz, String methodName, @Nullable Class<?>... paramTypes)
#public static Method getMethod(Class<?> clazz, String methodName, @Nullable Class<?>... paramTypes) 获取对应的 public 的方法,没有则IllegalStateException。
##若paramTypes!=null,按clazz.getMethod(methodName, paramTypes);处理 。表示该入参的场景目的是精确去匹配
##否则找出所有的public的methodName,若只有1个则匹配该method,否则IllegalStateException,表示不存在或无法唯一匹配到
@Nullable
#public static Method getMethodIfAvailable(Class<?> clazz, String methodName, @Nullable Class<?>... paramTypes) 以尝试的方式获取对应的 public 的方法。若paramTypes != null,按clazz.getMethod(methodName, paramTypes); 精确匹配;否则找出所有的public的methodName,若只有1个则匹配该method
#public static int getMethodCountForName(Class<?> clazz, String methodName) 统计所有方法名是methodName的个数(包括非public),递归包括父类、接口
#public static boolean hasAtLeastOneMethodWithName(Class<?> clazz, String methodName) 是否有方法名是methodName的方法(包括非public),递归包括父类、接口
#public static Method getMostSpecificMethod(Method method, @Nullable Class<?> targetClass) 获取method的具体实现方法,可能是method本身或targetClass中的方法。与AopUtils.getMostSpecificMethod(java.lang.reflect.Method,java.lang.Class<?>)相反,此方法不会自动解析java 5桥接方法。如果需要桥接方法解析(例如从原始方法定义获取元数据),则调用BridgeMethodResolver.findBridgedMethod(java.lang.reflect.Method)。
##若 targetClass != null && targetClass != method.getDeclaringClass() && isOverridable(method, targetClass)
##若method是public,尝试return targetClass.getMethod(method.getName(), method.getParameterTypes()); ,不存在则return method;
##否则 以父类递归方式在targetClass中查找与method同名同参的方法,不存在则return method;
##否则return method; 即情况可能是 targetClass是null 或 method的class与targetClass相同 或 method不允许重写
#public static Method getInterfaceMethodIfPossible(Method method) 查找method对应的接口方法(method的接口定义),如果找不到,则为method本身。
##若method不是public(表明不是实现接口的,属于找不到)或method的class是接口,return method;
##以method为key查询缓存,未命中 -> 递归在所有的接口中以method的名称和参数类型查找方法定义,如果找不到,则为method本身。
#public static boolean isUserLevelMethod(Method method) 检查方法是否可视为用户声明的。method.isBridge() || (!method.isSynthetic() && !isGroovyObjectMethod(method)) 桥接方法虽然是生成的,但本质上是用于定义而来的
#private static boolean isGroovyObjectMethod(Method method) return method.getDeclaringClass().getName().equals("groovy.lang.GroovyObject");
#private static boolean isOverridable(Method method, @Nullable Class<?> targetClass) 检查method是否可以被重写。若是private -> 不可以;若是public或protected -> 可以;无修饰则检查method和targetClass所在的package是否一致
@Nullable
#public static Method getStaticMethod(Class<?> clazz, String methodName, Class<?>... args) 根据methodName、参数类型args 返回public static的方法。
@Nullable
#private static Method getMethodOrNull(Class<?> clazz, String methodName, Class<?>[] paramTypes) 尝试性的,不存在则null
#private static Set<Method> findMethodCandidatesByName(Class<?> clazz, String methodName) 所有名称是methodName的 public 方法