Java - Generics - Casting generic object in generic specified object doesn't work

586 Views Asked by At

I'm trying to resolve this apparently simple generic casting problem :

First, declaring this simple generic object :

public interface GenericObject<T> {}

Second, declaring this working interface :

public interface Generic { // I don't want to do Generic<T>

    <T> void setGenericObject(GenericObject<T> obj);

}

Then, let's implements this interface :

public class GenericImpl implements Generic {

    private GenericObject<String> genericObject; // This is needed

    @Override
    public <String> void setGenericObject(GenericObject<String> obj) {
        genericObject = obj; // eclipse give me this error :
                             // Type mismatch: cannot convert from 
                             // interfaces.GenericObject<String> to
                             // interfaces.GenericObject<java.lang.String>
    }

}

How can I solve this error ?

Edit :

Actualy, the only way I have to solve this issue is to do this :

public class GenericImpl implements Generic {

    private GenericObject<String> genericObject; 

    @SuppressWarnings("unchecked") // I don't realy like this
    @Override
    public <T> void setGenericObject(GenericObject<T> obj) {
        genericObject = (GenericObject<String>) obj;
    }

}
2

There are 2 best solutions below

1
On

The real problem is that

public <String> void setGenericObject(GenericObject<String> obj)

where the String has nothing to do with the your intended java.lang.String. Here the String is just a type parameter whose name is String by accident.

Please refer to Is it possible to have an interface method defined with a generic return type and a concrete implementation define the return type?.

0
On

Case 1:

If T is not used in Generic, then just use a wildcard.

class Generic {
    List<?> list;
    void set(List<?> list) {
        this.list = list;
    }
    int size() {
        return list.size(); // doesn't care about T
    }
}

Case 2:

If T is only used as local variables, then declare <T> on the method

class Generic {
    <T> void swapFirstAndSecond(List<T> list) {
        T first = list.get(0), second = list.get(1);
        list.set(1, first);
        list.set(0, second);
    }
}

Case 3:

If several fields and methods use the same type T, but the exact type of T is not important, then delacre <T> on the class

class Generic<T> {
    List<T> list;
    void set(List<T> list) {
        this.list = list;
    }
    T getFirst() {
        return list.get(0);
    }
}

Case 4:

If T must be a specific type, like String, then don't declare type parameter <T>

class Generic {
    List<String> list;
    void set(List<String> list) {
        this.list = list;
    }
    boolean isFirstContainsSecond() {
        String first = list.get(0), second = list.get(1);
        // call String.contains here, so T must be String
        return first.contains(second);
    }
}