1

For example, if I have the following class:

class MyObject<T> {}

Why is this possible:

class Main {
    public static void main(String[] args) {        
        MyObject<MyObject<?>> moMo = new MyObject<MyObject<?>>();
    }
}

but not this:

class Main {
    public static void main(String[] args) {
        MyObject<?> mo = new MyObject<?>();
    }
}

I don't understand why one of these would be possible and not the other. I'm starting to believe that these many little discrepancies weren't intentionally designed, but are instead just quirks in the language.


I understand there have been similar questions asked on here (this, this, and this); however, none have answered why one is allowed and not the other.

johnnyodonnell
  • 1,838
  • 3
  • 16
  • 34

1 Answers1

0

Consider

    List<?> list1 = new ArrayList<>();
    List<?> list2 = new ArrayList<List<?>>();
    List<?> list3 = new ArrayList<?>(); // WRONG

    list2.add(new ArrayList<Integer>()); // WRONG

In the third wrong case an actual List is created with a generic parameter class not bound to the declared parameter class on the left (also ?). A wild card type may not be instantiated directly.

You might do new ArrayList<Integer>() (or new ArrayList()) telling what type is allowed. These are stored in Class.getType parameters(). Hence new ArrayList<?>() cannot be stored in the objects actual class for that ArrayList instance. Runtime class erasure does not hold 100% for generic classes.

In the second case this immediate instantiation does not happen.

That such usage of wild card types are cumbersome/impractical is shown by the add, where the actual list2 might be a List<List<String>> instead.

For those that have experience stronger type systems in other languages: better refrain from trying to use too clever type expressions.

Joop Eggen
  • 107,315
  • 7
  • 83
  • 138
  • There are a lot of good points in this answer, but ultimately it doesn't answer my question. You mention that **a wildcard type may not be instantiated directly**, but my question is *why*? I'm especially curious because it's perfectly fine to instantiate it indirectly. – johnnyodonnell Sep 16 '19 at 15:41
  • I have added to the answer (_"You might do...."_). I hope the explanation is indeed correct. – Joop Eggen Sep 16 '19 at 15:54
  • I don't believe those types are available through `Class#getTypeParameters`. `Class#getTypeParameters` just returns the name of the generic parameter name. So for `Map` it returns `K` and `V`, rather than `String` and `String` – johnnyodonnell Sep 16 '19 at 16:08