Java 在考虑差异的情况下多次从通用接口继承
我在尝试专门化一个实现了泛型接口的类时遇到了一个问题,在这个类中,我希望继承与超级类相同的接口,但具有更具体的类型参数。下面的代码段显示了一个无法编译的合成但完整的示例。注释包含来自Java编译器的错误消息Java 在考虑差异的情况下多次从通用接口继承,java,generics,inheritance,Java,Generics,Inheritance,我在尝试专门化一个实现了泛型接口的类时遇到了一个问题,在这个类中,我希望继承与超级类相同的接口,但具有更具体的类型参数。下面的代码段显示了一个无法编译的合成但完整的示例。注释包含来自Java编译器的错误消息 interface Producer<T> { T get(); } class NumberProducer implements Producer<Number> { @Override public Number get() { ret
interface Producer<T> {
T get();
}
class NumberProducer implements Producer<Number> {
@Override
public Number get() { return null; }
}
// Producer cannot be inherited with different arguments: <java.lang.Integer> and <java.lang.Number>
class IntegerProducer extends NumberProducer implements Producer<Integer> {
@Override
public Integer get() { return null; }
}
接口生成器{
T get();
}
类NumberProducer实现生产者{
@凌驾
公共编号get(){return null;}
}
//无法使用不同的参数继承Producer:和
类IntegerProducer扩展NumberProducer实现生产者{
@凌驾
公共整数get(){return null;}
}
从某种意义上说,Producer
是生产者,因此Producer
将是Producer
的子类型,但在Producer
的定义中无法声明这一点。Java不允许IntegerProducer
同时从NumberProducer
和Producer
继承,因为IntegerProducer
将同时从Producer
和Producer
继承
是否有一种标准方法来解决此限制,例如,一种模式可以解决相同的问题,而不需要这种继承?如果您想确保T属于您可以使用的特定子类型
interface Producer<T extends Number>
接口生成器
我不确定reall是什么制片人,所以我不得不猜测
更新:
如果我理解你是正确的,那么我会说,你需要声明一个接口,它是生产者。这很简单
从这个接口中,我将派生一个具有respectve基类型的新接口
i、 e:
接口生成器
{
基函数
};
接口新生产者
{
};
这就是你想要的吗?假设我们有一个简单的方法
给我
public static <T> T gimme(Producer<T> p) { return p.get(); }
public static T gimme(Producer p){return p.get();}
在gimme
的上下文中,对T
一无所知。它可以是数字
、整数
或任何其他引用类型。因此,由于擦除,编译器发出对Producer.get()对象的接口调用,而不是对IntegerProducer.get()Integer
的特定调用。使用T!=对象
还隐式实现了Producer.get()对象
。此隐式实现将转发到特定实现。这可能是NumberProducer.get()Number
或IntegerProducer.get()Integer
,但不是两者都是。这就是为什么不能实现同一接口两次
其他语言通过定义站点差异来实现这一点,其中
Producer
是Producer
的子类型,但遗憾的是,Java没有。常见的解决方法是将NumberProducer设置为泛型。只需向超类添加一个参数:
interface Producer<T> {
T get();
}
class NumberProducer<T extends Number> implements Producer<T> {
@Override
public T get() { return null; }
}
class IntegerProducer extends NumberProducer<Integer> { // Implicit: implements Producer<Integer>
@Override
public Integer get() { return null; }
}
接口生成器{
T get();
}
类NumberProducer实现生产者{
@凌驾
public T get(){return null;}
}
类IntegerProducer扩展NumberProducer{//Implicit:implements Producer
@凌驾
公共整数get(){return null;}
}
为什么要在IntegerProducer中实现接口?您可以在不实现接口的情况下重写get()方法。您能提供一个如何使用这些类的示例吗?我不确定,即使是让NumberProducer
通用化的常见建议也能达到您的目的。如果使用NumberProducer implements Producer
,则只能从NumberProducer.get()
返回null
,因为您不知道Number
的子类型是t
。也就是说,您不能返回newnumber()
(我知道构造函数不存在,但请原谅我),因为t
实际上可能是Integer
。问题是我想使用Producer
接口来处理与Number
不兼容的类型,例如String
。所以我不能在类型参数上加一个界限。更新了我的方法。不确定这是否是你的想法。对我来说,这听起来也有点像工厂,但在不知道您的意图的情况下,很难说。我确实理解,您代码片段中的调用p.get()
将被编译为对Producer.get()的调用对象
将由NumberProducer
实现,但是IntegerProducer
可以重写该方法,并让它调用NumberProducer.get()Integer
,所以我看不出有问题。@feuermemel在具有声明站点差异的语言中是可能的IntegerProducer.get()
将覆盖NumberProducer.get()
。然而,在Java中,它们将是重载方法,编译器只能转发给其中一个。所以这是不允许的。这就是我现在所做的,谢谢。我引入了一个SpecializableNumberProducer
,并使NumberProducer
继承自它,而不添加任何实现,只传递类型参数的Number
。这样,NumberProducer的用户就不必在每次使用时显式地将Number
作为类型参数传递。Ben Schulz的回答中有关于泛型实现的更多细节,以及是什么阻止了我的原始代码工作。
interface Producer<T> {
T get();
}
class NumberProducer<T extends Number> implements Producer<T> {
@Override
public T get() { return null; }
}
class IntegerProducer extends NumberProducer<Integer> { // Implicit: implements Producer<Integer>
@Override
public Integer get() { return null; }
}