【问题标题】:How to avoid (bounded) wildcard in return parameter如何在返回参数中避免(有界)通配符
【发布时间】:2018-11-23 08:26:58
【问题描述】:

我有一个接口,其方法返回一个带有有界通配符的不可变集合。

public interface Foo {
    Set<? extends Bar> getAllBar();
}

public interface Bar {
    String getBar();
}

一个实现该接口的抽象类以及几个在不覆盖方法的情况下扩展它的具体类:

abstract class AbstractFoo implements Foo {
    public Set<? extends Bar> getAllBar() {
        return Collections.emptySet();
    }
}

以及一个扩展抽象类的具体类,覆盖getAllBar,缩小通配符:

public class FooImpl extends AbstractFoo {
    public Set<BarImpl> getAllBar() {
        return Collections.singleton(new BarImpl());
    }
}

public class BarImpl implements Bar {
    public String getBar() {
        return "Bar";
    }

    /**
     * additional BarImpl method
     */
    public boolean isWee() {
        return true;
    }
}

调用代码通常会将返回的集合的项作为 Bar 进行迭代,但一些调用类,知道 FooImpl 期望 BarImpl 的集合能够调用 isWee()

class Zap {
    private FooImpl foo;

    boolean hasAnyWee() {
        return foo.getAllBar().stream().anyMatch(BarImpl::isWee);
    }
}

当然,现在 SonarQube 抱怨返回类型中的通配符 (https://jira.sonarsource.com/browse/RSPEC-1452)

但在我的情况下有那么错吗?

我怎么可能避免这种情况?

【问题讨论】:

    标签: java return-type bounded-wildcard


    【解决方案1】:

    使接口本身通用:

    public interface Foo<T extends Bar> {
        Set<T> getAllBar();
    }
    

    现在你可以拥有

    public class EmptyFoo implements Foo<BarImpl> {
        public Set<BarImpl>() { return Collections.emptySet(); }
    }
    

    【讨论】:

    • 确实这将是显而易见的方法,但是我不能做诸如“AbsractFoo 实现 Foo”然后“FooImpl 扩展 AbstractFoo 实现 Foo”之类的事情。它不会编译。
    • @PierreMarechal 不,但你可以先AbstractFoo&lt;T extends Bar&gt; implements Foo&lt;T&gt;然后FooImpl extends AbstractFoo&lt;BarImpl&gt;
    • 你是对的,我明白你的意思。但是在我的类层次结构中传播类型参数如何优于单个方法的返回类型中的有界通配符?
    • @PierreMaréchal 泛型旨在实现抽象行为。如果您觉得它污染了您的类层次结构,我会说这有点代码味道,如果您的层次结构太深,您可能需要重新考虑。毕竟,更喜欢组合而不是继承。
    猜你喜欢
    • 1970-01-01
    • 2015-04-23
    • 1970-01-01
    • 2018-10-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-15
    • 2019-02-18
    相关资源
    最近更新 更多