0

I have the following code that give me trouble compiling.

Give me this error

Error:(20, 22) java: incompatible types: com.company.Main.Impl cannot be converted to T

I only need that interface to work in this function, and I don't want to change the function body much.

Why doesn't this work? and How could I make this work?

    package com.company;

public class Main {

    class Impl implements someinterface, anotherinterface{

        @Override
        public Integer getInteger() {
            return 0;
        }
    }

    class BigObject{
        public Impl get(){
            return new Impl();
        }
    }

    private <T extends someinterface & anotherinterface> Integer myfunc(BigObject bg){

        T xy = bg.get(); // this line will not compile????
        if (xy.isOK()) // from someinterface 
           return xy.getInteger(); // from anotherinterface
        return null;
    }


    public static void main(String[] args) {
    // write your code here
    }
}
15
  • 1
    Why do you even need the generic parameter in the first place? From the looks of it, someinterface (which should be written in CamelCase), contains only the method getInteger(). You can replace T with someinterface Commented Jan 12, 2018 at 15:44
  • 5
    T is something that implements someinterface; it's not necessarily an Impl. Just use someinterface xy = ... instead. Commented Jan 12, 2018 at 15:45
  • 2
    Generics here are nonsensical. Remove the generic declaration and replace T xy = bg.get(); with someinterface xy = bg.get(); then debug. Commented Jan 12, 2018 at 15:45
  • 1
    @user40129 Then create a newinterface extends someinterface, anotherinterface and replace T with newinterface. Commented Jan 12, 2018 at 15:59
  • 2
    @user40129 Again the question: why do you need generics? Why not replace T with Impl? Commented Jan 12, 2018 at 16:21

2 Answers 2

2

It won't compile because in Java, generics are invariant, see related post.

With the following line of code:

<T extends SomeInterface> Integer myfunc(BigObject bg) { ... }

you are saying that T is something that is some kind of SomeInterface, or, more precisely, a certain type that is a subtype of SomeInterface. The compiler complains about T xy = bg.get(), because bg.get() returns a certain subtype of T, but that type may or may not be the same as Impl.

As an analogy, you are saying something like this:

class Cat extends Animal { }
class AnimalObj {
    public Cat get() {
        return new Cat();
    }
}

private <T extends Animal> Integer myfunc(AnimalObj bg) {
    T xy = bg.get();
    ...
}

T could be a Cat, but it could also be a Dog. Who knows. So that's why the compiler complains.

If you don't care about the subtype, you should drop generics, and write this instead:

private Integer myfunc(AnimalObj bg) {
    Animal xy = bg.get();
    ...
}

Since myFunc accepts a BigObject, which is able to deliver a concrete Impl, you could just replace <T extends someinterface & anotherinterface> by Impl.


Read more

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

8 Comments

Yes it can also be a Dog, does it matter. myfunc cares only about any type of Animal. Right?
No, not quite. Not "any type of Animal" (then we could just write Animal xy = ...) but merely "a specific, but unknown type which is a subclass of Animal". They are not the same.
Right, but the compiler should complain if bg.get() doesn't have those interfaces, why does the compiler wants to check more than that?
@user40129 According to that logic, Dog d = new Cat() would be possible, if they both implement Strokeable. The fact that two classes implement the same interfaces, doesn't mean they are interchangeable.
@MCEmperor, If <T extends strokable&willpee>, T d canott be a new Cat()?
|
0

Lets change the myfunc a little bit so that it will return the generic type T:

private static <T extends someinterface & anotherinterface> T myfunc(BigObject bg){
    return bg.get();
}

Now you can call it like this:

Impl i1 = myfunc( new BigObject() );

and like this:

Impl2 i2 = myfunc( new BigObject() );

But if BigObject.get would have only returned Impl you would have error with second call that expected Impl2.

8 Comments

this doesn't compile. and gives an error at bg.get()
Yes it does not because bg.get() is only returning Impl. The example I gave shows that with signature myfunc has, bg.get() function cannot just return Impl. The compiler cannot make sure that the caller of myfunc wont specify Impl2 for T.
a reasonable compiler will let you compile the function but neither of the function calls. Because it doesn't know if that generic type returned can be translated to Impl/Impl2, but if il is of type <T extends someinterface&anotherinterface> (instead of Impl/Impl2), function calls should compile, since there is no ambiguity.
Yes, that is why as others suggested you need to change bg.get() to be public <T extends someinterface & anotherinterface> T get(). This way compiler can be sure that bg.get() will handle Impl and Impl2.
don't think that's what they suggests, because public <T extends someinterface & anotherinterface> T get() on BigObject will not compile.
|

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.