如何判断对象是否实现了类似toString()的方法?

时间:2015-10-15 19:36:19

标签: java reflection

我正在编写测试库,我希望能够处理可能没有提供自己的String toString()实现的对象。

在这些情况下,而不是使用无用的默认实现,我想使用Apache Commons-Lang ToStringBuilder代替......但是如果可用的话,宁愿使用对象的toString()实现。

如何确定对象是否具有toString()除默认值以外的实现?

1 个答案:

答案 0 :(得分:1)

我发现的最好的方法是使用java.lang.Class.getDeclaredMethod(String,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;
    }
}

我用以下方法对此进行了测试:

NB:我没有使用default方法实现测试,因为我目前无法访问Java 8 JRE。