简体   繁体   中英

How do I call a generic interface method from another generic class

Here is my code.
I have a generic interface

public interface ClientServerComparator<T> {
    public boolean compare(T entity,T obj);
}

I am trying to implement another generic class

public class EntityTest<T> {

  public void testPutObject(Client client, T obj ) throws UnExpectedStatusException 
    {
        log.debug("PUT: " + location);
      T entity = testGetObject(client,entityLocation,l);

     if(entity instanceof ClientServerComparator<?> )
     {
        if( false ==  ((ClientServerComparator<?>) entity).compare(entity,obj) )
        {
            log.error("Object fetched back does not match object put");
            throw new UnExpectedStatusException();
        }

     }

    }

I receive the following compiler error:

The method compare(capture#1-of ?, capture#1-of ?) in the type 
ClientServerComparator<capture#1-of ?> is not applicable for the arguments (T, T)

How do I make the EntityTest generic class call a method on an object that implements ClientServerComparator generic interface?

I think the problem is that the wildcard you are using tells the compiler, that entity is any ClientServerComparator, not necessarily related to T.

However, you already know that entity is of type T (which you have defined by the type annotation where you instantiate entity). Also, you are checking whether entity is an instance of ClientServerComparator. I am assuming, that you always expect entity to be an instance of ClientServerComparator. If this is the case, then you can change the generic type of EntityTest to <T extends ClientServerComparator<T>> and get rid of the instanceof check and the type cast:

public class EntityTest<T extends ClientServerComparator<T>> {

    public void testPutObject(Client client, T obj) {
        T entity = testGetObject(client);

        if (entity.compare(entity, obj)) {
            throw new UnExpectedStatusException();
        }

    }
}

Now T is a ClientServerComparator<T> , hence you can call compare on entity.

T is a type variable in both your class EntityTest and in ClientServerComparator . But it's a variable and that means that it doesn't denote the same type in your two classes. You could have called T by another name like Z in ClientServerComparator and it would not change anything about the meaning of your code.

So, to invoke the compare method on two objects of type variable T , you first need to cast your object to ClientServerComparator<T> instead of ClientServerComparator<?> . In the latter case, it doesn't know what the type is ( <?> ) so you cannot invoke any methods with arguments of the generic type [you can only invoke methods that return the generic type]

If you cast to (ClientServerComparator<T>) you will get a warning from the compiler about an "unchecked cast". This is because in Java, generics are only compile-time type-safe. At runtime, the actual value of type variable T is not known anymore.

So technically it is possible that you have a class Foo that implements ClientServerComparator<Bar> . If you know that you don't ever have this in your code, you can suppress that compiler warning with the @SuppressWarnings("unchecked") annotation.

Like this:

@SuppressWarnings("unchecked")
public void testPutObject(Client client, T obj) throws UnExpectedStatusException {
    T entity = testGetObject(client, entityLocation, l);

    if (entity instanceof ClientServerComparator) {
        if (false == ((ClientServerComparator<T>) entity).compare(entity, obj)) {
            throw new UnExpectedStatusException();
        }
    }

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM