迭代List中的特定实例

时间:2014-07-10 12:07:51

标签: java class oop

我有一个ArrayList,它会占用不同类的一些实例,我想在for循环中迭代特定类型的类(例如扩展OnRender.class的类); 我有一个工作代码,但代码打破了OO规则,导致一些警告。 我可以做到这一点,或者我将永远通过向下转换来打破OO。

回顾我写的内容,我发现我没有解释得很好,所以请查看下面的代码,看看我的意思

代码

public class ListenerManager{
    List<Object> listeners=new ArrayList<Object>();
    int it;
    Class clazz;
    public <T extends Object> T begin(Class<T> clazz){
        it=-1;
        this.clazz=clazz;
        return next();
    }
    public <T extends Object> T next(){
        while((++it)<listeners.size()){
            if (clazz.isInstance(listeners.get(it))){
                return (T)listeners.get(it);
            }
        }
        return null;
    }
    public void add(Object listener){
        listeners.add(listener);
    }
}

我这样使用

ListenerManager lm=new ListenerManager();
lm.add(new OnRenderListener(){
    ........
});
for(OnRenderListener orl=lm.begin(OnRenderListener.class);orl!=null;orl=lm.next){
    .......
}

我收到的警告

Class clazz; - &gt;类是原始类型。对泛型类的引用应该参数化

return (T)listeners.get(it); - &gt;类型安全:未选中从对象转换为T

我不想仅使用Suspecnd注释暂停警告,我想遵循O​​O规则。

4 个答案:

答案 0 :(得分:3)

如果要识别特定的类或接口,请使用 instanceof

for (Object o : listeners) {
   if (o instanceof X) {
      X x = (X)o;
   }
}

然而,这并不是很好。你真的想利用语言的继承和多态。我的第一个想法是,您的列表应仅为容器Listeners或子类型,例如

listeners = new ArrayList<Listener>();

然后你不需要演员表。从列表中提取的所有内容都将是一个监听器(或子类型),并按此类型输入:

for (Listener l : listeners) {
   // listener type functionality here...
}

Visitor pattern也是一个选项。您可以将访问者对象传递给每个侦听器,每个侦听器将根据其类型决定要执行的操作。优点是,当您添加子类型时,您必须添加适当的方法 - 不存在从类声明序列中省略类型的危险。

Visitor v = new OnlyInterestedInOneTypeOfListener();
for (Listener l : listeners) {
   l.useVisitor(v);  // different subclasses will call different methods
                     // on the visitor. Some may be no-ops for different visitor
                     // implementations
}

(顺便说一句,我注意到你想要发现实现特定方法的条目。这称为duck-typing,而Java不支持它。其他语言如Scala可以)

答案 1 :(得分:2)

您可以使用Guava的Iterables.filter()方法。它只会迭代你想要的子类型。

for (YourType filteredElement : Iterables.filter(listeners, YourType.class)) {
    doSomething(filteredElement);
}

答案 2 :(得分:1)

您的ListenerManager应该返回java Iterator或已过滤的Collection(或List)。不要自己重建迭代器概念。特别是在您的经理类上有beginnext会在那里引入不必要的状态。

使用Java 8,您的ListenerManager可以很容易地写为:

public class ListenerManager {
    private final List<Object> listeners = new ArrayList<Object>();

    public <T> Collection<T> listenersOf(Class<T> type) {
        return listeners.stream()
            .filter(type::isInstance)
            .map(type::cast)
            .collect(Collectors.toList());
    }

    public void add(Object listener) {
        listeners.add(listener);
    }
}

如果您使用的是8之前的Java版本,请使用旧的for-each代替:

public <T> Collection<T> listenersOf(Class<T> type) {
    List<T> result = new ArrayList<T>();
    for (Object l : listeners) {
        if (type.isInstance(l)) result.add(type.cast(l));
    }
    return result;
}

答案 3 :(得分:0)

这只是一种粗略的(不可编译的)我会这样做的方式


    public interface Listener{
        public boolean canHandle(Event ev);
        public void handle(Event ev);
    }

    public class OnRenderListener implements Listener {

        public boolean canHandle(Event ev){
            return ev instanceOf OnRenderEvent; // or look for the classname
        }
        public void handle(Event ev);
    }

    public class KeyPressListener implements Listener {

        public boolean canHandle(Event ev){
            return ev instanceOf KeyPressEvent; // or look for the classname
        }
        public void handle(Event ev){
            keyPressed(((KeyPressEvent)ev).getKey());
        }
        keyPressed(int key){....}
    }



    public class Event{}
    public class KeyPressEvent extends Event{
        int key;
    }

    public class OnRenderEvent extends Event{
        //other stuff
    }

    //Loop to fire an event
    for(Listener lis : listeners){
        if(lis.canHandle(currentEvent){
            lis.handle(currentEvent);
        }
    }