前言
接着上一篇
【小家Spring】Spring Framework提供的实用纯Java工具类大合集(一)
继续来介绍Spring提供的好用的一些工具类。
Assert
这是Spring提供给我们的断言工具,是以抛异常的方式来处理的。
若你是自己的书写框架的时候,可以使用它的,而不用自己各种去if判空了
public static void main(String[] args) { Integer param = 1; Assert.state(param == 2, "param的值不为2,请校对~"); //Assert.hasText(); //Assert.hasLength(); //Assert.notNull(); //Assert.notEmpty(); //... } // 输出 Exception in thread "main" java.lang.IllegalStateException: param的值不为2,请校对~
ClassUtils:非常非常重要的一个工具类
这是关于类级别相关的工具类,虽然只是提供给Spring框架内部使用,但是很多方法还是有一定使用价值,并且理解这些方法的实现,也是有一定价值的
该工具类在Spring框架中可谓使用非常广泛
首先ClassUtils是一个非常大的工具类,提供了很多缓存数据和初始化内容
public abstract class ClassUtils { // 这些常量 挺重要的 都是public的 我们也可以使用 这些都遵循了Java的命名规范 public static final String ARRAY_SUFFIX = "[]"; private static final String INTERNAL_ARRAY_PREFIX = "["; // 这个非常有意思:如果你是八大基本类型(PRIMITIVE类型)的数组类型, toString()方法是"[A"/"[B"...等等 // 但是如果你是new Person[0]或者new Object[0]这种数组类型,全都是"[L"打头得,这个非常有规律性 private static final String NON_PRIMITIVE_ARRAY_PREFIX = "[L"; private static final char PACKAGE_SEPARATOR = '.'; private static final char PATH_SEPARATOR = '/'; // 是否是内部类 private static final char INNER_CLASS_SEPARATOR = '$'; // 这个符号,用来判断是否是CGLIB的代理类 public static final String CGLIB_CLASS_SEPARATOR = "$$"; public static final String CLASS_FILE_SUFFIX = ".class"; // 下面这个很重要,提高效率必备---缓存 他们都是private的 // 缓存八大基本数据类型 --> 包装类型的映射 所有长度相同 private static final Map<Class<?>, Class<?>> primitiveWrapperTypeMap = new IdentityHashMap<>(8); // 和上面区别:上面的key是这里的value private static final Map<Class<?>, Class<?>> primitiveTypeToWrapperMap = new IdentityHashMap<>(8); // 保存所遇的基础数据类型 8 + 8(对应数组类型) + void.class 一共会有17个元素 private static final Map<String, Class<?>> primitiveTypeNameMap = new HashMap<>(32); // 顾名思义:它是缓存一些常用的Class类型。key为class.getName() value为Class本身 // 比如:上面所列的17个、 还有包装类型的数组(8个) + Number.class/Class.class... + Enum.class/Exception.class/ List.clss... 总之就是缓存比较常用的一些类型吧 private static final Map<String, Class<?>> commonClassCache = new HashMap<>(64); // 缓存Java语言的一些常用接口: //Serializable.class, Externalizable.class, Closeable.class, AutoCloseable.class, Cloneable.class, Comparable.class private static final Set<Class<?>> javaLanguageInterfaces; // 这个方法非常常用:按照获取当前线程上下文类加载器-->获取当前类类加载器-->获取系统启动类加载器的顺序来获取 @Nullable public static ClassLoader getDefaultClassLoader() { ClassLoader cl = null; try { cl = Thread.currentThread().getContextClassLoader(); } catch (Throwable ex) { // Cannot access thread context ClassLoader - falling back... } if (cl == null) { // No thread context class loader -> use class loader of this class. cl = ClassUtils.class.getClassLoader(); if (cl == null) { // getClassLoader() returning null indicates the bootstrap ClassLoader try { cl = ClassLoader.getSystemClassLoader(); } catch (Throwable ex) { // Cannot access system ClassLoader - oh well, maybe the caller can live with null... } } } return cl; } //这个方法较为简单,使用传入的classloader替换线程的classloader;使用场景,比如一个线程的classloader和spring的classloader不一致的时候,就可以使用这个方法替换 @Nullable public static ClassLoader overrideThreadContextClassLoader(@Nullable ClassLoader classLoaderToUse) { Thread currentThread = Thread.currentThread(); ClassLoader threadContextClassLoader = currentThread.getContextClassLoader(); if (classLoaderToUse != null && !classLoaderToUse.equals(threadContextClassLoader)) { currentThread.setContextClassLoader(classLoaderToUse); return threadContextClassLoader; } else { return null; } } // 看名字就知道,是Class.forName的一个增强版本;通过指定的classloader加载对应的类;除了能正常加载普通的类型,``还能加载简单类型,数组,或者内部类`` // 数组是通过Array.newInstance创建出来的,然后.getClass() public static Class<?> forName(String name, @Nullable ClassLoader classLoader){ ... } }
看下测试代码:
//可以看到,简单类型int,数组String[]和内部类(内部类通过父类.子类的方式即可获取) public static void main(String[] args) throws ClassNotFoundException { ClassLoader defaultClassLoader = ClassUtils.getDefaultClassLoader(); // 加载基本数据类型int都可议 System.out.println(ClassUtils.forName("int", defaultClassLoader)); // int System.out.println(ClassUtils.forName("java.lang.String[]", defaultClassLoader)); //class [Ljava.lang.String; System.out.println(ClassUtils.forName("java.lang.Thread.State", defaultClassLoader)); //class java.lang.Thread$State } //和forName方法相同,内部就是直接调用的forName方法,只是抛出的异常不一样而已; public static Class<?> resolveClassName(String className, @Nullable ClassLoader classLoader){ ... } // 这个在Spring里也有大量的应用:判断某个是否存在 内部依赖于forName()方法 下面写个Demo public static boolean isPresent(String className, @Nullable ClassLoader classLoader) { ... } // 专门处理基本类型 效率非常的高 public static Class<?> resolvePrimitiveClassName(String name) { Class<?> result = null; // 简单类型,最长值不要超过8,如果超过8,反而可以忽略了 if (name != null && name.length() <= 8) { // Could be a primitive - likely. result = primitiveTypeNameMap.get(name); } return result; //判断一个类型是否在指定类加载器中可见 它在下面方法`getAllInterfacesForClassAsSet`会有用到 boolean isVisible(Class<?> clazz, ClassLoader classLoader) }
给个Demo如下:
public static void main(String[] args) throws ClassNotFoundException { ClassLoader defaultClassLoader = ClassUtils.getDefaultClassLoader(); System.out.println(ClassUtils.isPresent("java.lang.String", defaultClassLoader)); //true System.out.println(ClassUtils.isPresent("java.lang.xxx", defaultClassLoader)); //false System.out.println(ClassUtils.resolvePrimitiveClassName("int")); //int System.out.println(ClassUtils.resolvePrimitiveClassName("aaa")); //null 如果不存在,就返回null // 这里以defaultClassLoader为例 System.out.println(ClassUtils.isVisible(String.class, defaultClassLoader)); // true }
//判定一个类是否是简单类型的包装类; boolean isPrimitiveWrapper(Class<?> clazz); // 基本类型或者包装类型 boolean isPrimitiveOrWrapper(Class<?> clazz) // 基本类型的数组类型 public static boolean isPrimitiveArray(Class<?> clazz); // 基本类型的包装类型的数组类型 public static boolean isPrimitiveWrapperArray(Class<?> clazz); //如果传入的类型是一个简单类型,返回这个简单类型的包装类型 public static Class<?> resolvePrimitiveIfNecessary(Class<?> clazz);
demo演示:
public static void main(String[] args) throws ClassNotFoundException { System.out.println(ClassUtils.isPrimitiveWrapper(Integer.class)); //true System.out.println(ClassUtils.isPrimitiveWrapper(int.class)); //false System.out.println(ClassUtils.isPrimitiveOrWrapper(int.class)); //true System.out.println(ClassUtils.isPrimitiveArray(Integer[].class)); //false System.out.println(ClassUtils.isPrimitiveArray(int[].class)); // true System.out.println(ClassUtils.isPrimitiveWrapperArray(int[].class)); //false // 传进去事包装类型 最终返回的是基本类型 Class<?> clazz = ClassUtils.resolvePrimitiveIfNecessary(Integer[].class); System.out.println(clazz); //class [Ljava.lang.Integer; System.out.println(Integer[].class); //class [Ljava.lang.Integer; System.out.println(clazz == Integer[].class); //true }
public static boolean isAssignable(Class<?> lhsType, Class<?> rhsType) { ... } public static boolean isAssignableValue(Class<?> type, @Nullable Object value) { ... }
demo演示:
public static void main(String[] args) { System.out.println(Object.class.isAssignableFrom(Integer.class)); // true System.out.println(Object.class.isAssignableFrom(int.class)); // false 请注意这里返回的是false // 但是下面这么弄 就都返回true了 System.out.println(ClassUtils.isAssignable(Object.class, Integer.class)); //true System.out.println(ClassUtils.isAssignable(Object.class, int.class)); // true // 有个更简便的方式 对象参与比较 Integer i = 0; System.out.println(ClassUtils.isAssignableValue(Object.class, i)); //true }
public static String convertResourcePathToClassName(String resourcePath) {} public static String convertClassNameToResourcePath(String className) {} //在指定类的所属包下面,寻找一个资源文件,并返回该资源文件的文件路径 public static String addResourcePathToPackagePath(Class<?> clazz, String resourceName) {} public static String classPackageAsResourcePath(@Nullable Class<?> clazz) {} public static String classNamesToString(Class<?>... classes) {} public static String classNamesToString(@Nullable Collection<Class<?>> classes) {}