Different return types of abstract method in java without casting

23,050

Solution 1

In your example, classes C and D will not compile. The overridden methods in them violate the Liskov substitution principle, aka, their return type is incompatible with their parent class. What you are looking to do can be accomplished with generics, as long as you are willing to forego the use of primitives as your return type.

abstract class A<T> {
    public abstract T getValue(String content);
}

class B extends A<String> {
    public String getValue(String content) { }
}

class C extends A<Integer> {
    public Integer getValue(String content) { }
}

class D extends A<Boolean> {
    public Boolean getValue(String content) { }
}

Solution 2

What you describe is not possible in general. However, if the subclass returns a "narrower" subtype of the superclass method return, this is called a "covariant return type" and is allowed in Java since JDK 1.5. However, based on your example I do not think covariant return is what you are looking for.

I assume what you want is

for (A a : allAs)
{
    String b = a.getValue();
    int    c = a.getValue();
}

The problem here is, of course, that the compiler has no way of knowing at compile time which of those two statements is correct, and they can't both be correct.

Solution 3

You could use generics.

public abstract class A<T> {
   public abstract T getValue(String content);
}

public class B extends A<String> {
   public String getValue(String content) {...}
}

etc... int doesn't work as a return type for this, but Integer would.

I'm not typing at a compiler so there may be typos...

As noted by Jim and Chris, if you are looping over As, you can only get the "A" result, which is Object.

Solution 4

In your example, the definition of class B is ok, since String is a subclass of Object. The other two wont compile, since they are primitive types. You could replace them with Integer and Boolean returns to resolve that though.

As for your main loop, if you're iterating over them as references to A, you'll only be able to use A's definition of the method, which returns Object.

Share:
23,050
erwingun2010
Author by

erwingun2010

Updated on February 23, 2020

Comments

  • erwingun2010
    erwingun2010 about 4 years

    I am trying to implement and override a method with different return types without being forced to cast the return type.

    public abstract class A {
    public abstract Object getValue(String content);
    }
    
    public class B extends A {
    public String getValue(String content) {...}
    }
    
    public class C extends A {
    public int getValue(String content) {...}
    }
    
    
    public class D extends A {
    public boolean getValue(String content) {...}
    }
    
    // Main loop:
    for (A a : allAs)
    {
    // I want to use the method getValue() and corresponding to the type return a String, int or boolean without casting the return type
    }
    

    My question: Is it possible to return different types without being forced to cast? How has the abstract method look like to solve the problem?

    I think there has to be a solution because the compiler should know the return type...

  • erwingun2010
    erwingun2010 about 11 years
    Thanks. This code could work. However the return type of getValue() is an "Object" so that I have to cast it.
  • erwingun2010
    erwingun2010 about 11 years
    That is exactly what i want. I still don't get it why the compiler can not know at compile time which return type is correct. When I initialize allAs I use => allAs.add(new B()); allAs.add(new C());
  • Jim Garrison
    Jim Garrison about 11 years
    In the sample I showed, both statements inside the loop are referring to a single instance of A, which cannot be both a B and a C simultaneously. How is the compiler supposed to know which it is since that doesn't happen until runtime?
  • fiskeben
    fiskeben about 10 years
    @erwingun2010 If your method has return type Object you may be instantiating your class wrong. Do this: A<String> bInstance = new B(); If you don't add the type to the A declaration, your abstract methods will return Object.