The following code is provided for educational/illustrative purposes only.
This is probably just a clever hack. This is not kosher. To all students of the Java language, please do not start using this in your day-to-day code. Let me be the first to admit that I haven’t used this extensively and I wouldn’t recommend using it for production.
Disclaimers aside, I won’t give any more background into Java generics. For those in need of an introduction, Angelika Langer’s Java Generics FAQ explains a lot of things with more clarity and depth than I ever could.
The basic problem is, given a generic class, we would like to determine the type parameter to that class at run-time..
I’ve found myself needing to do this more than once. The simplest example I can contrive is one when we want the
Base class to perform run-time type-checking of some input parameter. For example:
The easy (and safe) way
Probably the safest way to do this would be to require that subclasses of
Base pass in their type parameter to
Base via a constructor call. To illustrate:
Which we would extend like such:
At this point, calling
ExtendsBase#accepts("Foo") should return
true, and all is well.
Laziness is the mother of invention
However, this approach imposes upon subclasses that particular constraint. What if we didn’t want to be so imposing? What if we wanted to be clever, and somehow let
Base figure things out on its own without subclasses lifting a finger?
A generic Base class with type-parameter auto-discovery
Well, it turns out that even with erasure, there is a way to discover the type parameter of a parameterized class! This is by exploiting the information we can get from
Let us rewrite the constructor of
Base to show you how this is possible:
@SuppressWarnings annotation is there so the compiler won’t complain about our (obviously) unsafe casts.
In the interest of brevity, I’ve also omitted sanity checks such as making sure that
actualClassOfSubclass.getGenericSuperclass() is actually a
firstTypeParameter is actually a
With the above in hand, we can now rewrite our subclass removing the
Here’s more or less complete code (minus import statements) with a JUnit 4 test to boot:
Please note that the above trick won’t work if we extend
ExtendsBase further. I’ll leave it as an exercise for reader to figure out why, and how to make it work no matter how deep our class hierarchy gets.
Final disclaimer: I’ve only tested this on Java 1.5.0_16 running on an Intel Mac with OS X 10.5.6. YMMV. In fact, I’d love to hear if this works or doesn’t work for you.