javagenericswildcarderasure

Conflict between return type and method parameter when return type is 'T' and method parameter consist of wild card


I'm trying to run a code. i and i get two compilation errors: 1.Reference to System.out.println is ambiguous (conflict between method that gets char[] and a method that gets a String) 2.Cap#1 can't converted to T return st.pop()

import java.util.*;
public class Test
{
    public static void main(String[] args)
    {
        Stack <Number> stackNumber = new Stack<Number>();
            Test t = new Test();
        t.setMethod(stackNumber,new Integer(3));
        System.out.println(t.getMethod(stackNumber));
    }

    public <T extends Number> void setMethod (Stack<? super Number>st,T t)
    {
     st.add(t);
    }   

    public <T>T getMethod (Stack<? extends Number >st)
    {
        return st.pop();
    } 
}   

I know that i can change getMethod signature to return Number and program will be compiled successfully but i want to understand why with current signature i'm getting compilation errors? AFAIK, T without bounds considered as Object and a function that declares to return Object can return any Object since Object is the "Father" of all classes (including Number). Can someone me what i'm dismissing here?


Solution

  • but i want to understand why with current signature i'm getting compilation errors?

    The errors are both because <T> is determined at the call site.

    Looking at compilation error 1:

    Java selects the most specifically-applicable method. Any of the PrintStream.println methods that take a reference-typed parameter could be selected.

    From JLS 15.12.2.5:

    The informal intuition is that one method is more specific than another if any invocation handled by the first method could be passed on to the other one without a compile-time error.

    Anything that you can pass to println(char[]) or println(String) can also be passed to println(Object), therefore the former methods are more specific than the latter. As such, these will be selected in preference to println(Object).

    However, some things that can be passed to println(char[]) cannot be passed to println(String), therefore neither of those is more specific than the other, hence the ambiguous method call.


    Now looking at compilation error 2:

    public <T>T getMethod (Stack<? extends Number >st)
    {
        return st.pop();
    }
    

    This method must be safe to invoke in all situations. You invoke it like this:

    System.out.println(t.getMethod(stackNumber));
    

    i.e. you treat the result simply like an object. But you could, legally, write this at the call site:

    String s = t.getMethod(stackNumber);
    

    It's hopefully clear that this would fail, because something popped out of a stack containing numbers can't be cast to a String.

    Because the compiler can't guarantee that it will be called with a "safe" T, it's an error.