Created
February 22, 2016 06:34
-
-
Save easternHong/d71a05fa29386fc6d3ea to your computer and use it in GitHub Desktop.
无需反射,获取一个类的实例...
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* <p>Operates on classes without using reflection.</p> | |
* <p/> | |
* <p>This class handles invalid {@code null} inputs as best it can. | |
* Each method documents its behaviour in more detail.</p> | |
* <p/> | |
* <p>The notion of a {@code canonical name} includes the human | |
* readable name for the type, for example {@code int[]}. The | |
* non-canonical method variants work with the JVM names, such as | |
* {@code [I}. </p> | |
* | |
* @version $Id: ClassUtils.java 1199894 2011-11-09 17:53:59Z ggregory $ | |
* @since 2.0 | |
*/ | |
public class ClassUtils { | |
/** | |
* <p>The package separator character: <code>'.' == {@value}</code>.</p> | |
*/ | |
public static final char PACKAGE_SEPARATOR_CHAR = '.'; | |
/** | |
* <p>The package separator String: {@code "."}.</p> | |
*/ | |
public static final String PACKAGE_SEPARATOR = String.valueOf(PACKAGE_SEPARATOR_CHAR); | |
/** | |
* <p>The inner class separator character: <code>'$' == {@value}</code>.</p> | |
*/ | |
public static final char INNER_CLASS_SEPARATOR_CHAR = '$'; | |
/** | |
* <p>The inner class separator String: {@code "$"}.</p> | |
*/ | |
public static final String INNER_CLASS_SEPARATOR = String.valueOf(INNER_CLASS_SEPARATOR_CHAR); | |
/** | |
* <p>Empty string.</p> | |
*/ | |
public static final String STRING_EMPTY = ""; | |
/** | |
* Maps primitive {@code Class}es to their corresponding wrapper {@code Class}. | |
*/ | |
private static final Map<Class<?>, Class<?>> primitiveWrapperMap = new HashMap<Class<?>, Class<?>>(); | |
static { | |
primitiveWrapperMap.put(Boolean.TYPE, Boolean.class); | |
primitiveWrapperMap.put(Byte.TYPE, Byte.class); | |
primitiveWrapperMap.put(Character.TYPE, Character.class); | |
primitiveWrapperMap.put(Short.TYPE, Short.class); | |
primitiveWrapperMap.put(Integer.TYPE, Integer.class); | |
primitiveWrapperMap.put(Long.TYPE, Long.class); | |
primitiveWrapperMap.put(Double.TYPE, Double.class); | |
primitiveWrapperMap.put(Float.TYPE, Float.class); | |
primitiveWrapperMap.put(Void.TYPE, Void.TYPE); | |
} | |
/** | |
* Maps wrapper {@code Class}es to their corresponding primitive types. | |
*/ | |
private static final Map<Class<?>, Class<?>> wrapperPrimitiveMap = new HashMap<Class<?>, Class<?>>(); | |
static { | |
for (Class<?> primitiveClass : primitiveWrapperMap.keySet()) { | |
Class<?> wrapperClass = primitiveWrapperMap.get(primitiveClass); | |
if (!primitiveClass.equals(wrapperClass)) { | |
wrapperPrimitiveMap.put(wrapperClass, primitiveClass); | |
} | |
} | |
} | |
/** | |
* Maps a primitive class name to its corresponding abbreviation used in array class names. | |
*/ | |
private static final Map<String, String> abbreviationMap = new HashMap<String, String>(); | |
/** | |
* Maps an abbreviation used in array class names to corresponding primitive class name. | |
*/ | |
private static final Map<String, String> reverseAbbreviationMap = new HashMap<String, String>(); | |
/** | |
* Add primitive type abbreviation to maps of abbreviations. | |
* | |
* @param primitive Canonical name of primitive type | |
* @param abbreviation Corresponding abbreviation of primitive type | |
*/ | |
private static void addAbbreviation(String primitive, String abbreviation) { | |
abbreviationMap.put(primitive, abbreviation); | |
reverseAbbreviationMap.put(abbreviation, primitive); | |
} | |
/** | |
* Feed abbreviation maps | |
*/ | |
static { | |
addAbbreviation("int", "I"); | |
addAbbreviation("boolean", "Z"); | |
addAbbreviation("float", "F"); | |
addAbbreviation("long", "J"); | |
addAbbreviation("short", "S"); | |
addAbbreviation("byte", "B"); | |
addAbbreviation("double", "D"); | |
addAbbreviation("char", "C"); | |
} | |
/** | |
* <p>ClassUtils instances should NOT be constructed in standard programming. | |
* Instead, the class should be used as | |
* {@code ClassUtils.getShortClassName(cls)}.</p> | |
* <p/> | |
* <p>This constructor is public to permit tools that require a JavaBean | |
* instance to operate.</p> | |
*/ | |
public ClassUtils() { | |
super(); | |
} | |
// Short class name | |
// ---------------------------------------------------------------------- | |
/** | |
* <p>Gets the class name minus the package name for an {@code Object}.</p> | |
* | |
* @param object the class to get the short name for, may be null | |
* @param valueIfNull the value to return if null | |
* @return the class name of the object without the package name, or the null value | |
*/ | |
public static String getShortClassName(Object object, String valueIfNull) { | |
if (object == null) { | |
return valueIfNull; | |
} | |
return getShortClassName(object.getClass()); | |
} | |
/** | |
* <p>Gets the class name minus the package name from a {@code Class}.</p> | |
* <p/> | |
* <p>Consider using the Java 5 API {@link Class#getSimpleName()} instead. | |
* The one known difference is that this code will return {@code "Map.Entry"} while | |
* the {@code java.lang.Class} variant will simply return {@code "Entry"}. </p> | |
* | |
* @param cls the class to get the short name for. | |
* @return the class name without the package name or an empty string | |
*/ | |
public static String getShortClassName(Class<?> cls) { | |
if (cls == null) { | |
return ""; | |
} | |
return getShortClassName(cls.getName()); | |
} | |
/** | |
* <p>Gets the class name minus the package name from a String.</p> | |
* <p/> | |
* <p>The string passed in is assumed to be a class name - it is not checked.</p> | |
* <p>Note that this method differs from Class.getSimpleName() in that this will | |
* return {@code "Map.Entry"} whilst the {@code java.lang.Class} variant will simply | |
* return {@code "Entry"}. </p> | |
* | |
* @param className the className to get the short name for | |
* @return the class name of the class without the package name or an empty string | |
*/ | |
public static String getShortClassName(String className) { | |
if (className == null) { | |
return STRING_EMPTY; | |
} | |
if (className.length() == 0) { | |
return STRING_EMPTY; | |
} | |
StringBuilder arrayPrefix = new StringBuilder(); | |
// Handle array encoding | |
if (className.startsWith("[")) { | |
while (className.charAt(0) == '[') { | |
className = className.substring(1); | |
arrayPrefix.append("[]"); | |
} | |
// Strip Object type encoding | |
if (className.charAt(0) == 'L' && className.charAt(className.length() - 1) == ';') { | |
className = className.substring(1, className.length() - 1); | |
} | |
} | |
if (reverseAbbreviationMap.containsKey(className)) { | |
className = reverseAbbreviationMap.get(className); | |
} | |
int lastDotIdx = className.lastIndexOf(PACKAGE_SEPARATOR_CHAR); | |
int innerIdx = className.indexOf( | |
INNER_CLASS_SEPARATOR_CHAR, lastDotIdx == -1 ? 0 : lastDotIdx + 1); | |
String out = className.substring(lastDotIdx + 1); | |
if (innerIdx != -1) { | |
out = out.replace(INNER_CLASS_SEPARATOR_CHAR, PACKAGE_SEPARATOR_CHAR); | |
} | |
return out + arrayPrefix; | |
} | |
/** | |
* <p>Null-safe version of <code>aClass.getSimpleName()</code></p> | |
* | |
* @param cls the class for which to get the simple name. | |
* @return the simple class name. | |
* @see Class#getSimpleName() | |
* @since 3.0 | |
*/ | |
public static String getSimpleName(Class<?> cls) { | |
if (cls == null) { | |
return STRING_EMPTY; | |
} | |
return cls.getSimpleName(); | |
} | |
/** | |
* <p>Null-safe version of <code>aClass.getSimpleName()</code></p> | |
* | |
* @param object the object for which to get the simple class name. | |
* @param valueIfNull the value to return if <code>object</code> is <code>null</code> | |
* @return the simple class name. | |
* @see Class#getSimpleName() | |
* @since 3.0 | |
*/ | |
public static String getSimpleName(Object object, String valueIfNull) { | |
if (object == null) { | |
return valueIfNull; | |
} | |
return getSimpleName(object.getClass()); | |
} | |
// Package name | |
// ---------------------------------------------------------------------- | |
/** | |
* <p>Gets the package name of an {@code Object}.</p> | |
* | |
* @param object the class to get the package name for, may be null | |
* @param valueIfNull the value to return if null | |
* @return the package name of the object, or the null value | |
*/ | |
public static String getPackageName(Object object, String valueIfNull) { | |
if (object == null) { | |
return valueIfNull; | |
} | |
return getPackageName(object.getClass()); | |
} | |
/** | |
* <p>Gets the package name of a {@code Class}.</p> | |
* | |
* @param cls the class to get the package name for, may be {@code null}. | |
* @return the package name or an empty string | |
*/ | |
public static String getPackageName(Class<?> cls) { | |
if (cls == null) { | |
return STRING_EMPTY; | |
} | |
return getPackageName(cls.getName()); | |
} | |
/** | |
* <p>Gets the package name from a {@code String}.</p> | |
* <p/> | |
* <p>The string passed in is assumed to be a class name - it is not checked.</p> | |
* <p>If the class is unpackaged, return an empty string.</p> | |
* | |
* @param className the className to get the package name for, may be {@code null} | |
* @return the package name or an empty string | |
*/ | |
public static String getPackageName(String className) { | |
if (className == null || className.length() == 0) { | |
return STRING_EMPTY; | |
} | |
// Strip array encoding | |
while (className.charAt(0) == '[') { | |
className = className.substring(1); | |
} | |
// Strip Object type encoding | |
if (className.charAt(0) == 'L' && className.charAt(className.length() - 1) == ';') { | |
className = className.substring(1); | |
} | |
int i = className.lastIndexOf(PACKAGE_SEPARATOR_CHAR); | |
if (i == -1) { | |
return STRING_EMPTY; | |
} | |
return className.substring(0, i); | |
} | |
// Superclasses/Superinterfaces | |
// ---------------------------------------------------------------------- | |
/** | |
* <p>Gets a {@code List} of superclasses for the given class.</p> | |
* | |
* @param cls the class to look up, may be {@code null} | |
* @return the {@code List} of superclasses in order going up from this one | |
* {@code null} if null input | |
*/ | |
public static List<Class<?>> getAllSuperclasses(Class<?> cls) { | |
if (cls == null) { | |
return null; | |
} | |
List<Class<?>> classes = new ArrayList<Class<?>>(); | |
Class<?> superclass = cls.getSuperclass(); | |
while (superclass != null) { | |
classes.add(superclass); | |
superclass = superclass.getSuperclass(); | |
} | |
return classes; | |
} | |
/** | |
* <p>Gets a {@code List} of all interfaces implemented by the given | |
* class and its superclasses.</p> | |
* <p/> | |
* <p>The order is determined by looking through each interface in turn as | |
* declared in the source file and following its hierarchy up. Then each | |
* superclass is considered in the same way. Later duplicates are ignored, | |
* so the order is maintained.</p> | |
* | |
* @param cls the class to look up, may be {@code null} | |
* @return the {@code List} of interfaces in order, | |
* {@code null} if null input | |
*/ | |
public static List<Class<?>> getAllInterfaces(Class<?> cls) { | |
if (cls == null) { | |
return null; | |
} | |
LinkedHashSet<Class<?>> interfacesFound = new LinkedHashSet<Class<?>>(); | |
getAllInterfaces(cls, interfacesFound); | |
return new ArrayList<Class<?>>(interfacesFound); | |
} | |
/** | |
* Get the interfaces for the specified class. | |
* | |
* @param cls the class to look up, may be {@code null} | |
* @param interfacesFound the {@code Set} of interfaces for the class | |
*/ | |
private static void getAllInterfaces(Class<?> cls, HashSet<Class<?>> interfacesFound) { | |
while (cls != null) { | |
Class<?>[] interfaces = cls.getInterfaces(); | |
for (Class<?> i : interfaces) { | |
if (interfacesFound.add(i)) { | |
getAllInterfaces(i, interfacesFound); | |
} | |
} | |
cls = cls.getSuperclass(); | |
} | |
} | |
// Convert list | |
// ---------------------------------------------------------------------- | |
/** | |
* <p>Given a {@code List} of class names, this method converts them into classes.</p> | |
* <p/> | |
* <p>A new {@code List} is returned. If the class name cannot be found, {@code null} | |
* is stored in the {@code List}. If the class name in the {@code List} is | |
* {@code null}, {@code null} is stored in the output {@code List}.</p> | |
* | |
* @param classNames the classNames to change | |
* @return a {@code List} of Class objects corresponding to the class names, | |
* {@code null} if null input | |
* @throws ClassCastException if classNames contains a non String entry | |
*/ | |
public static List<Class<?>> convertClassNamesToClasses(List<String> classNames) { | |
if (classNames == null) { | |
return null; | |
} | |
List<Class<?>> classes = new ArrayList<Class<?>>(classNames.size()); | |
for (String className : classNames) { | |
try { | |
classes.add(Class.forName(className)); | |
} catch (Exception ex) { | |
classes.add(null); | |
} | |
} | |
return classes; | |
} | |
/** | |
* <p>Given a {@code List} of {@code Class} objects, this method converts | |
* them into class names.</p> | |
* <p/> | |
* <p>A new {@code List} is returned. {@code null} objects will be copied into | |
* the returned list as {@code null}.</p> | |
* | |
* @param classes the classes to change | |
* @return a {@code List} of class names corresponding to the Class objects, | |
* {@code null} if null input | |
* @throws ClassCastException if {@code classes} contains a non-{@code Class} entry | |
*/ | |
public static List<String> convertClassesToClassNames(List<Class<?>> classes) { | |
if (classes == null) { | |
return null; | |
} | |
List<String> classNames = new ArrayList<String>(classes.size()); | |
for (Class<?> cls : classes) { | |
if (cls == null) { | |
classNames.add(null); | |
} else { | |
classNames.add(cls.getName()); | |
} | |
} | |
return classNames; | |
} | |
// Class loading | |
// ---------------------------------------------------------------------- | |
/** | |
* Returns the class represented by {@code className} using the | |
* {@code classLoader}. This implementation supports the syntaxes | |
* "{@code java.util.Map.Entry[]}", "{@code java.util.Map$Entry[]}", | |
* "{@code [Ljava.util.Map.Entry;}", and "{@code [Ljava.util.Map$Entry;}". | |
* | |
* @param classLoader the class loader to use to load the class | |
* @param className the class name | |
* @param initialize whether the class must be initialized | |
* @return the class represented by {@code className} using the {@code classLoader} | |
* @throws ClassNotFoundException if the class is not found | |
*/ | |
public static Class<?> getClass( | |
ClassLoader classLoader, String className, boolean initialize) throws ClassNotFoundException { | |
try { | |
Class<?> clazz; | |
if (abbreviationMap.containsKey(className)) { | |
String clsName = "[" + abbreviationMap.get(className); | |
clazz = Class.forName(clsName, initialize, classLoader).getComponentType(); | |
} else { | |
clazz = Class.forName(toCanonicalName(className), initialize, classLoader); | |
} | |
return clazz; | |
} catch (ClassNotFoundException ex) { | |
// allow path separators (.) as inner class name separators | |
int lastDotIndex = className.lastIndexOf(PACKAGE_SEPARATOR_CHAR); | |
if (lastDotIndex != -1) { | |
try { | |
return getClass(classLoader, className.substring(0, lastDotIndex) + | |
INNER_CLASS_SEPARATOR_CHAR + className.substring(lastDotIndex + 1), | |
initialize); | |
} catch (ClassNotFoundException ex2) { // NOPMD | |
// ignore exception | |
} | |
} | |
throw ex; | |
} | |
} | |
/** | |
* Returns the (initialized) class represented by {@code className} | |
* using the {@code classLoader}. This implementation supports | |
* the syntaxes "{@code java.util.Map.Entry[]}", | |
* "{@code java.util.Map$Entry[]}", "{@code [Ljava.util.Map.Entry;}", | |
* and "{@code [Ljava.util.Map$Entry;}". | |
* | |
* @param classLoader the class loader to use to load the class | |
* @param className the class name | |
* @return the class represented by {@code className} using the {@code classLoader} | |
* @throws ClassNotFoundException if the class is not found | |
*/ | |
public static Class<?> getClass(ClassLoader classLoader, String className) throws ClassNotFoundException { | |
return getClass(classLoader, className, true); | |
} | |
/** | |
* Returns the (initialized) class represented by {@code className} | |
* using the current thread's context class loader. This implementation | |
* supports the syntaxes "{@code java.util.Map.Entry[]}", | |
* "{@code java.util.Map$Entry[]}", "{@code [Ljava.util.Map.Entry;}", | |
* and "{@code [Ljava.util.Map$Entry;}". | |
* | |
* @param className the class name | |
* @return the class represented by {@code className} using the current thread's context class loader | |
* @throws ClassNotFoundException if the class is not found | |
*/ | |
public static Class<?> getClass(String className) throws ClassNotFoundException { | |
return getClass(className, true); | |
} | |
/** | |
* Returns the class represented by {@code className} using the | |
* current thread's context class loader. This implementation supports the | |
* syntaxes "{@code java.util.Map.Entry[]}", "{@code java.util.Map$Entry[]}", | |
* "{@code [Ljava.util.Map.Entry;}", and "{@code [Ljava.util.Map$Entry;}". | |
* | |
* @param className the class name | |
* @param initialize whether the class must be initialized | |
* @return the class represented by {@code className} using the current thread's context class loader | |
* @throws ClassNotFoundException if the class is not found | |
*/ | |
public static Class<?> getClass(String className, boolean initialize) throws ClassNotFoundException { | |
ClassLoader contextCL = Thread.currentThread().getContextClassLoader(); | |
ClassLoader loader = contextCL == null ? ClassUtils.class.getClassLoader() : contextCL; | |
return getClass(loader, className, initialize); | |
} | |
// ---------------------------------------------------------------------- | |
/** | |
* Converts a class name to a JLS style class name. | |
* | |
* @param className the class name | |
* @return the converted name | |
*/ | |
private static String toCanonicalName(String className) { | |
className = deleteWhitespace(className); | |
if (className == null) { | |
throw new NullPointerException("className must not be null."); | |
} else if (className.endsWith("[]")) { | |
StringBuilder classNameBuffer = new StringBuilder(); | |
while (className.endsWith("[]")) { | |
className = className.substring(0, className.length() - 2); | |
classNameBuffer.append("["); | |
} | |
String abbreviation = abbreviationMap.get(className); | |
if (abbreviation != null) { | |
classNameBuffer.append(abbreviation); | |
} else { | |
classNameBuffer.append("L").append(className).append(";"); | |
} | |
className = classNameBuffer.toString(); | |
} | |
return className; | |
} | |
/** | |
* <p>Converts an array of {@code Object} in to an array of {@code Class} objects. | |
* If any of these objects is null, a null element will be inserted into the array.</p> | |
* <p/> | |
* <p>This method returns {@code null} for a {@code null} input array.</p> | |
* | |
* @param array an {@code Object} array | |
* @return a {@code Class} array, {@code null} if null array input | |
* @since 2.4 | |
*/ | |
public static Class<?>[] toClass(Object... array) { | |
if (array == null) { | |
return null; | |
} else if (array.length == 0) { | |
return new Class[0]; | |
} | |
Class<?>[] classes = new Class[array.length]; | |
for (int i = 0; i < array.length; i++) { | |
classes[i] = array[i] == null ? null : array[i].getClass(); | |
} | |
return classes; | |
} | |
// Delete | |
//----------------------------------------------------------------------- | |
/** | |
* <p>Deletes all whitespaces from a String as defined by | |
* {@link Character#isWhitespace(char)}.</p> | |
* <p/> | |
* <pre> | |
* StringUtils.deleteWhitespace(null) = null | |
* StringUtils.deleteWhitespace("") = "" | |
* StringUtils.deleteWhitespace("abc") = "abc" | |
* StringUtils.deleteWhitespace(" ab c ") = "abc" | |
* </pre> | |
* | |
* @param str the String to delete whitespace from, may be null | |
* @return the String without whitespaces, {@code null} if null String input | |
*/ | |
public static String deleteWhitespace(String str) { | |
if (isEmpty(str)) { | |
return str; | |
} | |
int sz = str.length(); | |
char[] chs = new char[sz]; | |
int count = 0; | |
for (int i = 0; i < sz; i++) { | |
if (!Character.isWhitespace(str.charAt(i))) { | |
chs[count++] = str.charAt(i); | |
} | |
} | |
if (count == sz) { | |
return str; | |
} | |
return new String(chs, 0, count); | |
} | |
// Empty checks | |
//----------------------------------------------------------------------- | |
/** | |
* <p>Checks if a CharSequence is empty ("") or null.</p> | |
* <p/> | |
* <pre> | |
* StringUtils.isEmpty(null) = true | |
* StringUtils.isEmpty("") = true | |
* StringUtils.isEmpty(" ") = false | |
* StringUtils.isEmpty("bob") = false | |
* StringUtils.isEmpty(" bob ") = false | |
* </pre> | |
* <p/> | |
* <p>NOTE: This method changed in Lang version 2.0. | |
* It no longer trims the CharSequence. | |
* That functionality is available in isBlank().</p> | |
* | |
* @param cs the CharSequence to check, may be null | |
* @return {@code true} if the CharSequence is empty or null | |
* @since 3.0 Changed signature from isEmpty(String) to isEmpty(CharSequence) | |
*/ | |
public static boolean isEmpty(CharSequence cs) { | |
return cs == null || cs.length() == 0; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment