11

我不确定这是否可能,但我想要完成的是:

public static <A,B extends SomeClass & A> B makeB(A thing) {...}

本质上,使用反射/生成驱动的过程,我想提供 B 类型的东西,其中 B 属于类SomeClass并实现接口 A,而 A 是用户通过泛型提供的。

我不是在问生成 B 的机制——我已经控制住了。我正在寻找一种将泛型类型参数限制<A>为接口而不是类的方法,以便我可以使用语法B extends SomeClass & A来确保干净的类型安全。

这可能吗?有人知道解决此问题的替代方法吗?


编辑:我想我没有很清楚地表达自己,因为它似乎在评论中引起了混乱:

B旨在作为通配符的占位符,以便客户端可以获得既是 aSomeClass又是 a 的单个对象,A而无需基于信任进行强制转换。客户端将无法访问实现SomeClassand的实际类的名称A,因为它是在编译时生成的,因此这个问题与类型安全有关。

4

3 回答 3

5

施加这样的编译时限制是不可能的。泛型类型参数是引用类型的替身;它们不区分类类型和接口类型。类型参数声明中的附加边界必须是接口类型这一事实只是偶然的 - 您利用它作为将类型归为接口的手段的策略很聪明,但是由于不能使用类型参数的限制而失败了在多个范围内

Class.isInterface()您唯一的选择是像 Louis Wasserman指出的那样满足运行时检查,或者让调用者对其传入的内容负责。无论哪种方式,请确保清楚地记录方法的期望和行为。


B旨在作为通配符的占位符,以便客户端可以获得既是 aSomeClass又是 a 的单个对象,A而无需基于信任进行强制转换。客户端将无权访问实现的实际类的名称,SomeClass并且A

这对我来说似乎很矛盾。B如果调用者不可能知道它的评估结果,那么声明它是没有意义的。请记住:泛型方法的调用者提供其类型参数。因此,调用者B在没有任何依据的情况下做出决定只能是猜测——而这永远不可能是类型安全的。

看起来您真正希望您的方法返回的是某种既是 aSomeClass又是 an 的类型A,但这很棘手,因为它们不共享一个共同的超类型:

public static <A> SomeClass&A makeSomeClass(A thing) {...}

(这只是用于演示目的的无意义语法)

作为一种解决方法,请考虑表示 aSomeClass和某些接口类型的替代方法。例如,候选接口可以有一个返回 a 的通用方法SomeClass

public interface IsSomeClass {
    SomeClass asSomeClass();
}

public interface Foo extends IsSomeClass { }

的实现asSomeClass实际上只是 return this。然后你可以这样做:

public static <A extends IsSomeClass> A makeSomeClass(Class<A> type) {...}

并且该方法的调用者将能够使用返回的对象作为任一类型:

final Foo foo = makeSomeClass(Foo.class);
final SomeClass someClass = foo.asSomeClass();

如果接口本身不能修改,那么另一种选择是使用包装类和组合:

final class SomeClassWrapper<A> {

    private final SomeClass someClass;
    private final A a;

    //constructor and getters, etc.
}

而您的方法将返回一个包装器实例,将实现实例分配 someClassand a

public static <A> SomeClassWrapper<A> makeSomeClass(Class<A> type) {...}
于 2013-07-17T01:25:52.330 回答
1

如果SomeClass始终是类,那么Ain<B extends SomeClass & A> 只能是接口,因为Java中没有多重继承。唯一& A可以满足的方法是 ifA是一个接口。

于 2013-07-17T00:18:26.217 回答
1

我认为这里的问题是您想B从此方法返回 a 。

您指定B为类型参数,但它永远不会出现在方法签名的其他任何地方。

编译器应该如何从参数推断返回类型????

客户端代码没有机会指定是什么B

看来您应该返回 aSomeClass或 a A

任何一个都可以是B引擎盖下的 a,但应该在客户端代码中显示为 aSomeClass或 an 。A

于 2013-07-17T00:22:05.440 回答