Reputation: 1962
Despite the fact that Java does not have generics [@ runtime], lately I have been caught up in some kind of a generic hell.
Situation (simplified & useless context removed):
There is a library A, which provides an interface IA. There is a library B, which provides an interface IB. Both libraries are 3rd party libraries, which I have absolutely no control over. (In reality, there are more than 2, but let's not this make too complex just yet.)
There is an engine, developed by my company, which both defines and makes heavy use of objects that are/implement both IA and IB. Because our engine must deal with all implementations, we could not simply define some interface IAB implements IA, IB
and let all our classes implement it. Therefore, in order to attain compile-time type-safety & method exposure, it was decided to use generic methods. So, whenever an 'IAB' would be required, we would have
<IAB extends IA & IB> void doThis(IAB someObjectWithBothAPIs)
.
This works very well, as a matter of fact. However, it is not possible to do something as simple as <IAB extends IA & IB> IAB fieldWithBothAPIs;
(neither IA & IB fieldWithBothAPIs;
). Which brings us to the question:
Why not?
Basically, what are the (design-level?) reasons to allow arbitrary TypeParams(opt)
, while instance fields are restricted to a concrete Type
?
JLS §8.3
FieldDeclaration:
FieldModifiers(opt) Type VariableDeclarators ;
JLS §8.4
MethodDeclaration:
MethodHeader MethodBody
MethodHeader:
MethodModifiers(opt) TypeParameters(opt) Result MethodDeclarator Throws(opt)
Upvotes: 1
Views: 86
Reputation: 533660
You can do this, just not in the line of declaration.
interface IA {}
interface IB {}
interface IC {}
class Generic<IAB extends IA & IB> {
final IAB iab;
Generic(IAB iab) {
this.iab = iab;
}
<IBC extends IB & IC> void method(IBC arg) {
IBC ibc = arg;
}
}
A good reason to avoid doing this on each line is that two types which extend the same thing might not be the same.
For example, image you could write
class Generic {
<IAB extends IA & IB> IAB iab;
<IBA extends IA & IB> IBA iba;
<IAB extends IA & IB> void method(IAB arg) {
iab = arg; // error, types are not the same.
iba = iab; // compile error as the types are not the same.
would be the same as this, which is syntactically correct and doesn't compile.
class Generic<IAB extends IA & IB, IBA extends IA & IB> {
IAB iab;
IBA iba;
<IAB extends IA & IB> void method(IAB arg) {
iab = arg; // error, types are not the same.
iba = iab; // compile error as the types are not the same.
Upvotes: 1
Reputation: 280102
A generic method receives its type arguments at runtime from its invocation context. It can receive different types in different situations.
How would a generic field receive type arguments? The field cannot have a different type based on its use in some contexts. It must have a single type, known at compile time.
Upvotes: 1