java - 参数化类型参数?

标签 java generics nested-generics

我正在尝试使用容器创建库,该容器根据传递的描述符释放其包含对象的实例。我想让描述符确定返回对象的类型,但描述符可以指定有界类型。我该如何实现?例如,我能得到的最接近的是:

/*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) {...}
}

上面的代码可以编译,但是问题是ChannelArchivegetItem可以回SeekableByteChannel也是。这个库的用户在编译时知道这一点(因为他们知道描述符的类型参数),所以我试图避免添加 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接口(interface)是参数化类型参数,如:<II extends I, DD extends D<II>> .我做错了什么?

注意:我实际上并没有使用 ByteChannelSeekableByteChannel , 但我使用的是非常相似的。


这就是 ruakh,我选择了 block 4 中的代码。在我的例子中,用户发送错误的 ItemDescriptor 子类的可能性很小。在调用 getItem ,特别是因为描述符都是从 ArchiveContainer 返回的本身通过 getDescriptors !

最佳答案

我认为这段代码(几乎?)与您的第三次尝试相同,与您将获得的一样好:

// in ArchiveContainer:
<II extends I, DD extends ItemDescriptor<II>> II getItem(DD descriptor);

// in ChannelArchive:
public <II extends ByteChannel, DD extends ItemDescriptor<II>>
    II getItem(DD descriptor)
    { ... }

泛型确实提供了一种方法来声明具有两个独立上限的类型变量:

public <T extends Foo & Bar> Foo fooBar(T t) { ... }

但显然,当上限之一是类型参数而不是类或接口(interface)时,这是不允许的:

Type variables have an optional bound, T & I1 ... In. The bound consists of either a type variable, or a class or interface type T possibly followed by further interface types I1 , ..., In. […] It is a compile-time error if any of the types I1 ... In is a class type or type variable. [link]

(强调我的)。我不知道这是为什么。

不过我觉得这应该不是什么大问题。请注意,即使在 Map 之后被泛化为 Map<K,V> , 它的 get方法仍然采用类型 Object .当然,该方法将始终返回 null如果你传入一个对非 K 类型的对象的引用(因为这样的对象永远不应该插入到 map 中),但这不会损害类型安全。

关于java - 参数化类型参数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9387738/

相关文章:

Swift - 我可以实现对类的相互泛型引用吗?

java - Java 中的级联泛型类型声明

c# - 请帮助我理解在 C# 中使用泛型时的多态性

java - 是否有用于创建 XHTML 文档的 Java API?

oop - 使用泛型参数覆盖Dart方法

java - 子类变量没有隐藏父类(super class)中的变量

java - Stream 在没有过滤器(谓词)的情况下工作,使用它给出 "Incompatible types"

Java 泛型 - 方法签名的上限

java - 三重 DES Java 不工作

java - 如何仅打印数组中具有重复字符的单词?