Java tutorial
/* * Copyright (c) 2015 Power Group. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * * http://www.apache.org/licenses/LICENSE-2.0 * * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.power.commons.lang.util; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; import java.lang.reflect.Array; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.net.URL; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; /** * <code>Class</code> ? * <p> * ???? <code>null</code> ? * <code>NullPointerException</code> * </p> * * @author Geiger */ public class ClassUtils { // ========================================================================== // ????package?? // ========================================================================== private static final Map<String, PrimitiveInfo<?>> PRIMITIVES = new HashMap<>(); private final static Map<Class<?>, Set<Class<?>>> assignmentTable = new HashMap<>(); 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); } 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)); Assert.assertTrue(assignmentTable.size() == 8); } /** * ???? * <p> * <code>object.getClass().getName()</code>???? * </p> * <p/> * <pre> * int[].class.getName() = "[I" * ClassUtils.getFriendlyClassName(int[].class) = "int[]" * * Integer[][].class.getName() = "[[Ljava.lang.Integer;" * ClassUtils.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" * ClassUtils.getFriendlyClassName(int[].class) = "int[]" * * Integer[][].class.getName() = "[[Ljava.lang.Integer;" * ClassUtils.getFriendlyClassName(Integer[][].class) = "java.lang.Integer[][]" * </pre> * <p> * ? <code>Class.getName()</code> * </p> * <p> * ????? <code>Class.forName</code> ? * </p> * * @param clazz ??? * @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" * ClassUtils.getFriendlyClassName(int[].class) = "int[]" * * Integer[][].class.getName() = "[[Ljava.lang.Integer;" * ClassUtils.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 = StringUtils.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> * ClassUtils.getSimpleClassNameForObject(Boolean.TRUE) = "Boolean" * ClassUtils.getSimpleClassNameForObject(new Boolean[10]) = "Boolean[]" * ClassUtils.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> * ClassUtils.getSimpleClassNameForObject(Boolean.TRUE) = "Boolean" * ClassUtils.getSimpleClassNameForObject(new Boolean[10]) = "Boolean[]" * ClassUtils.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> * ClassUtils.getSimpleClassName(Boolean.class) = "Boolean" * ClassUtils.getSimpleClassName(Boolean[].class) = "Boolean[]" * ClassUtils.getSimpleClassName(int[][].class) = "int[][]" * ClassUtils.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> * ClassUtils.getSimpleClassName(Boolean.class) = "Boolean" * ClassUtils.getSimpleClassName(Boolean[].class) = "Boolean[]" * ClassUtils.getSimpleClassName(int[][].class) = "int[][]" * ClassUtils.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> * ClassUtils.getSimpleClassName(Boolean.class.getName()) = "Boolean" * ClassUtils.getSimpleClassName(Boolean[].class.getName()) = "Boolean[]" * ClassUtils.getSimpleClassName(int[][].class.getName()) = "int[][]" * ClassUtils.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> * ClassUtils.getSimpleClassName(Boolean.class.getName()) = "Boolean" * ClassUtils.getSimpleClassName(Boolean[].class.getName()) = "Boolean[]" * ClassUtils.getSimpleClassName(int[][].class.getName()) = "int[][]" * ClassUtils.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); } // ========================================================================== // ???package??resource?? // // ???package????resource??????? // java/lang/String.class // com/alibaba/commons/lang // etc. // ========================================================================== /** * ??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 (ArrayUtils.isNotEmpty(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 org.power.commons.lang.BasicConstant.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 org.power.commons.lang.BasicConstant.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 org.power.commons.lang.BasicConstant.EMPTY_STRING; } int i = friendlyClassName.lastIndexOf('.'); if (i == -1) { return org.power.commons.lang.BasicConstant.EMPTY_STRING; } return friendlyClassName.substring(0, i); } /** * ???? * <p> * * </p> * <p> * <pre> * ClassUtils.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> * ClassUtils.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> * ClassUtils.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('.', '/'); } // ========================================================================== // ??wrapper // ========================================================================== /** * ?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 componentClass * @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: Assert.assertTrue(dimension > 0, "wrong dimension: %d", dimension); return Array.newInstance(componentClass, new int[dimension]).getClass(); } } /** * ?primitive * <p> * * <p/> * <pre> * ClassUtils.getPrimitiveType("int") = int.class; * ClassUtils.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> * ClassUtils.getPrimitiveType(Integer.class) = int.class; * ClassUtils.getPrimitiveType(Long.class) = long.class; * </pre> * <p/> * </p> */ public static Class<?> getPrimitiveType(Class<?> type) { return getPrimitiveType(type.getName()); } /** * ?primitivewrapper?primitive * <p> * * <p/> * <pre> * ClassUtils.getPrimitiveWrapperType(int.class) = Integer.class; * ClassUtils.getPrimitiveWrapperType(int[].class) = int[].class; * ClassUtils.getPrimitiveWrapperType(int[][].class) = int[][].class; * ClassUtils.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> * ClassUtils.getPrimitiveDefaultValue(int.class) = 0; * ClassUtils.getPrimitiveDefaultValue(boolean.class) = false; * ClassUtils.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 <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); } /** * <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.4Widening 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 (!ArrayUtils.isSameLength(fromClasses, classes)) { return false; } if (fromClasses == null) { fromClasses = org.power.commons.lang.BasicConstant.EMPTY_CLASS_ARRAY; } if (classes == null) { classes = org.power.commons.lang.BasicConstant.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.4Widening 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; } // fromClassnull??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 static Set<Class<?>> assignableSet(Class<?>... types) { Set<Class<?>> assignableSet = new HashSet<>(); for (Class<?> type : types) { assignableSet.add(getPrimitiveType(type)); assignableSet.add(getWrapperTypeIfPrimitive(type)); } return assignableSet; } /** * class loaderclass? */ public static String locateClass(Class<?> clazz) { return locateClass(clazz.getName(), clazz.getClassLoader()); } // ========================================================================== // ?class? // ========================================================================== /** * class loaderclass? */ public static String locateClass(String className) { return locateClass(className, null); } /** * class loaderclass? */ public static String locateClass(String className, ClassLoader loader) { className = Assert.assertNotNull(StringUtils.trimToNull(className), "className"); 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):|!/$", org.power.commons.lang.BasicConstant.EMPTY_STRING); } return location; } /** * 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; } } }