Search code examples
javagenericscasting

How to automatically downcast classes in java?


How would you automatically downcast in Java?

Look at this example:

public class Parent {}

public class Boy extends Parent {}

public class Girl extends Parent {}

Parent father = new Boy();
Parent mother = new Girl();

Boy kid = (Boy)father;
Girl kiddette = (Girl)mother;

I know I can downcast manually like in example above, but, how would I do it automatically?

So, what I want is a autocast method, something like this:

public ? downcast(? parent) { return ? parent; }

which I would use like this:

Boy kid = downcast(father);
Girl kiddette = downcast(mother);

So, I do not want to perform any explicit casting in the caller's method. I need downcast to hide the casting within itself. Preferrably, I would like to avoid type checks (instanceof) within the downcast method, so, if downcasting can be generalized, that would be great.

What do I need to place instead of ?, ? and ? to make it work.

I remember that I did this exact same thing 10 or so years ago in Java, and I remember that I was puzzled by the code, but it worked and I did not understand how it works just that it does, but I did not need to do this thing in Java again in the last 10 years, so I forgot what I did. And I remember that I managed to solve it without type checks. So, one line of code that worked for no matter how many child classes parent class had.


Solution

  • You can abuse generics to achieve something like this:

    private static <F, T extends F> T cast(F value) {
        return (T) value;
    }
    

    Now you can do

    Parent father = new Boy();
    Parent mother = new Girl();
    Boy kid = cast(father);
    Girl kiddette = cast(mother);
    

    This works because the compiler infers the target type from the kid variables. It's also dangerous, as evidenced by the generated warning on (T) value: "Unchecked cast: 'F' to 'T'". In general, you don't want to do this. All you are doing is tricking the compiler into casts that normally wouldn't be allowed.