4

There are several simple test-case classes:

public interface ListCriteria<T> {
  // some stuff here
}

public class UserListCriteria implements ListCriteria<User> {
 // implementation
}

public interface Editor<T> {
  // sample method 1
  List<T> listObjectsTest1(ListCriteria<T> criteria);
  // sample method 2
  <L extends ListCriteria<T>> List<T> listObjectsTest2(L criteria);
}

And there is an implementation of Editor which Java thinks it does not provide necessary implementation for both sample methods:

public class UserEditor implements Editor<User> {

  @Override
  public List<User> listObjectsTest1(UserListCriteria criteria) {
    //
  }

  @Override
  public List<User> listObjectsTest2(UserListCriteria criteria) {
    //
  }
}

Both method implementations are wrong. The question is why. Especially for the latter method. Sure I could do interface Editor<T, L extends ListCriteria<T>>, and that would solve the issue, but I don't want to, I want to understand why I can't use method-level generics here.

2 Answers 2

2

The errors you get have nothing to do with generics, because you implement the method with another type than the interface enforces.

The Editor interface defines

List<T> listObjectsTest1(ListCriteria<T> criteria);

Thus the UserEditor must implement in your case

public List<User> listObjectsTest1(ListCriteria<User> criteria) {

You should not mistake the parameter's type with the parameter's generic type. The Editor interface enforces a ListCriteria type. The ListCriteria's generic type is T and T can be bound by a subclass, e.g implements ListCriteria<User>. That is what I mean when I say "errors you get have nothing to do with generics".

I guess what you wanted was

public interface Editor<C, T extends ListCriteria<C>> {
    List<C> listObjectsTest1(T criteria);
}

and then the UserEditor can be implemented as

public class UserEditor implements Editor<User, UserListCriteria> {

   public List<User> listObjectsTest1(UserListCriteria criteria) {
      return null;
   }
}

why? Especially for the latter method

The second method in the Editor interface

  <L extends ListCriteria<T>> List<T> listObjectsTest2(L criteria);

does not mean that you can implement any type binding of L The UserEditor must still implement

public <L extends ListCriteria<User>> List<User> listObjectsTest2(L criteria) {
    return null;
}

This method defines the generic type L that will be bound when a client invokes the method. Thus you can invoke the method with any type that is a subtype of ListCriteria<User>.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, do I get you right saying that I can override the return type, but not the method arguments, and that I must hold on to exactly the same arg signatures even if UserListCriteria perfectly fits at runtime?
1
  1. Your listObjectsTest1(UserListCriteria criteria) function of UserEditor is not overriding the function listObjectsTest1(ListCriteria<T> criteria) of Editor<T> interface because they have two different signature, i.e., essentially the argument type.

  2. The same goes for listObjectsTest2 which was declared in the interface: <L extends ListCriteria<T>> List<T> listObjectsTest2(L criteria); but you have declared it in the UserEditor class as: List<User> listObjectsTest2(UserListCriteria criteria)

So you will need to change the signature to:

class UserEditor implements Editor<User> {


    @Override
    public List<User> listObjectsTest1(ListCriteria<User> criteria) {

    }

    @Override
    public <L extends ListCriteria<User>> List<User> listObjectsTest2(L criteria) {

    }
}

Please read through jls 8.4.8. Inheritance, Overriding, and Hiding for more details.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.