您的位置:首页 > 编程语言 > Java开发

[置顶] 在java中如何判断一个类是否存在

2017-09-30 11:09 543 查看
Apache Commons-Logging 中的解决方案:

public class LogSource {

// ------------------------------------------------------- Class Attributes

static protected Hashtable logs = new Hashtable();

/** Is log4j available (in the current classpath) */
static protected boolean log4jIsAvailable = false;

/** Is JDK 1.4 logging available */
static protected boolean jdk14IsAvailable = false;

/** Constructor for current log class */
static protected Constructor logImplctor = null;

// ----------------------------------------------------- Class Initializers

static {

// Is Log4J Available?
try {
log4jIsAvailable = null != Class.forName("org.apache.log4j.Logger");
} catch (Throwable t) {
log4jIsAvailable = false;
}

// Is JDK 1.4 Logging Available?
try {
jdk14IsAvailable = null != Class.forName("java.util.logging.Logger") &&
null != Class.forName("org.apache.commons.logging.impl.Jdk14Logger");
} catch (Throwable t) {
jdk14IsAvailable = false;
}

// Set the default Log implementation
String name = null;
try {
name = System.getProperty("org.apache.commons.logging.log");
if (name == null) {
name = System.getProperty("org.apache.commons.logging.Log");
}
} catch (Throwable t) {
}
if (name != null) {
try {
setLogImplementation(name);
} catch (Throwable t) {
try {
setLogImplementation("org.apache.commons.logging.impl.NoOpLog");
} catch (Throwable u) {
// ignored
}
}
} else {
try {
if (log4jIsAvailable) {
setLogImplementation("org.apache.commons.logging.impl.Log4JLogger");
} else if (jdk14IsAvailable) {
setLogImplementation("org.apache.commons.logging.impl.Jdk14Logger");
} else {
setLogImplementation("org.apache.commons.logging.impl.NoOpLog");
}
} catch (Throwable t) {
try {
setLogImplementation("org.apache.commons.logging.impl.NoOpLog");
} catch (Throwable u) {
// ignored
}
}
}

}
//...
}


核心的代码:

boolean isPresent = null != Class.forName("org.apache.log4j.Logger");


!=
的优先级大于
=


所以以上的代码对应于:

boolean isPresent = (null != Class.forName("org.apache.log4j.Logger"));


SpringMVC 中的解决方案:

public class AllEncompassingFormHttpMessageConverter extends FormHttpMessageConverter {

private static final boolean jaxb2Present =
ClassUtils.isPresent("javax.xml.bind.Binder", AllEncompassingFormHttpMessageConverter.class.getClassLoader());

private static final boolean jackson2Present =
ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", AllEncompassingFormHttpMessageConverter.class.getClassLoader()) &&
ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", AllEncompassingFormHttpMessageConverter.class.getClassLoader());

private static final boolean jackson2XmlPresent =
ClassUtils.isPresent("com.fasterxml.jackson.dataformat.xml.XmlMapper", AllEncompassingFormHttpMessageConverter.class.getClassLoader());

private static final boolean gsonPresent =
ClassUtils.isPresent("com.google.gson.Gson", AllEncompassingFormHttpMessageConverter.class.getClassLoader());

public AllEncompassingFormHttpMessageConverter() {
addPartConverter(new SourceHttpMessageConverter<Source>());

if (jaxb2Present && !jackson2XmlPresent) {
addPartConverter(new Jaxb2RootElementHttpMessageConverter());
}

if (jackson2Present) {
addPartConverter(new MappingJackson2HttpMessageConverter());
}
else if (gsonPresent) {
addPartConverter(new GsonHttpMessageConverter());
}

if (jackson2XmlPresent) {
addPartConverter(new MappingJackson2XmlHttpMessageConverter());
}
}

}


/**
* Determine whether the Class identified by the supplied name is present and can be loaded.
* 判断由提供的类名(类的全限定名)标识的类是否存在并可以加载
* 如果类或其中一个依赖关系不存在或无法加载,则返回false
* @param className 要检查的类的名称
* @param classLoader 加载该类使用的类加载器
* 可以是 null, 表明使用默认的类加载器
* @return 指定的类是否存在
*/
public static boolean isPresent(String className, ClassLoader classLoader) {
try {
forName(className, classLoader);
return true;
}
catch (Throwable ex) {
// Class or one of its dependencies is not present...
return false;
}
}


可见,以上都是用了
Class.forName
来完成。

Class.forName
在没有找到该类时抛出
ClassNotFoundException
异常。

我们所需要做的仅仅是屏蔽该异常,并设置一个表示当前类不存在的标识。

那么问题来了,我们都知道
Class.forName
会导致我们加载的类去执行静态代码块(当然也可以设置不进行初始化),以及静态属性的初始化。在JVM中对应于

invokeSpecial <cint>


但是
在java中如何判断一个类是否存在
这一简单问题似乎没有必要这样做。

那么如下的代码似乎更符合我们的要求吧?

public static boolean isPresent(String name) {
try {
Thread.currentThread().getContextClassLoader().loadClass(name);
return true;
} catch (ClassNotFoundException e) {
return false;
}
}


以上的
loadClass(String name)
方法会去调用该类中的protected方法
java.lang.ClassLoader#loadClass(java.lang.String, boolean)


public Class<?> loadClass(String name) throws ClassNotFoundException {
return loadClass(name, false);
}


protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// First, check if the class has already been loaded
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}

if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
long t1 = System.nanoTime();
c = findClass(name);

// this is the defining class loader; record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}


resolve
参数表示是否进行链接。



两者的区别见:

http://blog.csdn.net/x_iya/article/details/73199280
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: