Java: If abstract class Foo returns Object, can concrete class Bar return String or Integer?

StackOverflow https://stackoverflow.com/questions/22545933

سؤال

I have a Java enum with an abstract class, like this:

public enum Strategy {
    STRING {
        @Override
        public String execute() {
            return "ABCDE";
        }
    },
    INTEGER {
        @Override
        public Integer execute() {
            return 12345;
        }
    };
    public abstract Object execute();
}

When I use it, I expect to be able to do this:

String text = Strategy.STRING.execute();
Integer num = Strategy.INTEGER.execute();

However, my IDE warns me that these are incompatible types and won't compile. To resolve it, I have to instead do this:

String text = (String) Strategy.STRING.execute();
Integer num = (Integer) Strategy.INTEGER.execute();

I'd rather not have to cast the results of my execute() methods. Is there any way to return the type specified in the concrete method signature, rather than returning Object?

هل كانت مفيدة؟

المحلول

When you override a method, the subclass method can be declared to return a refinement of the superclass return type. However, code that calls the superclass method has no way of knowing what the actual type is of the returned object. In your case, all it knows is that it's an Object of some sort. That's why you have to cast it before assigning to a more specific variable.

Enum objects are a little weird. When you compile this code:

Strategy.STRING.execute();

the compiler generates this bytecode (output from javap -c):

getstatic     #2 // Field Strategy.STRING:LStrategy;
invokevirtual #3 // Method Strategy.execute:()Ljava/lang/Object;

As you can see, it treats Strategy.STRING as a static field of class Strategy, and that field is of type Strategy. Thus, despite appearances, the calling code doesn't know that it's calling the STRING version of execute().

I wonder, though, why you would want to do all this. Designing an API that requires a cast seems contrary to the spirit of object-oriented programming.

نصائح أخرى

Your enum constants are compiled to static fields. Something like

public static final Strategy INTEGER = new Strategy() {
    @Override
    public Integer execute() {
        return 12345;
    }
};

Because they are simply Strategy references, you only have access to the Strategy 'interface' which declares the execute() method as returning an Object.

So, no, you won't be able to get it to do

Integer num = Strategy.INTEGER.execute();

in this way.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top