在Java中查找最具体的类

时间:2017-07-23 15:37:40

标签: java reflection instanceof

我试图为我的特定目的编写某种异常处理程序。 我有一个班级列表。让我们说:

if(!isset($_GET['page'])) {
    $page = 'dashboard';
} 

switch($_GET['page']) {
    case 'myProfile':
         $page = 'myProfile';
    break;
    case 'coupon':
         $page = 'settings';
    break;
    default:
         $page = 'dashboard';
}

现在,我想做:

List<Class<? extends Throwable>> list = new LinkedList<>();
list.add(RuntimeException.class);
list.add(IllegalArgumentException.class);

此方法必须找到给定类型的最具体的类。所以,如果我通过:

  • IllegalArgumentException,它必须找到IllegalArgumentException(不是RTE)。
  • RuntimeException,它必须找到RuntimeException
  • IllegalStateException,它还要查找RuntimeException(因为列表中没有IllegalStateException)
  • 如果我添加public Class<? extends Throwable> findMostSpecific(Class<? extends Throwable> type) { for (....) { if (... WHAT TO PUT HERE ? .... ) { return .... } } } 并传递它,则必须返回IllegalArgumentException(不是RTE而且CustomException不在列表中,因此IllegalArgumentException是最具体的)

那么如何找到给定实例的最具体类型?有可能吗?

3 个答案:

答案 0 :(得分:3)

在这里试一试:

public Class<? extends Throwable> findMostSpecific(Class<? extends Throwable> type) {
     // we'll keep a reference to the most specific one here
     Class<? extends Throwable> mostSpecific = null;
     // here we iterate over your list of types
     for (Class<? extends Throwable> tType : list) {
         // well not even a subtype of tType so ignore it
         if (!tType.isAssignableFrom(type)) {
             continue;
         }

         if (mostSpecific == null || mostSpecific.isAssignableFrom(tType)) {
             mostSpecific = tType;
         }
     }
     return mostSpecific;
}

答案 1 :(得分:2)

在这种情况下,您可以使用Class.getCanonicalName()在运行时检测当前类。请考虑使用Java Stream API创建最佳候选项的示例测试用例:

import org.junit.Test;

import java.util.LinkedList;
import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;

public class ReflectionTest {

    @Test
    public void test() {

        assertThat(findMostSpecific(IllegalArgumentException.class)).isEqualTo(IllegalArgumentException.class);

        assertThat(findMostSpecific(RuntimeException.class)).isEqualTo(RuntimeException.class);

        assertThat(findMostSpecific(IllegalStateException.class)).isEqualTo(RuntimeException.class);

        assertThat(findMostSpecific(IllegalStateException.class)).isEqualTo(RuntimeException.class);

        assertThat(findMostSpecific(CustomException.class)).isEqualTo(IllegalArgumentException.class);
    }

    public Class<? extends Throwable> findMostSpecific(Class<? extends Throwable> type) {
        List<Class<? extends Throwable>> list = new LinkedList<>();
        list.add(RuntimeException.class);
        list.add(IllegalArgumentException.class);

        return list.stream()
                .peek(e -> System.out.println("e.getClass() == " + e.getClass()))
                .filter(e -> type.getCanonicalName().equals(e.getCanonicalName()))
                .findAny()
                .orElseGet(() -> findMostSpecific((Class<? extends Throwable>) type.getSuperclass()));
    }

    public static class CustomException extends IllegalArgumentException {}
}

我已故意添加.peek(e -> System.out.println("e.getClass() == " + e.getClass())),因此您可以在此处看到我们获取编译时信息:

e.getClass() == class java.lang.Class
e.getClass() == class java.lang.Class
e.getClass() == class java.lang.Class
另一方面,

Class.getCanonicalName()返回运行时类的规范名称。 .orElseGet()使用父类名称检查大多数特定类,因此对于IllegalStateException.class,您将按预期获得RuntimeException.class。当然,这只是一个可以抛光和改进的示例代码(例如,不应为每个方法调用实例化具有类的列表)。我希望它有所帮助。

答案 2 :(得分:2)

基于流的解决方案还可以包含两个简单的步骤:

  • 根据元素是否可从给定类
  • 分配来过滤流
  • 计算剩余流的最大值

如下所示:

import java.util.Arrays;
import java.util.List;

public class MostSpecificClassFinder
{
    public static void main(String[] args)
    {
        List<Class<?>> classes = Arrays.asList(
            RuntimeException.class, 
            IllegalArgumentException.class
        );

        System.out.println(findMostSpecific(classes, IllegalArgumentException.class));
        System.out.println(findMostSpecific(classes, RuntimeException.class));
        System.out.println(findMostSpecific(classes, IllegalStateException.class));
        System.out.println(findMostSpecific(classes, CustomException.class));
    }

    public static Class<?> findMostSpecific(List<Class<?>> classes, Class<?> type) {
        return classes.stream()
            .filter(c -> c.isAssignableFrom(type))
            .max((c0, c1) -> c0.isAssignableFrom(c1) ? -1 : c1.isAssignableFrom(c0) ? 1 : 0)
            .get();
    }

}

class CustomException extends IllegalArgumentException 
{

}