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 方法

 

posted on 2021-10-09 14:06  icodegarden  阅读(250)  评论(0编辑  收藏  举报