简体   繁体   中英

Iterate over Java ArrayList and execute different methods depending on class

I'm relatively new to Java and would appreciate any help regarding the following inquiry. I've defined two classes - for simplicity sake, let's call them A and B . Class A has a method named methodA , and Class B has a method named methodB . The objects of these two classes are contained in an ArrayList called container . What I need to do is to loop over the ArrayList and call different methods depending on the type of object.

This is my code currently:

for (Object item : container) {
    if (item instanceof A) {
        item.methodA()
    } else if (item instanceof B) {
        item.methodB() 
    }
}

My IDE (NetBeans) won't compile the above code since item of type Object doesn't have methodA or methodB . Is there some other way to write the loop to accomplish what I need it to do? Thanks.

You need to add a cast. Just because you checked that item is an instance of A (or B) doesn't allow you to call A methods on the item.

if (item instanceof A) {
    ((A) item).methodA();
} else if (item instanceof B) {
    ((B) item).methodB();
}

In general, though, you may want to consider restructuring your code to avoid this pattern. For example, you could create a common interface of base class which both A and B implement:

public interface MyInterface { 
    void doSomething();
}

class A : MyInterface {
    ...
    public void doSomething() { this.methodA(); }
}


class B : MyInterface {
    ...
    public void doSomething() { this.methodB(); }
}

Then you could do:

List<MyInterface> list = // a list of A's and B's
for (MyInterface item : list) { 
    // use polymorphism to invoke the appropriate method
    item.doSomething(); 
}

The visitor pattern is another common solution for this type of code which is useful when you want to support a bunch of different common operations across a fixed set of classes without constantly modifying those classes.

You are dealing with the variants problem, for which Java (and pretty much any other widely-used language) has no good answer. Scala solves it with case classes, and more academic languages like ML handle it with ease.

All the above answers suggest using if-ladders and casting, which is the tersest solution in Java but which basically gives up complete compile-time safety. If you don't like casts, you can use a visitor pattern to get around the issue. It's about as verbose as you can get, but it's completely type-safe.

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();
        }
    } );
}

Just do type casting to A or B before calling method on it.Convert item into A or B before calling the method

for (Object item : container) {
    if (item instanceof A) {
       ((A) item).methodA();;
    } else if (item instanceof B) {
       ((B) item).methodB();
    }
}

Try in this way

       if (item instanceof A) {
            ((A) item).methodA();
        } else if (item instanceof B) {
            ((B) item).methodB();
        }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM