1

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;
    }

}
MonkeyJLuffy
  • 195
  • 3
  • 15
  • Sounds like an [XY problem](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). ` void` is not doing what you think it's doing. You're defining a new generic type parameter using the identifier "String". It may as well say ` void`. You should remove it. Only problem is that when you do, the method is not correctly overriding the method from the interface – Michael Nov 23 '18 at 13:46
  • 1
    The problem is that `Generic` specifies that any implementers should be able to implement `setGenericObject` for *all* values of `T`. Your implementation only works for strings, so it is not fulfilling the contract as defined by the interface. The best way to achieve what you want is to have `Generic` and `GenericImpl implements Generic` but you said you don't want to do that – Michael Nov 23 '18 at 13:48
  • plaese see https://stackoverflow.com/questions/7433279/is-it-possible-to-have-an-interface-method-defined-with-a-generic-return-type-an – chenzhongpu Nov 23 '18 at 13:53
  • Ok. @Michael Do you think there are any way to solve my problem without doing `@SuppressWarning` ? – MonkeyJLuffy Nov 23 '18 at 14:07

2 Answers2

1

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?.

chenzhongpu
  • 6,193
  • 8
  • 41
  • 79
  • Ok, I understand that my `` tag is like ``, but what do you propose to solve my problem ? And keep in mind that I don't want to do `Generic` – MonkeyJLuffy Nov 23 '18 at 14:02
0

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);
    }
}
yyyy
  • 593
  • 2
  • 10