首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >参数化类型参数?

参数化类型参数?
EN

Stack Overflow用户
提问于 2012-02-22 01:00:59
回答 1查看 1.6K关注 0票数 4

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

代码语言:javascript
复制
/*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也可以返回SeekableByteChannels。这个库的用户在编译时就知道这一点(因为他们知道描述符的类型参数),所以我试图避免添加一个Class类型的方法参数,以便在必要时强制用户将返回的值显式地转换为SeekableByteChannel。我不知道如何让getItem返回特定的ByteChannel子类型而不强制用户进行强制转换。我想这样做:

代码语言:javascript
复制
/*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检查和转换就更容易了。

我试过这个:

代码语言:javascript
复制
/*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>有不同的类型擦除。

我也试过这样做,它编译了:

代码语言:javascript
复制
/*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>>。我做错了什么?

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

也就是说,我确定了第4块中的代码。在我的例子中,用户很难在调用ItemDescriptor时发送错误的getItem子程序,特别是因为描述符都是通过getDescriptorsArchiveContainer本身返回的!

EN

回答 1

Stack Overflow用户

发布于 2012-02-22 01:10:42

我知道这可能不是您想要听到的,但是即使Java泛型在语法上看起来像C++模板,但是它们在工作方式上有很大的不同。

在你最喜欢的搜索引擎中查找java type erasure。不幸的是,仅仅因为在编译时已知类型并不意味着该类型可以在运行时恢复,甚至在以后的编译阶段也是如此。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9387738

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档