tags:

views:

164

answers:

2

I'm wrestling with a bit of weird generics behavior regarding being able to "narrow" return types when subclassing. I managed to reduce the problem to the following set of classes:

public class AbstractIndex {
}

public class TreeIndex extends AbstractIndex {
}

public interface IService<T extends AbstractIndex> {
}

public interface ITreeService extends IService<TreeIndex> {
}

public abstract class AbstractServiceTest<T extends AbstractIndex> {
    abstract <V extends IService<T>> V getService();
}

public class TreeServiceTest extends AbstractServiceTest<TreeIndex> {
    @Override
    ITreeService getService() {
        return null;
    }
}

The problem is that Java warns when I try to narrow the return type of getService to ITreeService. The warning is

Type safety: The return type ITreeService for getService() from the type TreeServiceTest needs unchecked conversion to conform to V from the type AbstractServiceTest

Why is not ITreeService a valid narrowing type for getService?

EDIT: changed error to warning

+5  A: 

Because I think you meant to say this:

public abstract class AbstractServiceTest<T extends AbstractIndex> {
    abstract IService<T> getService();
}

There's no purpose to making the separate V type variable, other than adding constraints that your subclasses can't fulfil. :-P

Chris Jester-Young
Thanks. That did it.
JesperE
+3  A: 

And if you want to have AbstractServiceTests with different Vs for the same T, you can do this:

public abstract class AbstractServiceTest<T extends AbstractIndex, V extends IService<T>> { 
    abstract V getService(); 
} 

public class TreeServiceTest extends AbstractServiceTest<TreeIndex, ITreeService> { 
    @Override 
    ITreeService getService() { 
        return null; 
    } 
}

public class AnotherTreeServiceTest extends AbstractServiceTest<TreeIndex, AnotherTreeService> { 
    @Override 
    AnotherTreeService getService() { 
        return null; 
    } 
}

EDIT: However, it makes sense only if you also use V in some other place, such as:

public void setService(V service) { ... }
axtavt