Java泛型限制为接口 [英] Java Generics restrict to interface

查看:82
本文介绍了Java泛型限制为接口的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm not sure if this is possible or not, but what I want to accomplish is this:

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

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

Essentially, using a reflection/generation driven process, I want to provide a thing of type B, where B is of class SomeClass and implements interface A, and A is user-supplied through Generics.

我不是在问生成B的机制-我已经控制住了.我正在寻找一种将通用类型参数< A> 限制为接口而不是类的方法,以便我可以使用语法 B扩展SomeClass&用于清洁类型的安全性.

I am not asking about the mechanics of generating B - I have that under control. What I'm looking for is a way to restrict generic type argument <A> to interfaces, not classes, so that I can use the syntax B extends SomeClass & A for clean type safety.

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

Is this possible? Is anyone aware of an alternative approach to this problem?

我想我说得不太清楚,因为这似乎引起了评论的混乱:

I guess I didn't express myself very clearly, as it seems to be causing confusion in the comments:

B 旨在用作通配符的占位符,以便客户端可以获得单个对象,该对象既是 SomeClass 又是 A ,而不必基于信任进行强制类型转换.客户端将无法访问实现 SomeClass A 的实际类的名称,因为它是在编译时生成的,因此,此问题涉及类型安全.

B is intended to be a placeholder for a wildcard, so that the client can get a single object that is both a SomeClass and an A without having to do casting based on trust. The client will not have access to the name of the actual class that implements SomeClass and A, because it's being generated at compile time, hence this issue regarding type safety.

推荐答案

不可能强加这样的编译时限制.泛型类型参数是引用类型的替身;它们在类类型和接口类型之间没有区别.类型参数的声明中的附加边界必须是接口类型这一事实只是偶然的-您使用该策略作为将类型归为接口的手段的策略很聪明,但是由于类型参数

It's impossible to impose such a compile-time restriction. Generic type parameters are stand-ins for reference types; they make no distinction between class types and interface types. The fact that additional bounds in a type parameter's declaration must be interface types is merely incidental - your strategy to leverage this as a means to impute a type as an interface was clever, but it's defeated by the limitation that type parameters can't be used in multiple bounds.

您唯一的选择是使用指出,或者让调用者对传入的内容负责.无论哪种方式,请确保清楚地记录该方法的期望和行为.

Your only options are to settle for a runtime check using Class.isInterface() like Louis Wasserman pointed out, or to leave it up to the caller to be responsible with what it passes in. Either way, make sure to clearly document the method's expectations and behavior.

B 旨在用作通配符的占位符,以便客户端可以获得单个对象,该对象既是 SomeClass 又是 A ,而不必基于信任进行强制类型转换.客户端将无法访问实现 SomeClass A

B is intended to be a placeholder for a wildcard, so that the client can get a single object that is both a SomeClass and an A without having to do casting based on trust. The client will not have access to the name of the actual class that implements SomeClass and A

这对我来说似乎是一个矛盾.如果调用者可能不知道它的计算结果,则没有必要声明 B .切记:泛型方法的调用者提供其类型参数.因此,调用方决定 B 而没有任何依据的话只能是猜测-绝不可能是类型安全的.

This seems like a contradiction to me. There's no point to declaring B if the caller can't possibly know what it evaluates to. Remember: the caller of a generic method provides its type arguments. So a caller deciding B without anything to base it on can only be guessing - and that can never be type-safe.

似乎您真正希望您的方法返回的是同时是 SomeClass A 的某种类型,但这很棘手,因为它们不共享常见的超类型:

It seems like what you really want your method to return is some type that is both a SomeClass and an A, but this is tricky because they don't share a common supertype:

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

(这是荒谬的语法仅用于演示)

作为一种解决方法,请考虑同时表示 SomeClass 和某些接口类型的其他方法.例如,候选接口可能具有返回 SomeClass 的通用方法:

As a workaround, consider alternative ways to represent both a SomeClass and some interface type. For example the candidate interfaces could have a common method for returning a SomeClass:

public interface IsSomeClass {
    SomeClass asSomeClass();
}

public interface Foo extends IsSomeClass { }

asSomeClass 的实现实际上只会返回 this .然后,您可以这样做:

The implementation of asSomeClass would in fact just return this. Then you could do:

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

该方法的调用者将可以使用返回的对象作为以下两种类型之一:

And the caller of that method would be able to use the returned object as either type:

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

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

If the interfaces themselves can't be modified, then another option is to use a wrapper class and composition instead:

final class SomeClassWrapper<A> {

    private final SomeClass someClass;
    private final A a;

    //constructor and getters, etc.
}

您的方法将返回一个包装实例,将实现实例分配给两者 someClass a :

And your method would return a wrapper instance instead, assigning the implementation instance to both someClass and a:

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

这篇关于Java泛型限制为接口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆