How does the ternary operator evaluate the resulting datatype?

Given this piece of code

public class Main {

    public static void main(String[] args) {
        foo(1);
        foo("1");
        foo(true?1:"1");
        foo(false?1:"1");
    }

    static void foo(int i){System.out.println("int");}
    static void foo(String s){System.out.println("String");}
    static void foo(Object o){System.out.println("Object");}
}

This is the output I get:

int
String
Object
Object

I can't understand why in the last two cases foo(Object o) is invoked, instead of foo(int i) and foo(String s). Isn't the return type for a ternary expression evaluated at runtime?

Edit:

What was confusing me is the assertion that

System.out.println((y>5) ? 21 : "Zebra");

compiles because (OCA Study Guide - Sybex):

The System.out.println() does not care that the statements are completely differnt types, because it can convert both to String

while the point is that println is overloaded to accept Object types as input. Quite misleading, imho.

Jon Skeet
people
quotationmark

Isn't the return type for a ternary expression evaluated at runtime?

No, absolutely not. That would be very contrary to the way Java works, where overload resolution etc is always performed at compile-time. What would you expect to happen if you hadn't passed the result to a method, but tried to assign it to a variable? What sort of variable would you have declared?

The expression's type is governed by the rules of JLS 15.25. In both your cases, the third operand is of type String, leading to this being a reference conditional expression, so table 15.25-E is applied, with a result of lub(Integer,Object). The lub part refers to JLS 4.10.4, which is fairly confusing - the type here isn't exactly the same as just Object, but in most cases it can be considered that way.

people

See more on this question at Stackoverflow