Reputation: 4580
Is it possible to narrow the type of a field in a Java class without making the containing class itself generic?
The generic example would be something like this:
abstract class MyClass {
//...
}
interface MyInterface {
//...
}
class MyConcreteClass<T extends MyClass & MyInterface> {
private T value;
}
Is there any way to do the following:
class MyConcreteClass {
private MyClass & MyInterface value;
}
This is essentially equivalent to MyConcreteClass or the raw MyConcreteClass type. In my implementation the type parameter will vary over the lifetime of the object (cursed mutability! It is imposed upon me by JPA!) and so the type annotation seems somewhat superfluous.
There is an additional restriction I forgot to mention. We will also have this:
class SubA extends MyClass
class SubB extends MyClass
class SubC extends MyClass
class SubSubA extends SubA implements MyInterface
class SubSubB extends SubB implements MyInterface
class SubSubC extends SubC implements MyInterface
Thus, simply declaring an abstract subclass of MyClass that implements MyInterface is not a suitable solution.
Also, the ultimate field type must be a concrete type, rather than simply an interface representing the intersection, for the simple reason that JPA-persisted entites cannot be referenced by their interface types. That is, a persistent field in a JPA entity class must be of either a primitive type or a concrete entity type.
Upvotes: 1
Views: 1424
Reputation: 56762
In such complicated cases you should hide classes behind interfaces.
Then you can define an explicit interface for the intersection, i.e. an interface that extends both the interface corresponding to MyClass and MyInterface, and letting the appropriate superclasses implement it instead of MyInterface.
Upvotes: 1
Reputation: 16761
I don't think there is a way to do that. Not exactly like that anyway. However, since this is a private field and you control it entirely, you can just declare it as
private MyClass value;
but also make sure in all your code that only objects that implements MyInterface are affected to it, and cast everywhere you need to access it as the interface. Yes, it looks dirty, and it is (slightly).
You could also create the following derived class
abstract class MyDerivedClass extends MyClass implements MyInterface {
//...
}
and then use
private MyDerivedClass value;
This is much cleaner, but you have to create an other class, just for that purpose...
Upvotes: 0
Reputation: 61526
I have never come across a problem like that (and thus no elegant solution comes to mind :-)... however...
interface Fooable
{
}
abstract class MyClass
implements Fooable
{
}
interface MyInterface
extends Fooable
{
}
class MyConcreteClass
{
private Fooable value;
}
Upvotes: 2