4

I have an interface called InterA which has a method call operate() that has its return value as Result.

 public interface InterA<T>
 {
    Result operate(T source);
 }

Assume Class MachineOperator and Class CarOperator are implementations of the above with two T object types.

 public class MachineOperator implements InterA<Machine>
 {
    Result operate(Machine source)
    {
      //Do some operation here and return result.
    }
}

public class CarOperator implements InterA<Car>
{
    Result operate(Car source)
    {
       //Do some operation here and return result.
    }
}

And I want to keep these implementations in a map so that when I give the class I can have the implementation. So my map would be like this.

Map<Class<?>, InterA<T>> map = new HashMap<>();

And when I go to fill the map I have to do following,

map.put(Machine.class, (InterA<T>) new MachineOperator());
map.put(Car.class, (InterA<T>) new CarOperator());

Is there any way of defining the map so there is no longer a need to cast when adding?

=============================================================

I have tried the following also which can avoid casting when adding to map.

public interface InterA
{
    Result <T> operate(T source);
}

Then in each implementation I have to have additional casting for each T.

public class MachineOperator implements InterA
{
    < Machine> Result operate(Machine source)
 {
    (Machine) source; //Need to cast for Machine In-order to read attributes.
    //Do some operation here and return result.
 }
}

Out of these what would be the correct approach? Is there any different solution?

rgettman
  • 176,041
  • 30
  • 275
  • 357
abo
  • 378
  • 4
  • 19
  • Some examples of how you can do something like this are here: https://stackoverflow.com/q/44422685/2891664. (Possible duplicate as well.) – Radiodef Dec 09 '17 at 01:00

3 Answers3

1

You should replace T in Map declaration with some common ancestor for Car and Machine.

If there is no common class, just use Object or ?.

That will eliminate compilation errors, but will increase chances of runtime errors. You will have be sure that the instance of the parameter is what is expected.

Gonzalo Matheu
  • 8,984
  • 5
  • 35
  • 58
1

You could write a wrapper for your Map to allow adding only corresponding InterA objects:

class ClassMap {
    private Map<Class<?>, InterA<?>> map = new HashMap<>();
    public <T> void put(Class<T> key, InterA<T> value) {
        map.put(key, value);
    }
    //we suppress unchecked cast warning because for Class<T> key we can put only InterA<T> value
    @SuppressWarnings("unchecked")
    public <T> InterA<T> get(Class<T> key) {
        return (InterA<T>) map.get(key);
    }
}

then you can use it like this

ClassMap map = new ClassMap();
map.put(Machine.class, new MachineOperator());
InterA<Machine> operator = map.get(Machine.class);
Kirill Simonov
  • 8,257
  • 3
  • 18
  • 42
1

The Lower Bounded Wildcards is what you are looking for. Your map declaration should looks like that:

Map<Class<?>, ? super InterA<?>> map = new HashMap<>();

user882813
  • 813
  • 5
  • 16