我可以简化此Java Generics层次结构吗?

时间:2009-05-13 08:13:57

标签: java generics

有时在我的代码中,我想引用(我认为的)泛型层次结构中的隐式类型(基本上是第一个隐含的类型?在下面)。

public class Foo<BAR extends Bar<?>> {
  public void t(BAR x) {
    List l = new ArrayList();
    Object baz = x.makeBaz(null);
    l.add(baz);
    x.setBazList(l);
  }
}

public interface Bar<BAZ extends Number> {
  public BAZ makeBaz(Object arg1);
  public List<BAZ> getBazList();
  public void setBazList(List<BAZ> baz);
}

例如,在上面的代码中,可以替换行

    List l = new ArrayList();
    Object baz = x.makeBaz(null);

使用泛型的东西?

我宁愿避免写:

public class Foo<BAZ extends Number, BAR extends Bar<BAZ>> {
  public void t(BAR x) {
    List<BAZ> l = new ArrayList<BAZ>();
    BAZ baz = x.makeBaz(null);
    l.add(baz);
  }
}

因为强制执行任何派生类的声明会感觉不自然。

我知道上面的内容有点人为,但它比试图显示我正在查看的实际代码要简单得多。

3 个答案:

答案 0 :(得分:3)

我想主要的问题是你需要以某种方式强制你从x.makeBaz()获得的类型与你给x.setBazList(l)的列表的类型参数相同,如果你只是使用?你失去了执行能力,所以你需要一个泛型类型参数。但从某种意义上说,类型参数只需要在这几行中“本地”,而其他类不需要知道。

您可以使用类型参数BAZ来仅参数化方法而不是类:

public <BAZ extends Number> void t2(Bar<BAZ> x) {
  List<BAZ> l = new ArrayList<BAZ>();
  BAZ baz = x.makeBaz(null);
  l.add(baz);
  x.setBazList(l);
}

这用于本地化我们需要此临时类型变量BAZ的代码区域。请注意,此方法的签名实际上是public void t2(Bar<?> x),即外部不需要知道此BAZ

现在,此方法现在接受所有Bar<anything>而非BAR。如果这是一个问题,你可以“包装”上面的方法。我们没有遇到与以前相同的问题,因为所有BAZ内容都已包含在t2()中,需要Bar<anything>,因此我们可以安全地传递BAR

public void t(BAR x) {
  t2(x);
}

我同意这似乎有点迂回。也许其他人会想出更好的方法。

答案 1 :(得分:0)

您可以至少绑定到数字,因为BAZ扩展数字

public class Foo<BAR extends Bar<?>> {
    public void t(BAR x) {    
        List<Number> l = new ArrayList<Number>();
        Number baz = x.makeBaz(null);
        l.add(baz);
        // l.add(Integer.valueOf(1)); compiles but with this here the next line throws ClassCastException
        x.setBazList(l);
    }
}

public interface Bar<BAZ extends Number> {
    public BAZ makeBaz(Object arg1);
    public List<BAZ> getBazList();
    public void setBazList(List<BAZ> baz);
}

public class BarConcreate implements Bar<BigDecimal>{
    long counter = 1;

    private List<BigDecimal> list = new ArrayList<BigDecimal>();
    public List<BigDecimal> getBazList() {
        return list;
    }


    public BigDecimal makeBaz(Object arg1) {
        return BigDecimal.valueOf(counter++);
    }

    public void setBazList(List<BigDecimal> baz) {
        list = baz;         
        for(BigDecimal d : baz){
            logger.debug("value:" + d.toString());
        }
    }

}


public void TestFooBar(){
    Foo<Bar<BigDecimal>> foo = new Foo<Bar<BigDecimal>>();
    Bar<BigDecimal> bar = new BarConcreate();
    foo.t(bar);
}

这个java编译并运行,如果List只用BigDecimal填充,如果List中有一个整数,每个东西都可以工作,我们在x.setBazList(l)行上得到一个类转换异常;

我觉得非常有趣。

答案 2 :(得分:0)

如果你愿意,我会选择这个:

List<Number> l = new ArrayList<Number>();
Number baz = x.makeBaz(null);

希望这有帮助。

编辑:这也是有道理的:

public class Foo<BAR extends Bar<? extends Number>>