2017-10-19 130 views
8

使用类参数我有以下类:爪哇 - 在方法参数

public class Publisher<T> { 

    private static final Class[] SUPPORTED_CLASSES = new Class[]{T1.class, T2.class}; 

    public Publisher() { 
     if(Arrays.asList(SUPPORTED_CLASSES).contains(T)) { // error: expression expected! 
      System.out.println("Class not supported!"); 
     } 
    } 
} 

我如何检查是否类参数符合执行?
在上面的例子中,我不能使用类参数T作为参数。

+0

检查此线程https://stackoverflow.com/questions/3403909/get-generic-type-of-class-at-runtime –

+3

为什么你想这个,如果我可能会问? –

+0

@MCEmperor我想检查课程是否受支持,并在必要时记录警告信息 – FazoM

回答

13

为什么

您正在尝试,因为type erasure访问在运行时泛型类型,它没有在这种情况下工作,这是行不通的。

如何解决

解决这个问题是采取在构造一个Class<T>,它会给你在运行时类型最简单的方法,就可以检查如果列表包含您已获得价值。

示例代码

public Publisher(Class<T> clazz) { 
    if(!SUPPORTED_CLASSES.contains(clazz)) { 
     System.out.println("Class not supported!"); 
    } 
} 

可能出现的问题

你的代码目前不支持亚型,这可能会导致问题,除非你确定这个(你可以在列表工作,但不一定的ArrayList) ,但这确实会烙上LSP

+0

我想说,OP代码不工作的一个更基本的原因是类型参数,如'T'指定*类型* ,而不是对象。特别是,它们不同于或不代表'java.lang.Class'类型的对象,比如OP的数组所包含的对象。类型不是有效的普通参数。 –

+0

如果OP的类在T中是协变的,那么LSP只是一个问题。如果它是反或不变的,那么这是一个完全合法的(如果奇怪和非OOP)的做事方式。 – Kevin

4

你需要的类传入构造:

public Publisher(Class<T> clazz) { 
    if(!SUPPORTED_CLASSES.contains(clazz)) { 
     System.out.println("Class not supported!"); 
    } 
} 

因为T不是在运行时可用:完全相同的代码会为new Publisher<T1>()new Publisher<T3>()执行。

6

虽然一些其他的答案是相当不错的,我想提出另一种解决办法:

您可以创建一个空的接口MyInterface,并在列表中的所有类实现此接口。然后,您可以将您的类别声明更改为:

public class Publisher<T extends S, MyInterface> 

这将实现您的目的。

+1

如果您可以控制所有需要支持的类,那么这是一个更好的解决方案,但是如果您需要支持未写入的类,则可能需要以不同的方式进行操作。 – jrtapsell

+1

@jrtapsell在最糟糕的情况下,如果您不必支持太多的类,为每个需要的类使用桥接(实际上是一个简单的包装)实现接口 – AxelH

+0

当您的解决方案仅适用于实现特定接口,您不再需要兼容类的列表,并且可以将该类声明为'public class Publisher ' – Philipp