简体   繁体   中英

Java Generics with multiple type support

Say we have an interface as such...

interface ICalculator<T extends CalculableObject>{ void calculate(T obj); }

where our generic type is an abstract class...

public abstract class CalculableObject{...}

with multiple concrete types...

public class TypeA extends CalculableObject{...}

public class TypeB extends CalculableObject{...}

How would you go about defining an implementation of the Calculator object that requires a calculate method to be defined for multiple CalculableObject types?

ie -

public CalculatorAB<?> implements ICalculator{
void calculate(TypeA obj){...}
void calculate(TypeB obj){...}
}

Because of type erasure, you can't. See: Getting error for generic interface: The interface Observer cannot be implemented more than once with different arguments:

What I would do is use a delgate and have your CalculatorAB but it simply doesn't implement ICalculator, or better yet, have CalculatorAB implements ICalcuator. Your method can then check instance of and forward to the appropriate method.

public CalculatorAB implements ICalculator<CalculableObject> {
  void calculate(CalculableObject obj){
    if(obj instanceof TypeA)
      calculate((TypeA)obj);
    else if(obj instanceof TypeB)
      calculate((TypeB)obj);
  }
  void calculate(TypeA obj){...}
  void calculate(TypeB obj){...}
}

You can't. (Contrary to popular belief, it could relatively easily be implemented without runtime reification. But it isn't.)

Generally multiple subtyping of "main" types is a bad idea. Have one object that has methods that returns appropriate Calculator s (no Hungarian please!).

Use an enum :

public enum Type extends CalculableObject {
    A
    {
        @Override
        public void doSomething() { }
    },
    B;
}

You are then guaranteed that Type 's A and B exist, and that they both extend the CalculableObject .

This also enables you to simply pass in Type.A to the calculate method as a Type or CalculableObject , rather than cluttering it with A, B, C, D, etc.

I daresay that if you want to do this, perhaps there is something wrong, elsewhere in your design. But besides the already mentioned alternatives, you could make just the calculate method generic in the interface, and not the whole interface. Then the subinterfaces can be generic or simply define the new methods you want.

Like this:

public static abstract class CalculableObject{}

public static class TypeA extends CalculableObject{}
public static class TypeB extends CalculableObject{}
public static class TypeC extends CalculableObject{}

public interface ICalculator{
    <T extends CalculableObject> void calculate(T obj);
}

public static class CalculatorAB implements ICalculator{

    void calculate(TypeA obj){
        System.out.println("TypeA");
    }
    void calculate(TypeB obj){
        System.out.println("TypeB");
    }

    @Override
    public <T extends CalculableObject> void calculate(T obj) {
        System.out.println("CalculableObject");
    }
} 

public static void main(String args[]){
    TypeA a = new TypeA();
    TypeB b = new TypeB();
    TypeC c = new TypeC();

    CalculatorAB ab = new CalculatorAB();

    ab.calculate(a);
    ab.calculate(b); 
    ab.calculate(c);
}

This renders

TypeA
TypeB
CalculableObject

You define the methods you need to "calculate" in the CalculableObject class. Then, in CalculatorAB you just call those methods on the given object.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM