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