TJRC
TJRC

Reputation: 434

Java: How do I cast a cloned object to it's original subclass?

Imagine super class A:

public class A {
    private int x;

    A(int x){
        this.x = x;
    }

    public int getX() {
        return x;
    }
}

And it's 2 subclasses B and C:

public class B extends A{
    private int y = 2;

    B(int x){
        super(x);
    }
}
public class C extends A{
    private int y = 3;

    B(int x){
        super(x);
    }
}

Now imagine a list of objects that all inherit class A. I want to iterate through that list and clone each object and also cast it to it's original subclass (B or C). This is how I tried to do that:

public static void main(String args[]) {
    ArrayList<A> aList = new ArrayList<A>();
    aList.add(new B(5));
    aList.add(new C(6));

    ArrayList<A> aClones = new ArrayList<A>();

    for(A a : aList) {
        A aNew = new A(a.getX());
        a.getClass().cast(aNew);
        aClones.add(aNew);
    }
}

But this gives me an error saying that I can't cast A to B. How am I able to achieve this without knowing up front what subtype of object I'm dealing with? I could do an if-statement inside the for loop for every type of subclass to check if a is an instance of that subclass and then simply create a new instance of that particular subclass and clone it that way. However, in my situation there will be many more subclasses than just B and C and many more might come. I don't want the for loop to contain any knowledge about the existing subclasses of A. Is this possible?

Upvotes: 0

Views: 223

Answers (3)

Makoto
Makoto

Reputation: 106400

This can't be done in the way you're writing it.

The reason is fairly simple: B and C have an is-a relationship with A, but A doesn't share the same is-a relationship with either B or C.

This is chiefly because you're trying to iterate using the superclass to describe everything.

for(A a : aList) { }

While you're iterating, you do not have any way of knowing from type inference alone what concrete class A actually is.

So this fails, as expected.

 a.getClass().cast(aNew);

Without explicitly asking the class what type it is, you have no way of doing this.

This means that you'll be writing a lot of instanceof of statements if you plan to expand upon this.

for(A a : aList) {
    if(a instanceof B) {
        B b = new B(a.getX());
        aClones.add(b);
    }
    if(a instanceof C) {
        C c = new C(a.getX());
        aClones.add(c);
    }
}

Upvotes: 1

will
will

Reputation: 358

You should clone it with the constructor of the subclass. Otherwise it will be the Type of the super class A which cannot be casted to C or B See e.g. reflection: http://tutorials.jenkov.com/java-reflection/constructors.html

Or better use the clone function. https://en.m.wikipedia.org/wiki/Clone_(Java_method)

That should be much easier.

Upvotes: 0

ControlAltDel
ControlAltDel

Reputation: 35011

You can do something like this

for(A a : aList) {
    A anew;
    if (a.getClass() == A.class) anow = new A(a.getX());
    else if (a.getClass() == B.class) anow = new B(a.getX());
    else if (...

}

Upvotes: 1

Related Questions