【问题标题】:Why does this not work while this does ? (Java Generics, named generic type vs. unnamed)为什么这不起作用而这不起作用? (Java 泛型,命名的泛型类型与未命名的类型)
【发布时间】:2016-01-26 15:55:45
【问题描述】:

很抱歉,除了举个例子,我不知道如何用另一种方式表达我的问题:

public interface IStuff<GenericParameter>{}

public interface IWorkWithStuff<GenericParameter>
{
    void doSomethingWithStuff(IStuff<GenericParameter> stuff);
}

public interface IBoth<GenericParameter>
extends IStuff<GenericParameter>, IWorkWithStuff<GenericParameter>
{}

public class Test<Both extends IBoth<?>>
{
    Both _myBoth;
    void test(final Both otherBoth)
    {
        _myBoth.doSomethingWithStuff(otherBoth);
    }
}

这不编译,有人可以解释为什么吗? 错误是:

IWorkWithStuff 类型中的方法 doSomethingWithStuff(IStuff) 不适用于参数(Both)

另一方面,如果我为参数命名,它会起作用

public class Test<NamedParameter, Both extends IBoth<NamedParameter>>
{
    Both _myBoth;
    void test(final Both otherBoth)
    {
        _myBoth.doSomethingWithStuff(otherBoth);
    }
}

这似乎与我非常相似(除了第二种解决方案在我遇到此问题的实际情况下对我来说不可行),有人可以解释这有何不同

非常感谢!


我补充说我用 Java 1.6 和 Java 1.8 测试过

编辑

awsome 的回答给了我解决方案

the link he pointed 中有一个部分名称"Capture helpers" 解释了避免此类问题的方法。

就我而言,这段代码有效:

public class WorkingTest<Both extends IBoth<?>>
{
    Both _myBoth;

    void test(final Both otherBoth)
    {
        final IBoth<?> myBoth = _myBoth;
        final IBoth<?> _otherBoth = otherBoth;
        rebox(myBoth, _otherBoth);
    }

    protected <Something, SomethingElse> void rebox(final IBoth<Something> both, final IBoth<SomethingElse> otherBoth)
    {
        both.doSomethingWithStuff(both);
    }
}

当类型有效时有效,当类型无效时失败。

谢谢!

编辑

糟糕,我的“解决方案”有一个错误:

我写的

        both.doSomethingWithStuff(both);

而不是

        both.doSomethingWithStuff(otherBoth);

这不起作用(并且有意义)。

我现在找到的唯一解决方案是使用 cast :

public class WorkingTest<Both extends IBoth<?>>
{
    Both _myBoth;

    public WorkingTest(final Both myBoth)
    {
        _myBoth = myBoth;
    }

    void test(final Both otherBoth)
    {
        deboxrebox(_myBoth, otherBoth);
    }

    @SuppressWarnings("unchecked")
    protected <CommonParent> void deboxrebox(final Both first, final Both second)
    {
        final IBoth<CommonParent> _first = (IBoth<CommonParent>) first;
        final IBoth<CommonParent> _second = (IBoth<CommonParent>) second;
        _first.doSomethingWithStuff(_second);
    }
}

至少,它封装了演员阵容,但仍然不是很令人满意

您认为使用“捕获助手”可以找到更好的解决方案吗?

【问题讨论】:

  • Test> 什么是Both?
  • @rajuGT 貌似是泛型参数的名称;请注意,Test 本身就是一个泛型类型。

标签: java generics type-erasure


【解决方案1】:

这里对您的示例进行了一些修改,以了解您面临的问题

    public class Test<Both extends IBoth<?>> {

    IBoth<?> hello;

    void test(final Both otherBoth) {
        hello.doSomethingWithStuff(hello);  // The method doSomethingWithStuff(IStuff<capture#1-of ?>) in the type IWorkWithStuff<capture#1-of ?> is not applicable for the arguments (IBoth<capture#2-of ?>)
        hello.doSomethingWithStuff(hello); // The method doSomethingWithStuff(IStuff<capture#3-of ?>) in the type IWorkWithStuff<capture#3-of ?> is not applicable for the arguments (IBoth<capture#4-of ?>)
    }
}

interface IStuff<S> {
}

interface IWorkWithStuff<T> {
    void doSomethingWithStuff(IStuff<T> stuff);
}

interface IBoth<U> extends IStuff<U>, IWorkWithStuff<U> {
}

我还用 doSomethingWithStuff 的方法调用编写了错误。您会看到每次进行新呼叫时 capture#xxx 都会发生变化。这里的数字 xxx 表示这是一种新的未知类型。 更多关于通配符的信息可以在这里阅读http://www.ibm.com/developerworks/java/library/j-jtp04298/index.html

【讨论】:

  • 非常有趣!它也给了我一个解决方案,链接文章中的重新装箱一章。我会在问题中详细说明。非常感谢!
  • 糟糕,对不起,我的“解决方案”实际上有一个错误。请参阅问题中的编辑。
【解决方案2】:

区别在于你指定时的类型?它是一种通配符,而如果您要指定 Test 扩展的类的类型是预定义的,即在编译时提到,因为 java 在编译时检查类型。在您的第一次尝试中,未定义类型。因此它显示错误。

以下链接还包含对泛型的很好解释。

Check the meaning of ?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多