Some sample code with generics, which are hard. Explanation about each package can be found below.
I also highly suggest reading:
- Java Generics Tutorial
- section Generics in Effective Java by Joshua Bloch.
- Generics FAQ by Angelika Langer
First you may look at WhyDoWeNeedGenerics
at all. Holders
contain both non-generic and a generic versions, which are
not too different, though the generic one is easier to use.
Generics work only compile time, there are no generics runtime. This is called "erasure". Most common problems is that
you cannot find the TypeOfGeneric
runtime and you cannot do the GenericOverload
of the methods. You can't use
generics in 'catch' clause when catching Exceptions
There is a common confusion about DifferencesBetweenGenericTypes
, such as what is the difference between List and
List<?>.
Please BeCarefulWithRawtypes
- this can bite you in some unexpected places. The example there is simple, but you
should understand very well where the casts are actually done.
See how different parametrized types can be cast to each other in Assignments
.
Bridge methods are explained in Java Tutorials
They rarely cause troubles, but ComparablePerson
illustrates what can happen.
There is such thing as multiple bounds:
MyItem<T extends Number & Iterable>
However you can get into problems when you want to store the reference to such bounded object.
To describe such a use case there are: Eatable
interface, Fruit
superclass and Banana
and Apple
which are both
eatable and fruits (not all fruits are eatable).
FoodEater
wants to eat anything which is Eatable
and Fruit
, so both Apple
and Banana
could be passed into the
method. But in case he wants to keep this food for later use and consume it at the evening, he has troubles with storing
a reference to such object. The workaround is to use two fields, one of type Eatable
and one of type Fruit
and store
the passed object in both places.
EatableFruitHolder
is a bit different - it can hold the reference to the passed object, but can't create the alternative
one. However this one is easily explainable.
Can you guess why?
When EatableFruitHolder is instantiated it is parametrized with Apple and T becomes Apple but we cannot know anything about the type T in the constructor itself. So imagine we parametrized it with Banana, and still try to push Apple as an alternative fruit. That won't work, because apples are not bananas. In this particular case you may use instanceof and casts, but this is a slippery path.What is not easily explainable is why method getEatableFruitOrAppleHolder
does not compile... well, actually this one
does not compile, because wildcards do not support multiple bounds. So it does not compile, because it does not compile.
But why doesn't it?
EatableFruitHolder
does not solve the FoodEater
problem.
This is a very clever technique to store the reference to the parametrized class taken from here.
ClassBasedFavourites
stores favourite objects of each class with a class being a key. You can't differentiate between
List<String>
and List<Integer>
with this technique, because of erasure. Now have a look at TypeReference
and how
it works in TypeReferenceFavourites
. This is not very straightforward, but it's nice and it works.
However be aware that generics are erased anyway - there is no magic, so please read comments for TypeReferencesAreNotPerfect
.
WildcardsMethods
are tricky.
You should prefer <T extends MyClass>
over <? extends MyClass>
if possible.
For example second signature is preferable:
public void processWildcardAnimal(Holder<? extends Animal> animal)
public <T extends Animal> void processExactAnimal(Holder<T> animal)
It's explained in several places why.
Syntax public <? extends Animal> getAnimal()
is impossible and public <T extends Animal> T getAnimal()
makes no sense unless you pass something in the method - class or instance (see getAnimal()
overloads).
Sometimes you can just use plain public Animal getAnimal();
and no generics. It can return Cat, no need of extends
.
processExactlyWithHolderCallback
requires to use type T, but processWildcardWithHolderCallback
overloads would
accept anything into callback.
processExactlyWithCallback
does not compile but it's easy to see why - you can parametrize it with everything, for
example Dog
so you can't use Cat
inside (similar to alternative fruit in EatableFruitHolder
).
First I could not find the explanation why
public void processWildcardWithCallback(Callback<? super Animal> callback)
compiles and
public <T super Animal> void processExactSuperWithCallback(Callback<T> callback) {
does not.
Explanation is actually simple. Wildcard bounds and type bounds have different syntax. Types support multiple bounds
but do not support super
, while wildcards support super
but do not support multiple bounds.
Wildcards:
<? extends ClassOrInterface>
<? super ClassOrInteface>
Types:
<T extends ClassOrInterface & InterfaceA & InterfaceB & InterfaceC>
On the contrary to the wildcards section, it seems impossible to avoid <? extends Handler>
syntax when you're dealing
with classes themselves. Let's say that there is some HandlerFactory
which would return us the Handler class we should
use (Handler
has two children: SimpleHandler
and ComplicatedHandler
). You'd like to instantiate those later.
One of the possible workaround is to use the Constructor
object, which would keep the wildcard inside.
The Problem
describes what I want to achieve. In particular I want to be able to save the object which is down
in the deep inheritance hierarchy.
When inheritance is two layers, there is a natural way of writing generics which is NotReallyASolution
.
Solution
shows how to solve the problem.
Please note, however, that we can parametrize PersonDao
with Freshman
and behavior is different for two seemingly the
same PersonDao<Freshman>
. We can't prevent PersonDao
be not parametrized with FreshmanDao
. Or can we?
Builder, generics and hierarchy is hard. I describe a problem in a Problem
. I show the usual solution for the
two-level hierarchy in the NotReallyASolution
. Why it's not really a solution is described in the class.
The naive approach of simply merging it with a 'deep inheritance' Solution just did not work as shown in the
NaiveApproach
, though it was close.
What we need is Curiously Recurrring Template Pattern (or, in other words Comparable<T extends Comparable<T>>
.
Check this out in CuriouslyRecurringPatternSolution
. There is still one problem with this solution: I don't know
what the Builder is actually parametrized with.
There is a discussion how to workaround the issue with additional class and how can a question mark become our savior.
Comparable<T>
is one of my favourite interfaces. Please check how to actually CompareComparables
and probably you
will get a bit amused (I was when I wrote the example).
I couln't come up with the better name for this package. There are some fun examples through this project, such as
StudentBuilder<StudentBuilder<StudentBuilder<StudentBuilder>>> studentBuilder = new StudentBuilder<>()
, however these
do not belong to any logical group.
Can you guess which compareTo
methods compile in NestedComparable
?
Do you know how Recurring
generics look like and behave?
You can parametrize with Void
to avoid (see the pun?) putting any objects into the Holder.
When XLintFails
to prevent you from ClassCastExceptions you understand that generics are hard even for compiler.
I don't quite understand why SometimesInheritanceFails
.