Java在超类方法中返回没有泛型参数的子类

时间:2014-11-11 22:39:21

标签: java generics inheritance self-reference

我真的很喜欢使用初始化程序来使构造和配置类更容易理解。基本上我更喜欢这个:

new ClassObj().StartingFrom(1).EndingAt(5).IncrementBy(1).Backwards();

而不是:

new ClassObj(1,5,1,false);

当与继承混合时,这在Java中有点痛苦,因为返回类型默认为尽可能通用。我找到了一个使用自引用继承(Java: returning subclass in superclass method signature)的可行解决方案,但我遇到了一些问题。

我的问题是Parent类实现了Iterable,但泛型类型参数丢失了,因此for-each循环想要返回一个Object而不是File。

这是一个显示行为的SSCCE:

public class SSCCE {
  private static abstract class Sentence<T extends Sentence<T>> implements Iterable<String> {
    protected LinkedList<String> Words = new LinkedList<>();

    abstract T self();

    public T Say(String word) {
      Words.add(word);
      return self();
    }

    @Override
    public Iterator<String> iterator () {
      return Words.iterator();
    }
  }

  static class QuietSentence extends Sentence<QuietSentence> {
    public QuietSentence Whisper(String word) {
      Say(word.toLowerCase());
      return this;
    }

    @Override
    QuietSentence self() {
      return this;
    }
  }

  static class LoudSentence extends Sentence<LoudSentence> {
    public LoudSentence Shout(String word) {
      return Say(word.toUpperCase());
    }

    @Override
    LoudSentence self() {
      return this;
    }
  }

  static void PrintWords(Sentence words) {
    for(Object obj : words) {
        // I'd really like to avoid this cast
        String word = (String)obj;
        System.out.println(new StringBuilder(word).append(": ").append(word.length())
                  .toString());
    }
  }

  public static void main (String[] args) {
    QuietSentence peaceful_words = new QuietSentence().Say("Hello").Whisper("World");
    PrintWords(peaceful_words);

    LoudSentence noisy_words = new LoudSentence().Say("Hello").Shout("World");
    PrintWords(noisy_words);
  }
}

发生了什么,我该如何解决?

1 个答案:

答案 0 :(得分:1)

事实证明问题是我没有正确指定类型。 PrintWords函数中的最小修复解决了这个问题。

static void PrintWords(Sentence<? extends Sentence> words) {
    for(String word : words) {
        System.out.println(new StringBuilder(word).append(": ").append(word.length())
                .toString());
    }
}