Java Generics - 使用上限和下限通配符迭代

时间:2014-08-28 11:00:51

标签: java generics

我有 2接口

public interface Flash { public void flash(int level); }

public interface SuperFlash extends Flash { public void flash(int level, boolean repeat); }

然后我有一个自定义集合类,它应该包含任意数量的实现FlashSuperFlash的东西。 类声明类似于

public class FlashyThings<? extends Flash>

因此,类可以包含类型Flash及其子类型的实例。

在课程FlashyThings中,我使用 ArrayList 来保存所有这些对象:

private ArrayList<? extends Flash> things;

到目前为止一切顺利,现在,当我尝试迭代集合时,有没有办法知道/推断对象的动态类型而不使用instanceof(如下一个片段)?

for (Flash f : this.things) {
    if (f instanceof SuperFlash) { // <-- :(
        // SuperFlash things
    } else {
        // Flash things
    }
}  

这是奖牌的上限,现在是下边界

首先,我必须将类声明更改为

public class FlashyThings

因为类声明中不允许使用较低的有界通配符。 ArrayList 声明现在看起来像:

private ArrayList<? super SuperFlash> things;

现在迭代整个集合变为:

for (Object o : this.things) { // <-- :((
    // All things are of type Object which is *really* not cool
    if (o instanceof SuperFlash) { // <-- :(
        // SuperFlash things
    } else {
        // Flash things
    }
}

所以我几乎陷入了我开始的地方。

迭代这样一个构造的推荐方法是什么?总而言之,我想要实现的目标是

  • 最顶层描述的界面层次结构
  • FlashyThings是可参数化的
  • 迭代ArrayList things,考虑其内容的动态类型(无需进行instanceof检查)

3 个答案:

答案 0 :(得分:2)

你需要做的是创建一个抽象的FlashyThing,它在抽象类中尽可能多地执行共享方法,只留下依赖于知道你有子类的Flash或SuperFlash的东西。例如(为简洁而遗漏的公众和私人):

abstract class AbstractFlashyThing<F extends Flash> {

    List<F> flashes;

    AbstractFlashyThing() {
        flashes = new ArrayList<F>();
    }

    void doOperations() {
        for (F flash : flashes) {
            doOperation(flash);
        }
    }

    abstract void doOperation(F flash);

}

请注意通用类型F如何尽可能用作占位符。

示例子类

class SuperFlashyThing extends AbstractFlashyThing<SuperFlash> {
    @Override
    void doOperation(SuperFlash superFlash) {
        // do super flash stuff
    }
}

子类是一个具体的实现而不是泛型类,因此它的实例如下。

SuperFlashyThing thing = new SuperFlashyThing();
// as opposed to the following
SuperFlashyThing<SuperFlash> thing = new SuperFlashyThing<SuperFlash>();

答案 1 :(得分:0)

也许我不太了解这个问题,但为什么你要把一切变得如此复杂,而不仅仅是使用多态?这就是面向对象范式的目的。例如:

<强> Flash.java

public class Flash {
    public void doSomething() {
        System.out.println("Flash doSomething()");
    }
}

<强> SuperFlash.java

public class SuperFlash extends Flash {
    @Override
    public void doSomething() {
        System.out.println("SuperFlash doSomething()");
    }
}

<强> FlashyThings.java

public class FlashyThings {
    private ArrayList<Flash> things = new ArrayList<>();

    public ArrayList<Flash> getThings() {
        return things;
    }

    public void doSomething(){
        for (Flash thing : things) {
            thing.doSomething();
        }
    }
}

<强> ExampleMain.java

public class ExampleMain {
    public static void main(String[] args) {
        Flash first = new Flash();
        SuperFlash second = new SuperFlash();
        Flash third = new Flash();

        FlashyThings things = new FlashyThings();
        things.getThings().add(first);
        things.getThings().add(second);
        things.getThings().add(third);

        things.doSomething();
    }
}

答案 2 :(得分:0)

如何使用enum

public enum FlashType
{
    Flash, SuperFlash;  
}

添加一种方法,用于检查Flash类型的任何对象的闪存类型:

public interface Flash 
{
    void flash(int level);
    FlashType getType();

}

然后迭代private ArrayList<? extends Flash> things;

for (Flash f : this.things)
{
    if (f.getType() == FlashType.SuperFlash)
    {
     // SuperFlash things
    }
    else if (f.getType() == FlashType.Flash)
    {
      // Flash things
    }
}  

或迭代ArrayList<? super SuperFlash> things;

for (Object o : this.things) 
{

    final Flash f = (Flash)o;//this cannot failed: SuperFlash extends Flash

    if (f.getType() == FlashType.SuperFlash)
    {
     // SuperFlash things
    }
    else if (f.getType() == FlashType.Flash)
    {
      // Flash things
    }
}