package com.rambo.tools; import java.beans.Introspector; import java.lang.reflect.Array; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.net.URL; import java.util.Collections; import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; import static com.rambo.tools.ArrayUtil.isArraySameLength; import static com.rambo.tools.ArrayUtil.isEmptyArray; import static com.rambo.tools.BasicConstant.EMPTY_CLASS_ARRAY; import static com.rambo.tools.BasicConstant.EMPTY_STRING; import static com.rambo.tools.CollectionUtil.createHashMap; import static com.rambo.tools.CollectionUtil.createHashSet; /** * 有关 <code>Class</code> 处理的工具类。 * <p> * 这个类中的每个方法都可以“安全”地处理 <code>null</code> ,而不会抛出 * <code>NullPointerException</code>。 * </p> * */ public class ClassUtil { /** Suffix for array class names: "[]" */ public static final String ARRAY_SUFFIX = "[]"; /** The package separator character '.' */ private static final char PACKAGE_SEPARATOR = '.'; /** The inner class separator character '$' */ private static final char INNER_CLASS_SEPARATOR = '$'; /** The CGLIB class separator character "$$" */ public static final String CGLIB_CLASS_SEPARATOR = "$$"; /** The ".class" file suffix */ public static final String CLASS_FILE_SUFFIX = ".class"; /** * 从接口端计算深度 * param pInterface * param targetClass * return */ public static int checkInterfaceDeepth(Class<?> pInterface, Class<?> targetClass) { if (targetClass.isAssignableFrom(pInterface)) return 0; int min = -1; for (Class<?> c : targetClass.getInterfaces()) { if (pInterface.isAssignableFrom(c)) { int i = checkInterfaceDeepth(pInterface, c) + 1; if (min == -1 || min > i) { min = i; } } } return min; } /** * param supperClass * param targetClass * return */ public static int checkSupperClassDeepth(Class<?> supperClass, Class<?> targetClass) { if (!supperClass.isAssignableFrom(targetClass)) { return -1; } if (targetClass.isAssignableFrom(supperClass)) return 0; int supperDeepth = checkSupperClassDeepth(supperClass, targetClass.getSuperclass()) + 1; int interfaceDeepth = checkInterfaceDeepth(supperClass, targetClass.getSuperclass()) + 1; if (supperDeepth < interfaceDeepth) return supperDeepth; return interfaceDeepth; } /** * 采取驼峰规则 * * param simpleName * return */ public static <T> String humpString(Class<T> clazz) { String simpleName = clazz.getSimpleName(); String first = simpleName.charAt(0) + ""; return first.toLowerCase() + simpleName.substring(1); } // ========================================================================== // 取得友好类名和package名的方法。 // ========================================================================== /** * 取得对象所属的类的友好类名。 * <p> * 类似<code>object.getClass().getName()</code>,但不同的是,该方法用更友好的方式显示数组类型。 例如: * </p> * <p/> * <pre> * int[].class.getName() = "[I" * ClassUtil.getFriendlyClassName(int[].class) = "int[]" * * Integer[][].class.getName() = "[[Ljava.lang.Integer;" * ClassUtil.getFriendlyClassName(Integer[][].class) = "java.lang.Integer[][]" * </pre> * <p> * 对于非数组的类型,该方法等效于 <code>Class.getName()</code> 方法。 * </p> * <p> * 注意,该方法所返回的数组类名只能用于显示给人看,不能用于 <code>Class.forName</code> 操作。 * </p> * * param object 要显示类名的对象 * return 用于显示的友好类名,如果对象为空,则返回<code>null</code> */ public static String getFriendlyClassNameForObject(Object object) { if (object == null) { return null; } String javaClassName = object.getClass().getName(); return toFriendlyClassName(javaClassName, true, javaClassName); } /** * 取得友好的类名。 * <p> * 类似<code>clazz.getName()</code>,但不同的是,该方法用更友好的方式显示数组类型。 例如: * </p> * <p/> * <pre> * int[].class.getName() = "[I" * ClassUtil.getFriendlyClassName(int[].class) = "int[]" * * Integer[][].class.getName() = "[[Ljava.lang.Integer;" * ClassUtil.getFriendlyClassName(Integer[][].class) = "java.lang.Integer[][]" * </pre> * <p> * 对于非数组的类型,该方法等效于 <code>Class.getName()</code> 方法。 * </p> * <p> * 注意,该方法所返回的数组类名只能用于显示给人看,不能用于 <code>Class.forName</code> 操作。 * </p> * * param object 要显示类名的对象 * return 用于显示的友好类名,如果类对象为空,则返回<code>null</code> */ public static String getFriendlyClassName(Class<?> clazz) { if (clazz == null) { return null; } String javaClassName = clazz.getName(); return toFriendlyClassName(javaClassName, true, javaClassName); } /** * 取得友好的类名。 * <p> * <code>className</code> 必须是从 <code>clazz.getName()</code> * 所返回的合法类名。该方法用更友好的方式显示数组类型。 例如: * </p> * <p/> * <pre> * int[].class.getName() = "[I" * ClassUtil.getFriendlyClassName(int[].class) = "int[]" * * Integer[][].class.getName() = "[[Ljava.lang.Integer;" * ClassUtil.getFriendlyClassName(Integer[][].class) = "java.lang.Integer[][]" * </pre> * <p> * 对于非数组的类型,该方法等效于 <code>Class.getName()</code> 方法。 * </p> * <p> * 注意,该方法所返回的数组类名只能用于显示给人看,不能用于 <code>Class.forName</code> 操作。 * </p> * * param javaClassName 要转换的类名 * return 用于显示的友好类名,如果原类名为空,则返回 <code>null</code> ,如果原类名是非法的,则返回原类名 */ public static String getFriendlyClassName(String javaClassName) { return toFriendlyClassName(javaClassName, true, javaClassName); } /** * 将Java类名转换成友好类名。 * * param javaClassName Java类名 * param processInnerClass 是否将内联类分隔符 <code>'$'</code> 转换成 <code>'.'</code> * return 友好的类名。如果参数非法或空,则返回<code>null</code>。 */ private static String toFriendlyClassName(String javaClassName, boolean processInnerClass, String defaultIfInvalid) { String name = StringUtil.trimToNull(javaClassName); if (name == null) { return defaultIfInvalid; } if (processInnerClass) { name = name.replace('$', '.'); } int length = name.length(); int dimension = 0; // 取得数组的维数,如果不是数组,维数为0 for (int i = 0; i < length; i++, dimension++) { if (name.charAt(i) != '[') { break; } } // 如果不是数组,则直接返回 if (dimension == 0) { return name; } // 确保类名合法 if (length <= dimension) { return defaultIfInvalid; // 非法类名 } // 处理数组 StringBuilder componentTypeName = new StringBuilder(); switch (name.charAt(dimension)) { case 'Z': componentTypeName.append("boolean"); break; case 'B': componentTypeName.append("byte"); break; case 'C': componentTypeName.append("char"); break; case 'D': componentTypeName.append("double"); break; case 'F': componentTypeName.append("float"); break; case 'I': componentTypeName.append("int"); break; case 'J': componentTypeName.append("long"); break; case 'S': componentTypeName.append("short"); break; case 'L': if (name.charAt(length - 1) != ';' || length <= dimension + 2) { return defaultIfInvalid; // 非法类名 } componentTypeName.append(name.substring(dimension + 1, length - 1)); break; default: return defaultIfInvalid; // 非法类名 } for (int i = 0; i < dimension; i++) { componentTypeName.append("[]"); } return componentTypeName.toString(); } /** * 取得指定对象所属的类的简单类名,不包括package名。 * <p> * 此方法可以正确显示数组和内联类的名称。 例如: * <p/> * <pre> * ClassUtil.getSimpleClassNameForObject(Boolean.TRUE) = "Boolean" * ClassUtil.getSimpleClassNameForObject(new Boolean[10]) = "Boolean[]" * ClassUtil.getSimpleClassNameForObject(new int[1][2]) = "int[][]" * </pre> * <p> * 本方法和<code>Class.getSimpleName()</code>的区别在于,本方法会保留inner类的外层类名称。 * </p> * * param object 要查看的对象 * return 简单类名,如果对象为 <code>null</code> ,则返回 <code>null</code> */ public static String getSimpleClassNameForObject(Object object) { if (object == null) { return null; } return getSimpleClassName(object.getClass().getName()); } /** * 取得指定对象所属的类的简单类名,不包括package名。 * <p> * 此方法可以正确显示数组和内联类的名称。 例如: * <p/> * <pre> * ClassUtil.getSimpleClassNameForObject(Boolean.TRUE) = "Boolean" * ClassUtil.getSimpleClassNameForObject(new Boolean[10]) = "Boolean[]" * ClassUtil.getSimpleClassNameForObject(new int[1][2]) = "int[][]" * </pre> * <p> * 本方法和<code>Class.getSimpleName()</code>的区别在于,本方法会保留inner类的外层类名称。 * </p> * * param object 要查看的对象 * return 简单类名,如果对象为 <code>null</code> ,则返回 <code>null</code> */ public static String getSimpleClassNameForObject(Object object, boolean processInnerClass) { if (object == null) { return null; } return getSimpleClassName(object.getClass().getName(), processInnerClass); } /** * 取得简单类名,不包括package名。 * <p> * 此方法可以正确显示数组和内联类的名称。 例如: * <p/> * <pre> * ClassUtil.getSimpleClassName(Boolean.class) = "Boolean" * ClassUtil.getSimpleClassName(Boolean[].class) = "Boolean[]" * ClassUtil.getSimpleClassName(int[][].class) = "int[][]" * ClassUtil.getSimpleClassName(Map.Entry.class) = "Map.Entry" * </pre> * <p> * 本方法和<code>Class.getSimpleName()</code>的区别在于,本方法会保留inner类的外层类名称。 * </p> * * param clazz 要查看的类 * return 简单类名,如果类为 <code>null</code> ,则返回 <code>null</code> */ public static String getSimpleClassName(Class<?> clazz) { if (clazz == null) { return null; } return getSimpleClassName(clazz.getName()); } /** * 取得简单类名,不包括package名。 * <p> * 此方法可以正确显示数组和内联类的名称。 例如: * <p/> * <pre> * ClassUtil.getSimpleClassName(Boolean.class) = "Boolean" * ClassUtil.getSimpleClassName(Boolean[].class) = "Boolean[]" * ClassUtil.getSimpleClassName(int[][].class) = "int[][]" * ClassUtil.getSimpleClassName(Map.Entry.class) = "Map.Entry" * </pre> * <p> * 本方法和<code>Class.getSimpleName()</code>的区别在于,本方法会保留inner类的外层类名称。 * </p> * * param clazz 要查看的类 * return 简单类名,如果类为 <code>null</code> ,则返回 <code>null</code> */ public static String getSimpleClassName(Class<?> clazz, boolean proccessInnerClass) { if (clazz == null) { return null; } return getSimpleClassName(clazz.getName(), proccessInnerClass); } /** * 取得类名,不包括package名。 * <p> * 此方法可以正确显示数组和内联类的名称。 例如: * <p/> * <pre> * ClassUtil.getSimpleClassName(Boolean.class.getName()) = "Boolean" * ClassUtil.getSimpleClassName(Boolean[].class.getName()) = "Boolean[]" * ClassUtil.getSimpleClassName(int[][].class.getName()) = "int[][]" * ClassUtil.getSimpleClassName(Map.Entry.class.getName()) = "Map.Entry" * </pre> * <p> * 本方法和<code>Class.getSimpleName()</code>的区别在于,本方法会保留inner类的外层类名称。 * </p> * * param javaClassName 要查看的类名 * return 简单类名,如果类名为空,则返回 <code>null</code> */ public static String getSimpleClassName(String javaClassName) { return getSimpleClassName(javaClassName, true); } /** * 取得类名,不包括package名。 * <p> * 此方法可以正确显示数组和内联类的名称。 例如: * <p/> * <pre> * ClassUtil.getSimpleClassName(Boolean.class.getName()) = "Boolean" * ClassUtil.getSimpleClassName(Boolean[].class.getName()) = "Boolean[]" * ClassUtil.getSimpleClassName(int[][].class.getName()) = "int[][]" * ClassUtil.getSimpleClassName(Map.Entry.class.getName()) = "Map.Entry" * </pre> * <p> * 本方法和<code>Class.getSimpleName()</code>的区别在于,本方法会保留inner类的外层类名称。 * </p> * * param javaClassName 要查看的类名 * return 简单类名,如果类名为空,则返回 <code>null</code> */ public static String getSimpleClassName(String javaClassName, boolean proccesInnerClass) { String friendlyClassName = toFriendlyClassName(javaClassName, false, null); if (friendlyClassName == null) { return javaClassName; } if (proccesInnerClass) { char[] chars = friendlyClassName.toCharArray(); int beginIndex = 0; for (int i = chars.length - 1; i >= 0; i--) { if (chars[i] == '.') { beginIndex = i + 1; break; } else if (chars[i] == '$') { chars[i] = '.'; } } return new String(chars, beginIndex, chars.length - beginIndex); } else { return friendlyClassName.substring(friendlyClassName.lastIndexOf(".") + 1); } } /** 取得简洁的method描述。 */ public static String getSimpleMethodSignature(Method method) { return getSimpleMethodSignature(method, false, false, false, false); } /** 取得简洁的method描述。 */ public static String getSimpleMethodSignature(Method method, boolean withClassName) { return getSimpleMethodSignature(method, false, false, withClassName, false); } /** 取得简洁的method描述。 */ public static String getSimpleMethodSignature(Method method, boolean withModifiers, boolean withReturnType, boolean withClassName, boolean withExceptionType) { if (method == null) { return null; } StringBuilder buf = new StringBuilder(); if (withModifiers) { buf.append(Modifier.toString(method.getModifiers())).append(' '); } if (withReturnType) { buf.append(getSimpleClassName(method.getReturnType())).append(' '); } if (withClassName) { buf.append(getSimpleClassName(method.getDeclaringClass())).append('.'); } buf.append(method.getName()).append('('); Class<?>[] paramTypes = method.getParameterTypes(); for (int i = 0; i < paramTypes.length; i++) { Class<?> paramType = paramTypes[i]; buf.append(getSimpleClassName(paramType)); if (i < paramTypes.length - 1) { buf.append(", "); } } buf.append(')'); if (withExceptionType) { Class<?>[] exceptionTypes = method.getExceptionTypes(); if (!isEmptyArray(exceptionTypes)) { buf.append(" throws "); for (int i = 0; i < exceptionTypes.length; i++) { Class<?> exceptionType = exceptionTypes[i]; buf.append(getSimpleClassName(exceptionType)); if (i < exceptionTypes.length - 1) { buf.append(", "); } } } } return buf.toString(); } /** * 取得指定对象所属的类的package名。 * <p> * 对于数组,此方法返回的是数组元素类型的package名。 * </p> * * param object 要查看的对象 * return package名,如果对象为 <code>null</code> ,则返回<code>""</code> */ public static String getPackageNameForObject(Object object) { if (object == null) { return EMPTY_STRING; } return getPackageName(object.getClass().getName()); } /** * 取得指定类的package名。 * <p> * 对于数组,此方法返回的是数组元素类型的package名。 * </p> * * param clazz 要查看的类 * return package名,如果类为 <code>null</code> ,则返回<code>""</code> */ public static String getPackageName(Class<?> clazz) { if (clazz == null) { return EMPTY_STRING; } return getPackageName(clazz.getName()); } /** * 取得指定类名的package名。 * <p> * 对于数组,此方法返回的是数组元素类型的package名。 * </p> * * param javaClassName 要查看的类名 * return package名,如果类名为空,则返回 <code>null</code> */ public static String getPackageName(String javaClassName) { String friendlyClassName = toFriendlyClassName(javaClassName, false, null); if (friendlyClassName == null) { return EMPTY_STRING; } int i = friendlyClassName.lastIndexOf('.'); if (i == -1) { return EMPTY_STRING; } return friendlyClassName.substring(0, i); } // ========================================================================== // 取得类名和package名的resource名的方法。 // // 和类名、package名不同的是,resource名符合文件名命名规范,例如: // java/lang/String.class // com/alibaba/commons/lang // etc. // ========================================================================== /** * 取得对象所属的类的资源名。 * <p> * 例如: * </p> * <p/> * <pre> * ClassUtil.getResourceNameForObjectClass("This is a string") = "java/lang/String.class" * </pre> * * param object 要显示类名的对象 * return 指定对象所属类的资源名,如果对象为空,则返回<code>null</code> */ public static String getResourceNameForObjectClass(Object object) { if (object == null) { return null; } return object.getClass().getName().replace('.', '/') + ".class"; } /** * 取得指定类的资源名。 * <p> * 例如: * </p> * <p/> * <pre> * ClassUtil.getResourceNameForClass(String.class) = "java/lang/String.class" * </pre> * * param clazz 要显示类名的类 * return 指定类的资源名,如果指定类为空,则返回<code>null</code> */ public static String getResourceNameForClass(Class<?> clazz) { if (clazz == null) { return null; } return clazz.getName().replace('.', '/') + ".class"; } /** * 取得指定类的资源名。 * <p> * 例如: * </p> * <p/> * <pre> * ClassUtil.getResourceNameForClass("java.lang.String") = "java/lang/String.class" * </pre> * * param className 要显示的类名 * return 指定类名对应的资源名,如果指定类名为空,则返回<code>null</code> */ public static String getResourceNameForClass(String className) { if (className == null) { return null; } return className.replace('.', '/') + ".class"; } /** * 取得指定对象所属的类的package名的资源名。 * <p> * 对于数组,此方法返回的是数组元素类型的package名。 * </p> * * param object 要查看的对象 * return package名,如果对象为 <code>null</code> ,则返回 <code>null</code> */ public static String getResourceNameForObjectPackage(Object object) { if (object == null) { return null; } return getPackageNameForObject(object).replace('.', '/'); } /** * 取得指定类的package名的资源名。 * <p> * 对于数组,此方法返回的是数组元素类型的package名。 * </p> * * param clazz 要查看的类 * return package名,如果类为 <code>null</code> ,则返回 <code>null</code> */ public static String getResourceNameForPackage(Class<?> clazz) { if (clazz == null) { return null; } return getPackageName(clazz).replace('.', '/'); } /** * 取得指定类名的package名的资源名。 * <p> * 对于数组,此方法返回的是数组元素类型的package名。 * </p> * * param className 要查看的类名 * return package名,如果类名为空,则返回 <code>null</code> */ public static String getResourceNameForPackage(String className) { if (className == null) { return null; } return getPackageName(className).replace('.', '/'); } // ========================================================================== // 取得数组类。 // ========================================================================== /** * 取得指定一维数组类. * * param componentType 数组的基础类 * return 数组类,如果数组的基类为 <code>null</code> ,则返回 <code>null</code> */ public static Class<?> getArrayClass(Class<?> componentType) { return getArrayClass(componentType, 1); } /** * 取得指定维数的 <code>Array</code>类. * * param dimension 维数,如果小于 <code>0</code> 则看作 <code>0</code> * return 如果维数为0, 则返回基类本身, 否则返回数组类,如果数组的基类为 <code>null</code> ,则返回 * <code>null</code> */ public static Class<?> getArrayClass(Class<?> componentClass, int dimension) { if (componentClass == null) { return null; } switch (dimension) { case 1: return Array.newInstance(componentClass, 0).getClass(); case 0: return componentClass; default: return Array.newInstance(componentClass, new int[dimension]).getClass(); } } // ========================================================================== // 取得原子类型或者其wrapper类。 // ========================================================================== /** * 取得primitive类。 * <p> * 例如: * <p/> * <pre> * ClassUtil.getPrimitiveType("int") = int.class; * ClassUtil.getPrimitiveType("long") = long.class; * </pre> * <p/> * </p> */ public static Class<?> getPrimitiveType(String name) { PrimitiveInfo<?> info = PRIMITIVES.get(name); if (info != null) { return info.type; } return null; } /** * 取得primitive类。 * <p> * 例如: * <p/> * <pre> * ClassUtil.getPrimitiveType(Integer.class) = int.class; * ClassUtil.getPrimitiveType(Long.class) = long.class; * </pre> * <p/> * </p> */ public static Class<?> getPrimitiveType(Class<?> type) { return getPrimitiveType(type.getName()); } /** * 取得primitive类型的wrapper。如果不是primitive,则原样返回。 * <p> * 例如: * <p/> * <pre> * ClassUtil.getPrimitiveWrapperType(int.class) = Integer.class; * ClassUtil.getPrimitiveWrapperType(int[].class) = int[].class; * ClassUtil.getPrimitiveWrapperType(int[][].class) = int[][].class; * ClassUtil.getPrimitiveWrapperType(String[][].class) = String[][].class; * </pre> * <p/> * </p> */ @SuppressWarnings("unchecked") public static <T> Class<T> getWrapperTypeIfPrimitive(Class<T> type) { if (type.isPrimitive()) { return ((PrimitiveInfo<T>) PRIMITIVES.get(type.getName())).wrapperType; } return type; } /** * 取得primitive类型的默认值。如果不是primitive,则返回<code>null</code>。 * <p> * 例如: * <p/> * <pre> * ClassUtil.getPrimitiveDefaultValue(int.class) = 0; * ClassUtil.getPrimitiveDefaultValue(boolean.class) = false; * ClassUtil.getPrimitiveDefaultValue(char.class) = '\0'; * </pre> * <p/> * </p> */ @SuppressWarnings("unchecked") public static <T> T getPrimitiveDefaultValue(Class<T> type) { PrimitiveInfo<T> info = (PrimitiveInfo<T>) PRIMITIVES.get(type.getName()); if (info != null) { return info.defaultValue; } return null; } private static final Map<String, PrimitiveInfo<?>> PRIMITIVES = createHashMap(); static { addPrimitive(boolean.class, "Z", Boolean.class, "booleanValue", false); addPrimitive(short.class, "S", Short.class, "shortValue", (short) 0); addPrimitive(int.class, "I", Integer.class, "intValue", 0); addPrimitive(long.class, "J", Long.class, "longValue", 0L); addPrimitive(float.class, "F", Float.class, "floatValue", 0F); addPrimitive(double.class, "D", Double.class, "doubleValue", 0D); addPrimitive(char.class, "C", Character.class, "charValue", '\0'); addPrimitive(byte.class, "B", Byte.class, "byteValue", (byte) 0); addPrimitive(void.class, "V", Void.class, null, null); } private static <T> void addPrimitive(Class<T> type, String typeCode, Class<T> wrapperType, String unwrapMethod, T defaultValue) { PrimitiveInfo<T> info = new PrimitiveInfo<T>(type, typeCode, wrapperType, unwrapMethod, defaultValue); PRIMITIVES.put(type.getName(), info); PRIMITIVES.put(wrapperType.getName(), info); } /** 代表一个primitive类型的信息。 */ @SuppressWarnings("unused") private static class PrimitiveInfo<T> { final Class<T> type; final String typeCode; final Class<T> wrapperType; final String unwrapMethod; final T defaultValue; public PrimitiveInfo(Class<T> type, String typeCode, Class<T> wrapperType, String unwrapMethod, T defaultValue) { this.type = type; this.typeCode = typeCode; this.wrapperType = wrapperType; this.unwrapMethod = unwrapMethod; this.defaultValue = defaultValue; } } // ========================================================================== // 类型匹配。 // ========================================================================== /** * 检查一组指定类型 <code>fromClasses</code> 的对象是否可以赋值给另一组类型 <code>classes</code>。 * <p> * 此方法可以用来确定指定类型的参数 <code>object1, object2, ...</code> 是否可以用来调用确定参数类型为 * <code>class1, class2, * ...</code> 的方法。 * </p> * <p> * 对于 <code>fromClasses</code> 的每个元素 <code>fromClass</code> 和 * <code>classes</code> 的每个元素 <code>clazz</code>, 按照如下规则: * <ol> * <li>如果目标类 <code>clazz</code> 为 <code>null</code> ,总是返回 <code>false</code> * 。</li> * <li>如果参数类型 <code>fromClass</code> 为 <code>null</code> ,并且目标类型 * <code>clazz</code> 为非原子类型,则返回 <code>true</code>。 因为 <code>null</code> * 可以被赋给任何引用类型。</li> * <li>调用 <code>Class.isAssignableFrom</code> 方法来确定目标类 <code>clazz</code> * 是否和参数类 <code>fromClass</code> 相同或是其父类、接口,如果是,则返回 <code>true</code>。</li> * <li>如果目标类型 <code>clazz</code> 为原子类型,那么根据 <a * href="http://java.sun.com/docs/books/jls/">The Java Language * Specification</a> ,sections 5.1.1, 5.1.2, 5.1.4定义的Widening Primitive * Conversion规则,参数类型 <code>fromClass</code> 可以是任何能扩展成该目标类型的原子类型及其包装类。 例如, * <code>clazz</code> 为 <code>long</code> ,那么参数类型可以是 <code>byte</code>、 * <code>short</code>、<code>int</code>、<code>long</code>、<code>char</code> * 及其包装类 <code>java.lang.Byte</code>、<code>java.lang.Short</code>、 * <code>java.lang.Integer</code>、 <code>java.lang.Long</code> 和 * <code>java.lang.Character</code> 。如果满足这个条件,则返回 <code>true</code>。</li> * <li>不满足上述所有条件,则返回 <code>false</code>。</li> * </ol> * </p> * * param classes 目标类型列表,如果是 <code>null</code> 总是返回 <code>false</code> * param fromClasses 参数类型列表, <code>null</code> 表示可赋值给任意非原子类型 * return 如果可以被赋值,则返回 <code>true</code> */ public static boolean isAssignable(Class<?>[] classes, Class<?>[] fromClasses) { if (!isArraySameLength(fromClasses, classes)) { return false; } if (fromClasses == null) { fromClasses = EMPTY_CLASS_ARRAY; } if (classes == null) { classes = EMPTY_CLASS_ARRAY; } for (int i = 0; i < fromClasses.length; i++) { if (isAssignable(classes[i], fromClasses[i]) == false) { return false; } } return true; } /** * 检查指定类型 <code>fromClass</code> 的对象是否可以赋值给另一种类型 <code>clazz</code>。 * <p> * 此方法可以用来确定指定类型的参数 <code>object1, object2, ...</code> 是否可以用来调用确定参数类型 * <code>class1, class2, * ...</code> 的方法。 * </p> * <p> * 按照如下规则: * <ol> * <li>如果目标类 <code>clazz</code> 为 <code>null</code> ,总是返回 <code>false</code> * 。</li> * <li>如果参数类型 <code>fromClass</code> 为 <code>null</code> ,并且目标类型 * <code>clazz</code> 为非原子类型,则返回 <code>true</code>。 因为 <code>null</code> * 可以被赋给任何引用类型。</li> * <li>调用 <code>Class.isAssignableFrom</code> 方法来确定目标类 <code>clazz</code> * 是否和参数类 <code>fromClass</code> 相同或是其父类、接口,如果是,则返回 <code>true</code>。</li> * <li>如果目标类型 <code>clazz</code> 为原子类型,那么根据 <a * href="http://java.sun.com/docs/books/jls/">The Java Language * Specification</a> ,sections 5.1.1, 5.1.2, 5.1.4定义的Widening Primitive * Conversion规则,参数类型 <code>fromClass</code> 可以是任何能扩展成该目标类型的原子类型及其包装类。 例如, * <code>clazz</code> 为 <code>long</code> ,那么参数类型可以是 <code>byte</code>、 * <code>short</code>、<code>int</code>、<code>long</code>、<code>char</code> * 及其包装类 <code>java.lang.Byte</code>、<code>java.lang.Short</code>、 * <code>java.lang.Integer</code>、 <code>java.lang.Long</code> 和 * <code>java.lang.Character</code> 。如果满足这个条件,则返回 <code>true</code>。</li> * <li>不满足上述所有条件,则返回 <code>false</code>。</li> * </ol> * </p> * * param clazz 目标类型,如果是 <code>null</code> 总是返回 <code>false</code> * param fromClass 参数类型, <code>null</code> 表示可赋值给任意非原子类型 * return 如果可以被赋值,则返回 <code>null</code> */ public static boolean isAssignable(Class<?> clazz, Class<?> fromClass) { if (clazz == null) { return false; } // 如果fromClass是null,只要clazz不是原子类型如int,就一定可以赋值 if (fromClass == null) { return !clazz.isPrimitive(); } // 如果类相同或有父子关系,当然可以赋值 if (clazz.isAssignableFrom(fromClass)) { return true; } // 对于原子类型,根据JLS的规则进行扩展 // 目标class为原子类型时,fromClass可以为原子类型和原子类型的包装类型。 if (clazz.isPrimitive()) { return assignmentTable.get(clazz).contains(fromClass); } return false; } private final static Map<Class<?>, Set<Class<?>>> assignmentTable = createHashMap(); static { // boolean可以接受:boolean assignmentTable.put(boolean.class, assignableSet(boolean.class)); // byte可以接受:byte assignmentTable.put(byte.class, assignableSet(byte.class)); // char可以接受:char assignmentTable.put(char.class, assignableSet(char.class)); // short可以接受:short, byte assignmentTable.put(short.class, assignableSet(short.class, byte.class)); // int可以接受:int、byte、short、char assignmentTable.put(int.class, assignableSet(int.class, byte.class, short.class, char.class)); // long可以接受:long、int、byte、short、char assignmentTable.put(long.class, assignableSet(long.class, int.class, byte.class, short.class, char.class)); // float可以接受:float, long, int, byte, short, char assignmentTable.put(float.class, assignableSet(float.class, long.class, int.class, byte.class, short.class, char.class)); // double可以接受:double, float, long, int, byte, short, char assignmentTable.put(double.class, assignableSet(double.class, float.class, long.class, int.class, byte.class, short.class, char.class)); } private static Set<Class<?>> assignableSet(Class<?>... types) { Set<Class<?>> assignableSet = createHashSet(); for (Class<?> type : types) { assignableSet.add(getPrimitiveType(type)); assignableSet.add(getWrapperTypeIfPrimitive(type)); } return assignableSet; } // ========================================================================== // 定位class的位置。 // ========================================================================== /** 在class loader中查找class的位置。 */ public static String locateClass(Class<?> clazz) { return locateClass(clazz.getName(), clazz.getClassLoader()); } /** 在class loader中查找class的位置。 */ public static String locateClass(String className) { return locateClass(className, null); } /** 在class loader中查找class的位置。 */ public static String locateClass(String className, ClassLoader loader) { if (loader == null) { loader = Thread.currentThread().getContextClassLoader(); } String classFile = className.replace('.', '/') + ".class"; URL locationURL = loader.getResource(classFile); String location = null; if (locationURL != null) { location = locationURL.toExternalForm(); if (location.endsWith(classFile)) { location = location.substring(0, location.length() - classFile.length()); } location = location.replaceAll("^(jar|zip):|!/$", EMPTY_STRING); } return location; } /** Return the short string name of a Java class in uncapitalized JavaBeans * property format. Strips the outer class name in case of an inner class. * param clazz the class * return the short name rendered in a standard JavaBeans property format * see java.beans.Introspector#decapitalize(String) */ public static String getShortNameAsProperty(Class<?> clazz) { String shortName = ClassUtil.getShortName(clazz); int dotIndex = shortName.lastIndexOf('.'); shortName = (dotIndex != -1 ? shortName.substring(dotIndex + 1) : shortName); return Introspector.decapitalize(shortName); } /** * Get the class name without the qualified package name. * param className the className to get the short name for * return the class name of the class without the package name * throws IllegalArgumentException if the className is empty */ public static String getShortName(String className) { int lastDotIndex = className.lastIndexOf(PACKAGE_SEPARATOR); int nameEndIndex = className.indexOf(CGLIB_CLASS_SEPARATOR); if (nameEndIndex == -1) { nameEndIndex = className.length(); } String shortName = className.substring(lastDotIndex + 1, nameEndIndex); shortName = shortName.replace(INNER_CLASS_SEPARATOR, PACKAGE_SEPARATOR); return shortName; } /** * Get the class name without the qualified package name. * param clazz the class to get the short name for * return the class name of the class without the package name */ public static String getShortName(Class<?> clazz) { return getShortName(getQualifiedName(clazz)); } /** * Return the qualified name of the given class: usually simply * the class name, but component type class name + "[]" for arrays. * param clazz the class * return the qualified name of the class */ public static String getQualifiedName(Class<?> clazz) { if (clazz.isArray()) { return getQualifiedNameForArray(clazz); } else { return clazz.getName(); } } /** * Build a nice qualified name for an array: * component type class name + "[]". * param clazz the array class * return a qualified name for the array class */ private static String getQualifiedNameForArray(Class<?> clazz) { StringBuilder result = new StringBuilder(); while (clazz.isArray()) { clazz = clazz.getComponentType(); result.append(ARRAY_SUFFIX); } result.insert(0, clazz.getName()); return result.toString(); } /** * Return the qualified name of the given method, consisting of * fully qualified interface/class name + "." + method name. * param method the method * return the qualified name of the method */ public static String getQualifiedMethodName(Method method) { return method.getDeclaringClass().getName() + "." + method.getName(); } /** * Return all interfaces that the given instance implements as array, * including ones implemented by superclasses. * param instance the instance to analyze for interfaces * return all interfaces that the given instance implements as array */ public static Class[] getAllInterfaces(Object instance) { return getAllInterfacesForClass(instance.getClass()); } /** * Return all interfaces that the given class implements as array, * including ones implemented by superclasses. * <p>If the class itself is an interface, it gets returned as sole interface. * param clazz the class to analyze for interfaces * return all interfaces that the given object implements as array */ public static Class<?>[] getAllInterfacesForClass(Class<?> clazz) { return getAllInterfacesForClass(clazz, null); } /** * Return all interfaces that the given class implements as array, * including ones implemented by superclasses. * <p>If the class itself is an interface, it gets returned as sole interface. * param clazz the class to analyze for interfaces * param classLoader the ClassLoader that the interfaces need to be visible in * (may be <code>null</code> when accepting all declared interfaces) * return all interfaces that the given object implements as array */ public static Class<?>[] getAllInterfacesForClass(Class<?> clazz, ClassLoader classLoader) { Set<Class> ifcs = getAllInterfacesForClassAsSet(clazz, classLoader); return ifcs.toArray(new Class[ifcs.size()]); } /** * Return all interfaces that the given instance implements as Set, * including ones implemented by superclasses. * param instance the instance to analyze for interfaces * return all interfaces that the given instance implements as Set */ public static Set<Class> getAllInterfacesAsSet(Object instance) { return getAllInterfacesForClassAsSet(instance.getClass()); } /** * Return all interfaces that the given class implements as Set, * including ones implemented by superclasses. * <p>If the class itself is an interface, it gets returned as sole interface. * param clazz the class to analyze for interfaces * return all interfaces that the given object implements as Set */ public static Set<Class> getAllInterfacesForClassAsSet(Class clazz) { return getAllInterfacesForClassAsSet(clazz, null); } /** * Return all interfaces that the given class implements as Set, * including ones implemented by superclasses. * <p>If the class itself is an interface, it gets returned as sole interface. * param clazz the class to analyze for interfaces * param classLoader the ClassLoader that the interfaces need to be visible in * (may be <code>null</code> when accepting all declared interfaces) * return all interfaces that the given object implements as Set */ public static Set<Class> getAllInterfacesForClassAsSet(Class clazz, ClassLoader classLoader) { if (clazz.isInterface() && isVisible(clazz, classLoader)) { return Collections.singleton(clazz); } Set<Class> interfaces = new LinkedHashSet<Class>(); while (clazz != null) { Class<?>[] ifcs = clazz.getInterfaces(); for (Class<?> ifc : ifcs) { interfaces.addAll(getAllInterfacesForClassAsSet(ifc, classLoader)); } clazz = clazz.getSuperclass(); } return interfaces; } /** * Check whether the given class is visible in the given ClassLoader. * param clazz the class to check (typically an interface) * param classLoader the ClassLoader to check against (may be <code>null</code>, * in which case this method will always return <code>true</code>) */ public static boolean isVisible(Class<?> clazz, ClassLoader classLoader) { if (classLoader == null) { return true; } try { Class<?> actualClass = classLoader.loadClass(clazz.getName()); return (clazz == actualClass); // Else: different interface class found... } catch (ClassNotFoundException ex) { // No interface class found... return false; } } /** * Determine the name of the class file, relative to the containing * package: e.g. "String.class" * param clazz the class * return the file name of the ".class" file */ public static String getClassFileName(Class clazz) { String className = clazz.getName(); int lastDotIndex = className.lastIndexOf(PACKAGE_SEPARATOR); return className.substring(lastDotIndex + 1) + CLASS_FILE_SUFFIX; } /** * 判断该类型是不是包装类型 * param clazz * return */ public static boolean isBasicClass(Class<?> clazz) { boolean isPrimitive = false; try { if (clazz.isPrimitive() || clazz.isAssignableFrom(String.class)) { isPrimitive = true; } else { isPrimitive = ((Class<?>) clazz.getField("TYPE").get(null)) .isPrimitive(); } } catch (Exception e) { isPrimitive = false; } return isPrimitive; } }