1

I encountered the following code in Joshua Bloch's Effective Java book but I can't understand why the pickTwo method returns Object[]? The method toArray returns Integer[]. So why does pickTwo return Object[]? I think it should return Integer[].

Joshua Bloch's book says that:

The type of this array is determined by the compile-time types of the arguments passed in to the method, and the compiler may not have enough information to make an accurate determination. Because this method returns its varargs parameter array, pickTwo will always return an array of type Object[].

public class JavaApplication52 {

    public static void main(String[] args) {
     System.out.println(toArray(1,2,3));
     System.out.println(pickTwo(1,2,3));
    }

    static <T> T[] pickTwo(T a, T b, T c) {
        switch (ThreadLocalRandom.current().nextInt(3)) {
            case 0:
                return toArray(a, b);
            case 1:
                return toArray(a, c);
            case 2:
                return toArray(b, c);
        }
        throw new AssertionError(); // Can't get here
    }

    static <T> T[] toArray(T... args) {
        return args;
    }
}

OUTPUT:

[Ljava.lang.Integer;@6d06d69c
[Ljava.lang.Object;@70dea4e
Boann
  • 44,932
  • 13
  • 106
  • 138
3code
  • 55
  • 6
  • The erasure of `T` is `Object`, so the erasure of `T[]` is `Object[]`. – Daniel Pryden Apr 08 '18 at 21:54
  • @DanielPryden I'm going to assume the OP does not understand the concept of erasure in the compiler (I barely do). Does my gross wording below capture the gist of it? – Ray Apr 08 '18 at 21:58
  • @DanielPryden I’m sure this question is a duplicate, but not of that question. This question is specifically about varargs. – cpp beginner Apr 08 '18 at 22:01
  • 1
    Yes, more or less. The authoritative Java language specification actually explains erasure reasonably well. The basic idea is that compile-time types and runtime types, while related to each other, are not actually the same thing. This is true (to one degree or another) in practically every programming language I know, so it's not a fundamentally strange concept. But the rules for exactly what runtime type an expression has, relative to its compile-time type, are... subtle, to say the least. And as each version of Java adds more complex type inference rules, it keeps getting more complicated. – Daniel Pryden Apr 08 '18 at 22:02
  • @cppbeginner: Yes, I was searching for a good duplicate and I couldn't find a great one, but it's easy to edit the duplicate list. Do you have a link to a better duplicate? – Daniel Pryden Apr 08 '18 at 22:02
  • 1
    @cppbeginner: OK, I found a better duplicate. How does that look? – Daniel Pryden Apr 08 '18 at 22:04
  • Looks like a much better duplicate. – cpp beginner Apr 08 '18 at 22:04
  • @ Daniel Pryden Thanks.I didn't know that type information erase by erasure. – 3code Apr 08 '18 at 22:30

1 Answers1

2

You've explained yourself in your question. Since pickTwo() takes generics, when it calls toArray() the compiler has no idea with what class would have been passed to pickTwo() then used when calling toArray(). Since that can only be known at runtime, you just get Object ([Ljava.lang.Object;@70dea4e))

When you call toArray() explicitly with int's at compile time the compiler can determine what the return type will be.

Ray
  • 36,097
  • 17
  • 85
  • 129