如何判断一个对象是否实现了类似 toString() 的方法?
How to tell if an object implements a method like toString()?
我正在编写一个测试库,我希望能够处理可能未提供它们自己的 String toString()
实现的对象。
在那些情况下,我不想使用无用的默认实现,而是想使用 Apache Commons-Lang ToStringBuilder
...但如果可用,我宁愿使用对象的 toString()
实现。
我如何判断一个对象是否有 toString()
的实现而不是默认的?
我发现的最好的方法是使用 java.lang.Class.getDeclaredMethod(String,Class<?>...)
并在对象的 class 层次结构上调用它,如下所示:
public static boolean objectHasToStringImplemented( final Object o ){
return classHasToStringImplemented( o.getClass() );
}
public static boolean classHasToStringImplemented( final Class<?> initialClass ){
Class<?> classToCheck = initialClass;
while( classToCheck != Object.class ){
if( classImplementsToString( classToCheck ) ){
return true;
}
classToCheck = classToCheck.getSuperclass();
}
return false;
}
private boolean classImplementsToString( final Class<?> aClass ){
try{
aClass.getDeclaredMethod( "toString" );
return true;
}catch( NoSuchMethodException e ){
return false;
}
}
然后我通过缓存答案而不触发异常来加快速度
//NB: implementation is synchronized and thus thread-safe
private static final Hashtable<Class<?>,Boolean> cachedAnswers = new Hashtable<>();
static {
cachedAnswers.put( Object.class, Boolean.FALSE );
}
public static Boolean objectHasToStringImplemented( final Object o ){
return classHasToStringImplemented( o.getClass() );
}
public static Boolean classHasToStringImplemented( final Class<?> classToCheck ){
if( cachedAnswers.containsKey( classToCheck ) ){
return cachedAnswers.get( classToCheck );
}
final Boolean result = classImplementsToString( classToCheck ) || classHasToStringImplemented( classToCheck.getSuperclass() );
cachedAnswers.put( classToCheck, result );
return result;
}
private static Boolean classImplementsToString( final Class<?> aClass ){
for( Method m : aClass.getDeclaredMethods() ){
if( isToString( m ) ){
return Boolean.TRUE;
}
}
return Boolean.FALSE;
}
private static Boolean isToString( final Method m ){
if( m.getParameterCount() == 0 && m.getName().equals( "toString" ) && m.getReturnType().equals( String.class ) ){
return Boolean.TRUE;
}else{
return Boolean.FALSE;
}
}
我用以下方法测试过:
java.lang.StringBuilder
(实现 toString()
)
java.util.ArrayList
(which inherits an implementation from java.util.AbstractList
)
java.util.Objects
(只有一个静态的toString(java.lang.Object)
)
- 和一个只定义了
String toString(int i)
方法的自定义 class
注意: 我没有用 default
方法实现测试这个,因为我目前无法访问 Java 8 JRE。
我正在编写一个测试库,我希望能够处理可能未提供它们自己的 String toString()
实现的对象。
在那些情况下,我不想使用无用的默认实现,而是想使用 Apache Commons-Lang ToStringBuilder
...但如果可用,我宁愿使用对象的 toString()
实现。
我如何判断一个对象是否有 toString()
的实现而不是默认的?
我发现的最好的方法是使用 java.lang.Class.getDeclaredMethod(String,Class<?>...)
并在对象的 class 层次结构上调用它,如下所示:
public static boolean objectHasToStringImplemented( final Object o ){
return classHasToStringImplemented( o.getClass() );
}
public static boolean classHasToStringImplemented( final Class<?> initialClass ){
Class<?> classToCheck = initialClass;
while( classToCheck != Object.class ){
if( classImplementsToString( classToCheck ) ){
return true;
}
classToCheck = classToCheck.getSuperclass();
}
return false;
}
private boolean classImplementsToString( final Class<?> aClass ){
try{
aClass.getDeclaredMethod( "toString" );
return true;
}catch( NoSuchMethodException e ){
return false;
}
}
然后我通过缓存答案而不触发异常来加快速度
//NB: implementation is synchronized and thus thread-safe
private static final Hashtable<Class<?>,Boolean> cachedAnswers = new Hashtable<>();
static {
cachedAnswers.put( Object.class, Boolean.FALSE );
}
public static Boolean objectHasToStringImplemented( final Object o ){
return classHasToStringImplemented( o.getClass() );
}
public static Boolean classHasToStringImplemented( final Class<?> classToCheck ){
if( cachedAnswers.containsKey( classToCheck ) ){
return cachedAnswers.get( classToCheck );
}
final Boolean result = classImplementsToString( classToCheck ) || classHasToStringImplemented( classToCheck.getSuperclass() );
cachedAnswers.put( classToCheck, result );
return result;
}
private static Boolean classImplementsToString( final Class<?> aClass ){
for( Method m : aClass.getDeclaredMethods() ){
if( isToString( m ) ){
return Boolean.TRUE;
}
}
return Boolean.FALSE;
}
private static Boolean isToString( final Method m ){
if( m.getParameterCount() == 0 && m.getName().equals( "toString" ) && m.getReturnType().equals( String.class ) ){
return Boolean.TRUE;
}else{
return Boolean.FALSE;
}
}
我用以下方法测试过:
java.lang.StringBuilder
(实现toString()
)java.util.ArrayList
(which inherits an implementation fromjava.util.AbstractList
)java.util.Objects
(只有一个静态的toString(java.lang.Object)
)- 和一个只定义了
String toString(int i)
方法的自定义 class
注意: 我没有用 default
方法实现测试这个,因为我目前无法访问 Java 8 JRE。