0

I have found following code:

public class Ex7 {
    static class Translator<T1, T2 extends String> {
        T2 translate(T1 what) {
           return what + " ";
        }
    }
    public static void main(String[] args) {
        System.out.println(
            new Translator<Integer, String>().translate(1)
       );
    }
}

I don't understand why this code doesn't compile, since T2 is String and i want to return
String from the method "translate", compiler says that it expects T2 instead of String, but i understand that T2 is string as is is stated here:

new Translator<Integer, String>().translate(1)

Can someone please, explain this to me?

  • `T2 extends String` is legal, but nonsensical: nothing can `String`, because it's final. The only thing this method could safely return is `null`. – Andy Turner Dec 13 '19 at 10:45
  • Since you want to return a string and as mention String is final T2 is irrelevant here and might be removed from the declaration and the method should be "hardcoded" to return String. – Joakim Danielson Dec 13 '19 at 10:50

2 Answers2

1

T2 extends String is legal, but nonsensical. Nothing extends String, because it's a final class. However, the compiler doesn't stop you writing this because it doesn't consider final-ness of the bounding class.

Put String aside for a second, and consider these classes:

class A {}
class B extends A {}

If you declare a class like this:

static class Translator<T1, T2 extends A> {
    T2 translate(T1 what) {
       return new A();
    }
}

you can hopefully see why this would be illegal:

Translator<String, B> t = new Translator<>();
B result = t.translate("");

Here, result is expected to be an instance of B; but the implementation of the method means that it's returning an A. This is guaranteed to fail, so it's forbidden.

The compiler doesn't consider String any differently from A in this regard: there might be a subclass, so it bans you from returning a String where a subclass might be expected to be returned.

Andy Turner
  • 137,514
  • 11
  • 162
  • 243
  • the problem is, if we leave your code as it is and we only change translate method so that it returns new B() it wont compile either ... – Prezes Kozłowski Dec 13 '19 at 11:24
  • @PrezesKozłowski correct. Because the caller might expect it to return any subclass of `A`, perhaps `C` which is a direct subclass of `A`. You can't actually return anything from the method other than literal `null`. – Andy Turner Dec 13 '19 at 11:40
  • See also [this answer](https://stackoverflow.com/a/38095037/2711488), which demonstrates that even expecting `List` as return value of `translate` would be valid, as the caller might infer `X extends String&List` for `T2` without violating the `T2 extends String` constraint. Of course, the implementation of `translate` can't fulfill this expectation, as correctly said, "*You can't actually return anything from the method other than literal `null`*". The only alternatives are throwing an exception or never returning (i.e. looping endlessly). – Holger Dec 14 '19 at 17:28
0

since T2 is String

This is the essential part. A generic class is a template for instances that can use various types. If the method signature defines T2 it remains generic even if it has a constraint like extends String. T2 is never String, it is some unknown type that should extend String.

If the generic class does not consider that and returns a String it violates the method definition of returning T2.

ldz
  • 2,217
  • 16
  • 21