我正在尝试使用一个容器创建库,该容器根据传递的描述符释放其包含的对象的实例。我想让描述符确定返回对象的类型,但描述符可以指定有界类型。我该如何实施?例如,我能得到的最接近的是:
/*Block 1 - First Attempt. Compiles, but forces user to cast*/
interface ItemDescriptor<I> {
Class<? extends I> getType();
}
interface ArchiveContainer<I, D extends ItemDescriptor<? extends I>> {
Iterable<? extends D> getDescriptors();
I getItem(D descriptor);
}
//Implementations
class ChannelItemDescriptor<I extends ByteChannel> implements ItemDescriptor<I>
{
final Class<? extends I> type;
ChannelItemDescriptor(Class<I> type) {
this.type = type;
}
@Override Class<? extends I> getType() {return type;}
}
class ChannelArchive implements ArchiveContainer<ByteChannel, ChannelItemDescriptor<? extends ByteChannel>> {
@Override ByteChannel getItem(ChannelItemDescriptor<? extends ByteChannel> descriptor) {...}
}
上面的代码可以编译,但问题是ChannelArchive
'sgetItem
也可以返回SeekableByteChannel
s。这个库的用户在编译时就知道这一点(因为他们知道描述符的类型参数),所以我试图避免添加一个类型的方法参数Class
来强制用户在必要时显式地转换返回的值SeekableByteChannel
。我不知道如何在不强制用户强制转换的情况下getItem
返回特定的子类型。ByteChannel
我想做这个:
/*Block 2 - Test code*/
ChannelArchive archive = ...;
ChannelItemDescriptor<SeekableByteChannel> desc = ...;
ChannelItemDescriptor<ByteChannel> otherDesc = ...;
SeekableByteChannel sbc = archive.getItem(desc);
SeekableByteChannel sbc = archive.getItem(otherDesc); //Should fail to compile, or compile with warning
ByteChannel bc = archive.getItem(otherDesc);
我可以为每个方法添加一个Class<? extends I>
参数,但是该方法的代码将完全忽略Class
方法参数!它的唯一目的是帮助编译器推断类型。我认为它只是混淆了代码,以至于让用户使用instanceof
检查和强制转换会更容易。
我试过这个:
/*Block 3 - Failed attempt.*/
class ChannelArchive implements ArchiveContainer<ByteChannel, ChannelItemDescriptor<? extends ByteChannel>> {
//Won't compile, getItem doesn't override
@Override <II extends ByteChannel> II getItem(ChannelItemDescriptor<II> descriptor) {...}
}
但这不起作用: ChannelArchive is not abstract and does not override abstract method getItem(ChannelItemDescriptor<? extends ByteChannel>) in ArchiveContainer
。我认为这是因为第二个类型参数<II extends ByteChannel>
的类型擦除与<? extends ByteChannel>
?
我也试过这个,它编译:
/*Block 4 - Almost specific enough*/
interface ArchiveContainer<I, D extends ItemDescriptor<? extends I>> {
Iterable<? extends D> getDescriptors();
<II extends I, DD extends ItemDescriptor<II>> II getItem(DD descriptor);
}
class ChannelArchive implements ArchiveContainer<ByteChannel, ChannelItemDescriptor<? extends ByteChannel>> {
@Override <II extends ByteChannel, DD extends ItemDescriptor<II>> II getItem(DD descriptor) {...}
}
即使它可以编译,它也不会真正起作用,因为我需要ChannelItemDescriptor
在该方法内部,并且生成的强制转换会破坏使用泛型的附加类型安全的目的。
我不明白为什么我不能这样做,因为在编译时就知道正确的类型。我在该ArchiveContainer
接口上真正需要的是参数化类型参数,例如:<II extends I, DD extends D<II>>
. 我究竟做错了什么?
注意:我实际上并没有使用ByteChannel
and SeekableByteChannel
,但我使用的是非常相似的。
这就是 ruakh,我确定了第 4 块中的代码。在我的情况下,用户极不可能在对ItemDescriptor
a 的调用中发送错误的子类getItem
,尤其是因为描述符都是ArchiveContainer
通过自身返回的getDescriptors
!