Java Generics Of Generics - java

I have an interface:
public interface Human<D extends Details> {
D getDetails();
}
And a concrete impl:
public class Man implements Human<ManDetails> {
ManDetails getDetails();
}
I'd like to extend Man in such a way so I could do something like:
public class Baby extends Man {
BabyDetails getDetails();
}
So basically I'm looking for a way so Man would be concrete (I would be able to use it on it's own) but also a generic so others can extends it (for example, getDetails() of baby will get super.getDetails() and create a new instance of BabyDetails from it).

You may consider changing your code to
class Man<T extends ManDetails> implements Human<T> {
public T getDetails(){return null;}
}
which would let you do something like
class Baby extends Man<BabyDetails> {
public BabyDetails getDetails(){...}
}
or
class Baby<T extends BabyDetails> extends Man<T> {
public T getDetails(){...}
}
But as Sotirios Delimanolis already mentioned what you did is already fine
public class Baby extends Man {
public BabyDetails getDetails(){...}
}
because overriding method can declare new return type as long as this type is subtype of return type declared in overridden method, for instance
List<String> method()
can be overridden by
ArrayList<String> method();

Related

In java, is an interface providing parameters to extend a parameterized interface an exact synonym of it?

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.
The overall idea is correct, but there are problems in the hierarchy. An Animal can't lay a type that is either Egg or Animal directly, they're not related.
I think the following represents what you intended:
interface LayProduct {}
interface Animal<E extends LayProduct> extends LayProduct{
E lay();
}
interface Egg<E extends Egg<E,A>, A extends Oviparous<E,A>> extends LayProduct {
A hatch();
}
interface Viviparous<A extends Viviparous<A>> extends Animal<A> { }
interface Oviparous<E extends Egg<E,A>, A extends Oviparous<E,A>> extends Animal<E> { }
interface AnimalDog extends Viviparous<AnimalDog> {
}
interface AnimalChicken extends Oviparous<EggChicken,AnimalChicken> {
}
interface EggChicken extends Egg<EggChicken,AnimalChicken> {
}

How do I parameterise in an interface and then specify generic type in implemented class

I want to have an interface as :
public interface CarManager<T extends Car> {
public T createCar(Map data);
public T saveCar(T t);
}
so that I can do:
public class FiatManager<Fiat> implements CarManger {
public Fiat createCar(Map data) {
// ...
}
// ...
}
for various cars that extend Car.
However, when I try, I get an error that I haven't implemented createCar
The exact error message is:
The class 'FiatManager' must be declared abstract or the method Car createCar(Map data)' must be implemented.
You forgot to implement the interface:
public class FiatManager implements CarManager<Fiat>
Of course, you have to make sure that Fiat extends Car.
Also, (as #Thilo correctly noted) note that FiatManager is not generic anymore, since it is already known as a one that's dealing with Fiat(s).
For just Fiats, then:
public class FiatManager implements CarManager<Fiat>
public Fiat createCar(Map data) {
// ...
}
// ...
}
For all Cars:
public class FiatManager<T extends Car> implements CarManager<T>
public T createCar(Map data) {
// ...
}
// ...
}
You need to declare your FiatManager class as:
public class FiatManager implements CarManager<Fiat>{
Then you need to implement both methods createCar and saveCar.
Of course, that is assuming you have a Fiat class extending or implementing Car.
Finally, watch out for the raw Map in your method parameters!

Is it possible to extend a generic class while restricting the generic type?

Suppose I have abstract classes (or, indeed, interfaces)
public abstract class Animal
public abstract class Bird Extends Animal
and a generic class
public class Lifestyle<A extends Animal>
So we might create a Lifestyle<Lion> object.
The Lifestyle class contains methods that animals can use to tell them how to walk around, find food, interact with other animals of the same species, etc. Now suppose I want to extend this class to a special BirdLifestyle class that tells Birds how to do all the above things, but also tells them how to fly and use all of the extra methods in the Bird class. I want to be able to create a BirdLifestyle<Eagle> object, for instance. I'm pretty sure that the following won't compile:
public class BirdLifestyle<B extends Bird> extends Lifestyle<A extends Animal>
and the only alternative I can think of is rather nasty:
public class BirdLifestyle<B extends Bird>
{
private Lifestyle<B> lifestyle // tells the bird how to do animal things.
public Lifestyle<B> getLifestyle()
{
return lifestyle;
}
// Bird-specific methods.
}
We could then get all of the methods from Animal by calling getLifestyle().walk() or things like that.
Now suppose that my friends have all created their own implementations of these four classes and that we want to link them using interfaces. So we create
public interface LifestyleInterface
{
public void walk();
// etc.
}
public interface AvianLifestyleInterface extends LifestyleInterface
{
public void fly();
// etc.
}
My friends are all more specialize, so they've all written things like:
public class LionLifestyle implements LifestyleInterface
or
public class EagleLifestyle implements AvianLifestyleInterface
while I can write:
public class Lifestyle<A extends Animal> implements LifestyleInterface
But I can't now write:
public class BirdLifestyle<B extends Bird> implements AvianLifestyleInterface
even if my BirdLifestyle class overrides all the methods introduced in AvianLifestyleInterface. This is because BirdLifestyle is not a superclass of Lifestyle. The only way round this is to create lots of entry-point methods such as:
public class BirdLifestyle<B extends Bird>
{
private Lifestyle<B> lifestyle;
public Lifestyle<B> getLifestyle()
{
return lifestyle;
}
// 'AvianLifestyleInterface' methods.
#Override
public void fly()
{
// Code for flying.
}
// etc.
// 'LifestyleInterface' methods.
#Override
public void walk()
{
getLifestyle().walk();
}
// etc., creating a similar one-line method for each method in
// 'LifestyleInterface' that is just an entry-point to the same
// method in the 'Lifestyle<A>' object.
}
This seems like an unnecessary amount of code to write, and a lot of the code is written in a fairly mechanical way, which breaks several programming rules. For example, if I want to add any methods to the LifestyleInterface interface then I need to remember to add a new one-line method into the BirdLifestyle class. Is there a cleaner way?
It's a little unclear to me what you are really asking here, but it seems that your first attempt can be easily remedied by:
public class BirdLifestyle<B extends Bird> extends Lifestyle<B> {
// ...
}
Lifestyle is already declared to be generic as Lifestyle<A extends Animal>, no need to repeat what the generic type bound is (and as you say, it won't compile).
Similarly:
public class BirdLifestyle<B extends Bird> extends Lifestyle<B> implements AvianLifestyleInterface {
// ...
}
Will work.
I'm pretty much lost in your question right now. But you can surely change your BirdLifestyle class to:
public class BirdLifestyle extends Lifestyle<Bird> { }
Don't see why you would make BirdLifestyle itself a generic class here. Will update the answer if I understand other part of the question.
If you're moving to interfaces, then you can just do:
public class BirdLifestyle implements AvianLifestyleInterface { }
Again, why would you make the class generic? The name BirdLifeStyle should really describe the life style of a bird. Do you have different kinds of Bird?

Java inheritance and generics

I'm trying to extend an abstract class with generics and I'm running into a problem:
abstract public class SomeClassA<S extends Stuff> {
protected ArrayList<S> array;
public SomeClassA(S s) {
// ...
}
public void someMethod() {
// Some method using the ArrayList
}
abstract public void anotherMethod() {
// ...
}
}
Now I want to extend this class with another abstract class so I could override "someMethod". I tried:
abstract public class SomeClassB<Z extends Stuff> extends SomeClassA {
public SomeClassB(Z z) {
super(z);
}
#Override public void someMethod() {
// Some method using the ArrayList
}
}
NetBeans doesn't see any problem with the constructor, but I cannot use the ArrayList from SomeClassA within the method someMethod. So I tried:
abstract public class SomeClassB<Z extends Stuff> extends SomeClassA<S extends Stuff> {
public SomeClassB(Z z) {
super(z);
}
#Override public void someMethod() {
// Some method using the ArrayList
}
}
And now it's just very odd. Everything seems to work (and I can now use the arraylist, but NetBeans says there's a "> expected" in the declaration of SomeClassB and it just won't compile. If possible, I would like:
To know how to solve this particular problem.
To have a good reference to understand generics.
To know if it's any easier in C#.
You will need to pass the generic type to the superclass also, like this:
abstract public class SomeClassB<Z extends Stuff> extends SomeClassA<Z>
Your superclass and subclass will then both use the same generic type. Generic Types are not inherited by subclasses or passed down to superclasses.
For a good reference to understand generics, check out Effective Java, 2nd Edition.

Java - Return correct type from Generic method

I have the following class structure:
public class Team {
...
}
public class Event {
}
public abstract class Fixture<T extends Team> implements Event {
...
}
public abstract class Forecast<Event> {
}
public class MyPrediction<T extends Fixture<? extends Team>> extends Forecast<Fixture<? extends Team>>{
}
I am trying to model sports events of all kinds (i.e. a 'Fixture' is for a particular game between two participants play against each other, whereas another type of 'Event' may have many participants), along with predictions for the outcome of particular 'Events'. I have a generic method:
public <T> MyPrediction<Fixture<? extends Team>> getMyPrediction(Fixture<? extends Team> fixture) {
}
I want to be able to return a MyPrediction instance which has the generic type of the fixture argument, but I can't seem to do so. For example, if I do something like the following, then I get a compilation error:
SoccerFixture<EnglishSoccerTeams> soccerMatch = new ScoccerFixture<EnglishSoccerTeams>();
MyPrediction<SoccerFixture<EnglishSoccerTeams>> = getMyPrediction(soccerMatch);
I am willing to change my class structure to incorporate this feature. How can I do so?
Change the signature of getMyPrediction to
public <T extends Fixture<? extends Team>> MyPrediction<T> getMyPrediction(T fixture)
This tells the compiler that the fixture types in the argument and result are the same, allowing type-checking to pass.
Here is a complete example, with some other minor changes to get it to compile. It introduces the class Predictor to hold the getMyPrediction method and a doit method to show sample use:
public interface Team {
}
public interface Event {
}
public abstract class Fixture<T extends Team> implements Event {
}
public abstract class Forecast<T> {
}
public class MyPrediction<T extends Fixture<? extends Team>> extends
Forecast<Fixture<? extends Team>> {
}
public class SoccerFixture<T extends SoccerTeam> extends Fixture<T> {
}
public class SoccerTeam implements Team {
}
public class EnglishSoccerTeam extends SoccerTeam {
}
public class Predictor {
public <T extends Fixture<? extends Team>> MyPrediction<T> getMyPrediction(T fixture) {
return new MyPrediction<T>();
}
public void doit() {
SoccerFixture<EnglishSoccerTeam> soccerMatch = new SoccerFixture<EnglishSoccerTeam>();
MyPrediction<SoccerFixture<EnglishSoccerTeam>> myPrediction = getMyPrediction(soccerMatch);
}
}
As noted elsewhere, you might need to introduce one or more factory objects to perform meaningful work in the MyPrediction implementation.
Java's type system is not powerful enough to do directly what you propose, because of type erasure (the generic parameters are not available at runtime.
The usual solution is to create a separate EventFactory class, which you can then pass in to any method which needs to create a specific Event subtype instance.

Categories

Resources