I would like to use an interface as a short-name for a parameterized interface, so as to avoid polluting all the code with generic syntax. For example:
EggChicken egg = chicken.lay(); // Can't make it compile.
instead of:
Egg<AnimalChicken> egg = chicken.lay(); // Compiles happily.
Say I would like to model the animals reproduction modes Using parameterized classes (https://en.wikipedia.org/wiki/Modes_of_reproduction). I have the following interfaces:
public interface Animal<T> {
T lay();
}
interface Viviparous<T extends Viviparous> extends Animal<T> {
}
interface Egg<T extends Oviparous> {
T hatch();
}
interface Oviparous<T extends Oviparous> extends Animal<Egg<T>> {
}
The idea being that viviparous animals lay new instances of the same animal, whereas oviparous animals lay eggs that hatch new instances of the same animal.
Now, I would like to define more precise interfaces to describe a Dog and a Chicken:
interface AnimalDog extends Viviparous<AnimalDog> {
}
interface AnimalChicken extends Oviparous<AnimalChicken> {
}
interface EggChicken extends Egg<AnimalChicken> {
}
Finally, those are the implementations:
public class AnimalDogImpl implements AnimalDog {
@Override
public AnimalDog lay() {
return new AnimalDogImpl();
}
}
class AnimalChickenImpl implements AnimalChicken {
@Override
public EggChickenImpl lay() {
return new EggChickenImpl();
}
}
public class EggChickenImpl implements EggChicken {
@Override
public AnimalChicken hatch() {
return new AnimalChickenImpl();
}
}
My problem comes when I want to use the the classes in code:
public class AnimalTest {
@Test
public void can_do_something_nice() {
AnimalChicken chicken = new AnimalChickenImpl();
// Error here:
EggChicken egg = chicken.lay();
AnimalChicken chick = egg.hatch();
Assertions.assertThat(chick).isNotNull();
}
}
I get the error: Required EggChicken, found Egg<AnimalChicken>, but this is precisely how I defined EggChicken
. Is it possible to solve this kind of indirection?
What you are looking for is called a type alias.
Java unfortunately does not have them.
When you create a new interface, that defines a new type. An instance of EggChicken
is also an instance of Egg<Chicken>
, but not the other way around. You would have to make your AnimalChicken
(interface!) return an EggChicken
explicitly.