1

This has probably been asked before but i haven't been able to find a question.

I would like to understand the underlying reasons why does the following block of code not compile:

public class Box<T> {

    private T value;

    public Box(T value) {
        this.value = value;
    }

    public T getValue() {
        return value;
    }

    public static void main(String[] args) {

        Box<Integer> i = new Box<Integer>(13);

        // does not compile
        Box<Object> o = i;
    }

}
John
  • 5,189
  • 2
  • 38
  • 62

4 Answers4

2

Firstly you cannot cast parameterized types. Check this oracle doc.

Typically, you cannot cast to a parameterized type unless it is parameterized by unbounded wildcards. For example:

List li = new ArrayList<>();
List ln = (List) li; // compile-time error

Hence the line Box<Object> o = i; causes compile time error.

Even though while creating Box object you have not specified the generic parameter, but using constructor parameter type java Type inference the constructing object's type.

Community
  • 1
  • 1
rajuGT
  • 6,224
  • 2
  • 26
  • 44
2

One way to look at it is, let's assume Box defined a void setValue(T val) method.

Box<Object> o = i;
o.setValue("a string");
Integer x = i.getValue(); // ?!
Vlad
  • 18,195
  • 4
  • 41
  • 71
2

The problem is mentioned in java documentation here (it is similar to Vlad's answer):

https://docs.oracle.com/javase/tutorial/extra/generics/subtype.html

Let's test your understanding of generics. Is the following code snippet legal?

List<String> ls = new ArrayList<String>(); // 1
List<Object> lo = ls; // 2 

Line 1 is certainly legal. The trickier part of the question is line 2. This boils down to the question: is a List of String a List of Object. Most people instinctively answer, "Sure!"

Well, take a look at the next few lines:

lo.add(new Object()); // 3
String s = ls.get(0); // 4: Attempts to assign an Object to a String!

Here we've aliased ls and lo. Accessing ls, a list of String, through the alias lo, we can insert arbitrary objects into it. As a result ls does not hold just Strings anymore, and when we try and get something out of it, we get a rude surprise.

Community
  • 1
  • 1
Vlasec
  • 5,500
  • 3
  • 27
  • 30
  • Thank you for the answer and link, it was very informative. However i have decided to accept vlad's answer since he offered that information first. – John Jan 22 '16 at 09:11
1

You can assign any reference to an Object reference but when generics kicks in, the exact generic type is matched at compile time. Hence it's not working. If you change to Box<? extends Object> o = i; it'll work since the generic type matches the contained type.

barunsthakur
  • 1,196
  • 1
  • 7
  • 18
  • Yup, those question marks are capturing the type somehow. You can't insert any random `Object` into that `Box extends Object>` though. It means "some particular subclass of `Object`". – Vlasec Jan 22 '16 at 09:14