为什么这不起作用呢? (Java泛型,命名为泛型类型与未命名)

时间:2015-10-27 09:49:33

标签: java generics type-erasure

我很抱歉,但我不知道如何以另一种方式表达我的问题,而不是通过展示一个例子:

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)方法不适用于参数(两者)

另一方面,如果我为参数命名,则可以

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);
    }
}

当类型有效时它起作用,而当类型不起作用时它失败。

谢谢!

修改

Wooops,我的“解决方案”中存在错误:

我写了

        both.doSomethingWithStuff(both);

而不是

        both.doSomethingWithStuff(otherBoth);

哪个不起作用(并且有效)。

我现在找到的唯一解决方案是使用强制转换:

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);
    }
}

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

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

2 个答案:

答案 0 :(得分: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的方法调用编写了错误。您会看到每次进行新的呼叫时,捕获#xxx都会发生变化。这里的数字xxx表示这是一种新的未知类型。  有关通配符的更多信息,请参阅http://www.ibm.com/developerworks/java/library/j-jtp04298/index.html

答案 1 :(得分:0)

您指定的类型之间的区别是什么?它是一种外卡,如果你指定了一个类,Test正在扩展,它是预定义的,即在编译时提到的,因为java在编译时检查类型。在您的第一次尝试中,未定义类型。因此它显示错误。

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

Check the meaning of ?