简体   繁体   中英

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?

Neither of your methods should be using wildcard captures, you have two methods that are generic against some T . Like,

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

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

If you want to ensure that T must be a Number for some reason (I would just use Number then), you define it at T . Like,

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

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

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM