Question

how i can dynamic downcast objects, with out instanceof statement? I reading Bruce Eckel's Thinking in Java, and there using Class, and there is such a theme, but I was not approached P.s. Sorry for my English.

public class GenericTest {


    static private interface Base {
    }


    static private class A implements Base {
    }

    static private class B implements Base {
    }

    static private class C extends B {
    }

    private List<Class<? extends Base>> types;
    private List<Base> objects;

    public GenericTest() {
        types = new ArrayList<Class<? extends Base>>();
        types.add(A.class);
        types.add(B.class);
        types.add(C.class);

        objects = new ArrayList<Base>(Arrays.asList(new A(), new B(), new C()));

        for (Base base : objects) {
            if (base instanceof A)
                test((A) base);
            else if (base instanceof C)
                test((C) base);
            else if (base instanceof B)
                test((B) base);

            for (Class<? extends Base> c : types)
                if (base.getClass().equals(c))
                    test(c.cast(base));
        }
    }

    private void test(A a) {
        System.out.println("A");
    }

    private void test(B b) {
        System.out.println("B");
    }

    private void test(C c) {
        System.out.println("C");
    }

    private void test(Base base) {
        System.out.println("Base");
    }

    public static void main(String[] args) {
        new GenericTest();
    }
}
Was it helpful?

Solution

Sometimes, the use of instanceof indicates a flaw in your design, probably by violating some basic principals of Object Oriented Programing.

In you case, I can oversee two solutions depending on what your final goal is. The first one is to encapsulate the specific behavior of test() in the classes A, B and C. It can be done by declaring a method test() in the interface Base, making it an abstract class and implementing it in the subclasses.

static private abstract class Base {
    public void test() {
        System.out.println("Base");
    } 
}

static private class A extends Base {
    private void test() {
        System.out.println("A");
    }
}

static private class B implements Base {
    private void test() {
        System.out.println("B");
    }
}

static private class C extends B {
    private void test() {
        System.out.println("C");
    }
}

Notice that classes with an hierarchy level greater than 3 are not a good practice. Inheritance is the highest degree of coupling you can get between two objects. That is why we tend to prefer composition over inheritance.

The second way to improve your design is, as @SLaks mentioned, to use the Visitor Pattern. More about this pattern can be found here. Recommended reading on the subject are GOF and Refactoring to Patterns.

OTHER TIPS

It's not exactly clear what you would like to do, but here is how you can achieve the same result without casting and instanceof.

Put the test method on interface Base:

static private interface Base {
    public void test();
}

Then implement it:

static private class A implements Base {
    public void test() {
        System.out.println("A");

}

and similarly for B and C. Then your loop should look like this:

for (Base base : objects) {
    base.test();
}

This will result in calling A::test if base is an instance of A, B::test if base is instance of B etc. (The method is selected based on the runtime type of the referenced object).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top