Bick
Bick

Reputation: 18551

Java generics calling a method that returns <T extends > object

I have a class called TResult

public class TResult<T extends MyEntity>  {

    public List<T> getEntityList() {
        return entityList;
    }
}

And I have a static method in other some class that returns it

public static TResult getAllEntities(final Class clazz, RouteFilter filter ){
}

Now, when I call getAllEntities I need to cast it to MyEntity otherwise i get a warning (unchecked assignment). I try to change the method signature and it only works with

public static <T extends APIBaseEntity> TResult<T> getAllEntities(final Class clazz, RouteFilter filter) {}

Why do I have to point that T extends APIBaseEntity in getAllEntities method when it is already defined in TResult class signature?

TResult<APIBaseEntity> allEntities = GeneralCRUD.getAllEntities(APIAccount.class, filter);

Upvotes: 3

Views: 2716

Answers (1)

Joffrey
Joffrey

Reputation: 37859

First of all, you should not use raw types*, it would help you understand what you're doing with generic classes.

Ask yourself these questions: What class is clazz? What kind of TResult are you returning? Is the provided class supposed to define the type parameter of TResult?

If the answer is yes to the last question, then you're probably looking for a declaration like this:

public static <T extends APIBaseEntity> TResult<T> getAllEntities(final Class<T> clazz, RouteFilter filter) {
    //...
}

This basically forces the returned TResult<T> to be of the same type T as the provided clazz: the type parameter of your method. This also removes the burden of casting to the return type you want, because the compiler now knows already.

Why do I have to point that T extends APIBaseEntity in getAllEntities method when it is already defined in TResult class signature?

If you write public <T> TResult<T> myMethod(), T is a generic type for your method, but is not constrained at all, so it could be anything. TResult<T> does not act as a constraint for the type parameter of your method. You have to explicitly constrain it yourself, because you could even constrain it more than the TResult class (for instance with a subtype of APIBaseEntity).

If you don't constrain your method's type parameter, you get a compile error/warning (don't remember from the top of my head) because it wouldn't fit TResult's type parameter declaration.


*Note: raw types are generic types referenced without their type parameter, such as Class or TResult, as opposed to Class<T> or TResult<T>.

Upvotes: 7

Related Questions