让我们假设我想检查Object数组中的值是否属于超类或子类,例如我的超类是Called Animal,我声明了一个类型为Animal的数组
Animal myAnimals[] = new Animal[];
现在假设有像Lion,Tiger,Elephant等动物的子类。如果我要遍历数组,我如何区分子类(Lion,Tiger等)和超类Animal?谢谢!
答案 0 :(得分:6)
在运行时,如果[...],instanceof运算符的结果为true 可以将引用(第15.16节)转换为ReferenceType而不使用 引发ClassCastException。
for (Animal a : myAnimals) {
if (a instanceof Lion) System.out.println("Lion");
// etc.
}
答案 1 :(得分:1)
正如@YassinHajaj已经说过你可以使用instanceof运算符:
for (Animal animal : animals) {
if (animal instanceof Tiger) {
Tiger tiger = (Tiger) animal;
}
}
然而,这导致非结构化代码,此外这很难维护。我个人更喜欢更面向对象的方式。
正如@JBNizet在评论中建议的那样,您可以使用polymorphism。这很好但不完美:你需要改变所有动物类的实现以增加一些逻辑。
但是,如果将其与visitor pattern结合使用。这将变得非常强大,因为您可以将逻辑分成访问者类:
interface AnimalVisitor {
void visitLion(Lion lion);
void visitFish(Fish fish);
// Gets called when animal does not override the accept method:
void visitDefault(Animal animal);
}
class Animal {
public void accept(AnimalVisitor visitor) {
visitor.visitDefault(this);
}
}
class Fish extends Animal {
@Override
public void accept(AnimalVisitor visitor) {
visitor.visitFish(this);
}
}
class Lion extends Animal {
@Override
public void accept(AnimalVisitor visitor) {
visitor.visitLion(this);
}
}
然后你可以用这样的东西轻松替换你的循环:
AnimalVisitor visitor = new AnimalVisitor() {
@Override
public void visitLion(Lion lion) {
// Do something with lion
}
@Override
public void visitFish(Fish fish) {
// Do something with fish
}
}
for (Animal animal : animals) {
animal.accept(visitor);
}
我们甚至可以更进一步:
由于为每种不同类型的动物添加特定的visitAnimal
方法很烦人,我们可以使用reflection来避免这种情况!这将导致更小更清晰的代码:
interface Visitable { }
class Animal implements Visitable {
// No accept method
}
class Fish extends Animal {}
class Goldfish extends Fish {}
class Shark extends Fish {}
// Take for example this visitor:
class BittenByVisitor extends ReflectiveVisitor {
private Surfer surfer;
public BitByVisitor(surfer) {
this.surfer = surfer;
}
// We only care about the sharks:
public void visit(Shark shark) {
surfer.die();
}
// Any other fish is just the same:
public void visit(Fish fish) {
surface.decreaseHealthBy(1);
}
// It also works with interfaces:
public void visit(VerySmallFish fish) {
// Do nothing by purpose!
}
}
这里是反思访客的实施:
abstract class ReflectiveVisitor {
public void visit(Visitable v) throws NoSuchMethodException {
Method m = findMethod(v);
try {
m.invoke(this, new Object[] { v });
}
catch ( IllegalAccessException e1 ) { /* code handling */ }
catch ( InvocationTargetException e2 ) { /* code handling */ }
}
private Method findMethod(Visitable v) throws NoSuchMethodException {
String methodName = "visit";
Class visitable = v.getClass();
while ( isAncestorOf("Visitable", visitable) {
Class visitor = getClass();
while ( isAncestorOf("Visitor", visitor) {
try {
Method m = visitor.getDeclaredMethod(methodName, new Class[]{visitable});
return m;
} catch ( NoSuchMethodException e ) {
visitor = visitor.getSuperclass();
}
}
visitable = visitable.getSuperclass();
}
String errMsg = "put error message here";
throw new NoSuchMethodException(errMsg);
}
private boolean isAncestorOf(String ancestorName, Class descendant) {
try {
return Class.forName(ancestorName).isAssignableFrom(descendant);
}
catch ( ClassNotFoundException e ) { /* code handling */ }
return false;
}
}
}
源代码来自this paper。
我个人喜欢使用反射访问者来避免Visitable
课程。您可以这样定义:
class ReflectiveVisitor<T> {
public void visit(T visitable);
}
答案 2 :(得分:1)
您可以使用instanceof ..
迭代每个元素并检查子类型