我有一个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注释暂停警告,我想遵循OO规则。
答案 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
)。不要自己重建迭代器概念。特别是在您的经理类上有begin
和next
会在那里引入不必要的状态。
使用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); } }