我对Java还比较陌生,如果您能提供以下查询方面的帮助,我将不胜感激。我定义了两个类——为了简单起见,我们称它们为A
和B
。Class A
有一个名为methodA
的方法,而Class B
有一个名叫methodB
的方法。这两个类的对象包含在一个名为container
的ArrayList
中。我需要做的是在ArrayList
上循环,并根据对象的类型调用不同的方法。
这是我目前的代码:
for (Object item : container) {
if (item instanceof A) {
item.methodA()
} else if (item instanceof B) {
item.methodB()
}
}
我的IDE(NetBeans)不会编译上面的代码,因为Object
类型的item
没有methodA
或methodB
。有没有其他方法可以编写循环来完成我需要它做的事情?谢谢
您需要添加一个强制转换。仅仅因为您检查了该项是A(或B)的实例,就不允许您对该项调用A方法。
if (item instanceof A) {
((A) item).methodA();
} else if (item instanceof B) {
((B) item).methodB();
}
不过,一般来说,您可能需要考虑重新构建代码以避免这种模式。例如,您可以创建一个基类的公共接口,a和B都实现该接口:
public interface MyInterface {
void doSomething();
}
class A : MyInterface {
...
public void doSomething() { this.methodA(); }
}
class B : MyInterface {
...
public void doSomething() { this.methodB(); }
}
然后你可以做:
List<MyInterface> list = // a list of A's and B's
for (MyInterface item : list) {
// use polymorphism to invoke the appropriate method
item.doSomething();
}
访问者模式是这类代码的另一个常见解决方案,当您希望在一组固定的类中支持一组不同的通用操作而不不断修改这些类时,它非常有用。
您正在处理变体问题,Java(以及几乎所有其他广泛使用的语言)对此没有很好的答案。Scala通过案例类解决了这个问题,而像ML这样的更学术的语言可以轻松地处理它。
以上所有答案都建议使用if梯形图和强制转换,这是Java中最简洁的解决方案,但基本上放弃了完整的编译时安全性。如果你不喜欢演员阵容,你可以使用访问者模式来解决这个问题。它是尽可能详细的,但它是完全类型安全的。
interface ABVariantVisitor {
void visit( A a );
void visit( B b );
}
interface ABVariant {
void accept( ABVariantVisitor v );
}
class A implements ABVariant {
// ...
void accept( ABVariantVisitor v ) {
v.visit( this );
}
// ...
}
class B implements ABVariant {
// ...
void accept( ABVariantVisitor v ) {
v.visit( this );
}
// ...
}
List< ABVariant > container;
// ...
for ( ABVariant item : container ) {
item.accept( new ABVariantVisitor() {
@Override void visit( A a ) {
a.methodA();
}
@Override void visit( B b ) {
b.methodB();
}
} );
}
在调用方法之前,只需将类型转换为A或B即可。在调用方法之前,将项转换成A或B
for (Object item : container) {
if (item instanceof A) {
((A) item).methodA();;
} else if (item instanceof B) {
((B) item).methodB();
}
}
以这种方式尝试
if (item instanceof A) {
((A) item).methodA();
} else if (item instanceof B) {
((B) item).methodB();
}