【问题标题】:Java generics - parameterized class vs. typed methodJava 泛型 - 参数化类与类型化方法
【发布时间】:2015-04-04 09:06:56
【问题描述】:

我猜这是一个重复的问题,但是在浏览了大量相关问题后,我找不到匹配的问题......是的,蹩脚的借口;)

我目前正在为POIs HSLF/XSLF 实现开发一个通用接口。 使用泛型的原因是为了支持Iterable接口,用户代码不需要向下转换到具体的实现,即可以决定是使用实现类还是通用接口。 当然,如果没有泛型,返回类型缩小会按预期工作。

我的目标是尽量减少类用户的参数声明 - 请参阅 main 方法。在内部,泛型引用可能更复杂。

所以我想要这样的东西: (为简单起见,我没有使用Iterable接口,而是使用了不同类型的参数)

/* 更新:向类添加静态并删除空定义以实际运行示例 */

public class GenericsTest {
    static interface SlideShow {}
    static class HSLFSlideShow implements SlideShow {}

    static interface Notes<SS extends SlideShow> {}
    static class HSLFNotes implements Notes<HSLFSlideShow> {}

    static interface Slide<SS extends SlideShow> {
        <N extends Notes<SS>> N getNotes();
        <N extends Notes<SS>> void setNotes(N n);
    }

    // compile errors
    static class HSLFSlide implements Slide<HSLFSlideShow> {
        HSLFNotes notes = new HSLFNotes();

        @Override
        public HSLFNotes getNotes() { return notes; }
        @Override
        public void setNotes(HSLFNotes n) { notes = n; }
    }

    public static void main(String[] args) {
        HSLFSlide s = new HSLFSlide();
        HSLFNotes n = s.getNotes();
        s.setNotes(n);

        Slide<HSLFSlideShow> s2 = new HSLFSlide();
        Notes<HSLFSlideShow> n2 = s2.getNotes();
    }
}

我可以让它工作......但这似乎有点笨拙:

    static interface Slide<SS extends SlideShow, N extends Notes<SS>> {
        N getNotes();
        void setNotes(N n);
    }

    static class HSLFSlide implements Slide<HSLFSlideShow,HSLFNotes> {
        HSLFNotes notes = new HSLFNotes();

        @Override
        public HSLFNotes getNotes() { return notes; }
        @Override
        public void setNotes(HSLFNotes n) { notes = n; }
    }

    public static void main(String[] args) {
        HSLFSlide s = new HSLFSlide();
        HSLFNotes n = s.getNotes();
        s.setNotes(n);

        Slide<HSLFSlideShow,HSLFNotes> s2 = new HSLFSlide();
        Notes<HSLFSlideShow> n2 = s2.getNotes();
    }

你会如何最小化main方法中需要的类型参数(最低是JDK6)?

【问题讨论】:

  • 我相信你不能,至少只要你希望它是类型安全的。 Java 中的类型系统相当冗长,遗憾的是不如其他一些语言中的类型系统灵活。这是因为 Java 泛型是后来添加的,并且提供向后兼容性对语言设计者很重要。

标签: java generics inheritance apache-poi parameterized-types


【解决方案1】:

据我所知,这里没有理由使用泛型方法。用非泛型方法覆盖泛型方法可能不会像您认为的那样做。我已经讨论过这个herehere。 (另见generic methods tutorial。)

泛型方法的类型由调用站点决定。出于向后兼容的原因,允许将其覆盖为非泛型。仍然可以出现并执行以下操作:

HSLFSlide slide = ...;
Slide<HSLFSlideShow> oops = slide;

// perfectly legal
// probably throws a ClassCastException somewhere
oops.<SomeOtherNotes>set(new SomeOtherNotes());

例如,泛型方法让我们定义一个返回其接受的相同类型的方法:

static <T> T pass(T t) { return t; }

String s = pass("abc");
Double d = pass(3.14d);

这就是泛型方法的用处。

一种更典型的方式来做你想做的事情如下:

interface Slide<SS extends SlideShow> {
    Notes<SS> getNotes();
    void setNotes(Notes<SS> n);
}

class HSLFSlide implements Slide<HSLFSlideShow> {
    Notes<HSLFSlideShow> notes = new HSLFNotes();

    @Override
    public Notes<HSLFSlideShow> getNotes() { return notes; }
    @Override
    public void setNotes(Notes<HSLFSlideShow> n) { notes = n; }
}

如果有一些要求notes的引用类型不能是接口,你应该再看看你的设计。例如,HSLFNotes 实现可能具有应该移动到Notes 接口的功能。

另一种方式如下:

interface Slide<N extends Notes<?>> {
    N getNotes();
    void setNotes(N n);
}

class HSLFSlide implements Slide<HSLFNotes> {
    HSLFNotes notes = new HSLFNotes();

    @Override
    public HSLFNotes getNotes() { return notes; }
    @Override
    public void setNotes(HSLFNotes n) { notes = n; }
}

还有来自问题的工作示例:

interface Slide<SS extends SlideShow, N extends Notes<SS>> {…}
class HSLFSlide implements Slide<HSLFSlideShow, HSLFNotes> {…}

其实挺好的。

【讨论】:

  • 首先,非常感谢你——你的回答/链接让我对泛型有了更多的了解,我仍然时不时地遇到一些理解问题......@“完全合法”:我'已经认为这样的事情是可能的,但我不知道语法。我想最后我必须决定,我想在多大程度上是类型安全的......
  • @"这里没有理由使用泛型方法":是的,我已经尝试删除所有泛型声明,但它们不知何故又开始蔓延,也许我牺牲了 list/iterable-handling并返回数组...完成后,我将查看用户代码并确定它看起来有多可怕;)@“典型方式”:将有特定于实现的方法,我不希望用户当他决定处理实现参考时,对参考进行贬低
  • @"另一种方式/工作示例":当我想安全起见时,我认为工作示例是最好的,它锁定了混合实现的可能性
【解决方案2】:

虽然这似乎是一个答案,但请随意添加另一个替代方案:

public class GenericsTest {
    static interface SlideShow {}
    static class HSLFSlideShow implements SlideShow {}

    static interface Notes<SS extends SlideShow> {}
    static class HSLFNotes implements Notes<HSLFSlideShow> {}

    static interface Slide<SS extends SlideShow> {
        <N extends Notes<SS>> N getNotes();
        <N extends Notes<SS>> void setNotes(N n);
    }

    static class HSLFSlide implements Slide<HSLFSlideShow> {
        HSLFNotes notes = new HSLFNotes();

        @SuppressWarnings("unchecked")
        @Override
        public HSLFNotes getNotes() {
            return notes;
        }

        @Override
        public <N extends Notes<HSLFSlideShow>> void setNotes(N n) {
            notes = (HSLFNotes)n;
        }
    }

    public static void main(String[] args) {
        HSLFSlide s = new HSLFSlide();
        HSLFNotes n = s.getNotes();
        s.setNotes(n);

        Slide<HSLFSlideShow> s2 = new HSLFSlide();
        Notes<HSLFSlideShow> n2 = s2.getNotes();
    }
}

【讨论】:

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