tags:

views:

364

answers:

3

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.

  • EDIT -

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.

+2  A: 

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;
}
TofuBeer
This solution is interesting, but it only narrows the type of the value field to Fooable, not MyInterface, hence any client of the interface will have to perform a cast, defeating the purpose.
Kris Nuttycombe
I think you have this backwards... see my answer below
Scott Stanchfield
Scott Stanchfield
@Scott That would work out if an interface could extend a class...
TofuBeer
right -- between that and having to have the value implement that new interface, it wouldn't work (which is why I didn't do it as an answer)
Scott Stanchfield
A: 

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...

Varkhan
+1  A: 

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.

starblue