Java Generics - 3. Multiple bounding
This is part 3 of the 9 part series on Java Generics
Prev Topic
|
Topics
1. Introduction
2. Bounding
8. Target Types
|
|
Java Generics - Multiple bounding
Refer back to out Fruit and Grain hierarchy. Remember
few of the Grains and Fruits also implement the interface Exportable.
What if you wanted the generic class to be used only with the type Exportable? We already discussed that earlier. The declaration extends makes no
distinction whether the F extends a class or an interface. The generics give us
even more flexibility. Say you wanted you generic class to be used with a type Fruit
which is Exportable? Here the class to be used with the Generic types
should be both – Fruit & Exportable. Is that possible with
generics? Yes of course it is. And that is what makes it even more flexible.
And this is how you would declare those types of classes.
public class ExportableFruitBean<E extends Fruit & Exportable>
{ }
|
Notice that you are putting Fruit and Exportable
both in the diamond separated by &. This tells that the class can
be used with the type which is both Fruit and Exportable. If you wanted
this class to be derived from Bean<E> then the declaration
is similar to the one which we have already seen.
public class ExportableFruitBean<E extends Fruit & Exportable> extends Bean<E> { }
|
Recall the Fruit and Grain hierarchies. Some Fruit
and Grain
were Exportable
even when they were in a different hierarchy. The typed class above can be used
only with the Fruit which is Exportable. All other ways will
generate the compiler error.
// The Grape Shiraz and Mango Alphono are the only fruits
// that are Exportable
ExportableFruitBean<Shiraz>
efbs = new ExportableFruitBean<>();
efbs.set(new Shiraz());
System.out.println(efbs.get());
ExportableFruitBean<Alphonso>
efba = new ExportableFruitBean<>();
efba.set(new Alphonso());
System.out.println(efba.get());
|
Trying to use other types will give compiler errors. The
error would be something like this - Bound mismatch: The type Mango is not a
valid substitute for the bounded parameter <E extends Fruit &
Exportable> of the type.
// the fruits Mango, Grape-Chardonnay will give errors as they
are only
// Fruits but not Exportable
ExportableFruitBean<Mango>
efbm = new ExportableFruitBean<>();
ExportableFruitBean<Chardonnay>
efbc = new ExportableFruitBean<>();
// Basmati rice is
Exportable but is not a fruit
ExportableFruitBean<Basmati>
efbb = new ExportableFruitBean<>();
|
Can you declare them interchangeably as <E extends Exportable & Fruit
> instead of <E extends Fruit & Exportable>? At first glance, why not? But the answer is No. You
will get a compiler error - The type Fruit is not an interface; it
cannot be specified as a bounded parameter.
// compliler error
public class ExportableFruitBean<E extends Exportable & Fruit> extends Bean<E> { }
|
This has to do with the java language structure. Java allows
only one line of polymorphism, i.e. you can extend at the most only one class,
but implement many interfaces. To keep the compiler checks easy and to make it
more readable, the java programming language mandates that anything beyond the
symbol ‘&’ in the declaration should be an interface. You can have
one and only one class which E can extend. Thus the decaration <E
extends Fruit & Grain> would throw a complier error, because Grain
is a class and not an interface. The declaration below throws a complier error
- The
type Fruit is not an interface; it cannot be specified as a bounded parameter
– same as the one above. In the java programming language you cannot have a Fruit
which is also a Grain, and therefore allowing such a declaration would not mean
anything. You could argue that you can have a declaration as <E
extends Fruit & Grape> as Grape is also a fruit and lies in
the same inheritance hierarchy. Yes but then how would your class refers it
internally? As a Grape or as a Fruit? You must declare it as an
extension of Fruit if you want to refer it as a fruit, or as a Grape
if your class wants the reference as a Grape.
// compiler error
public class GrainAndFruitBean<E extends Grain & Fruit> extends Bean<E> { }
|
Can I declare more than one interface? Yes!
Can I declare only interfaces without a class? Yes!!
Both declarations below are therefore valid. Just make sure
that the types with which you initialize the classes fulfill the type criteria.
public class MyFruitBean<E extends Fruit & Exportable
& Serializable> extends Bean<E> { }
public class MyFruitBean<E extends Exportable &
Serializable> extends Bean<E> { }
|
Comments
Post a Comment