John Gowers
John Gowers

Reputation: 2736

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?

Upvotes: 1

Views: 143

Answers (2)

Harald K
Harald K

Reputation: 27054

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.

Upvotes: 4

Rohit Jain
Rohit Jain

Reputation: 213203

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?

Upvotes: 2

Related Questions