Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 1015745
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 16, 20262026-05-16T10:26:48+00:00 2026-05-16T10:26:48+00:00

Let’s first consider a simple scenario ( see complete source on ideone.com ): import

  • 0

Let’s first consider a simple scenario (see complete source on ideone.com):

import java.util.*;

public class TwoListsOfUnknowns {
    static void doNothing(List<?> list1, List<?> list2) { }

    public static void main(String[] args) {
        List<String> list1 = null;
        List<Integer> list2 = null;
        doNothing(list1, list2); // compiles fine!
    }
}

The two wildcards are unrelated, which is why you can call doNothing with a List<String> and a List<Integer>. In other words, the two ? can refer to entirely different types. Hence the following does not compile, which is to be expected (also on ideone.com):

import java.util.*;

public class TwoListsOfUnknowns2 {
    static void doSomethingIllegal(List<?> list1, List<?> list2) {
        list1.addAll(list2); // DOES NOT COMPILE!!!
            // The method addAll(Collection<? extends capture#1-of ?>)
            // in the type List<capture#1-of ?> is not applicable for
            // the arguments (List<capture#2-of ?>)
    }
}

So far so good, but here’s where things start to get very confusing (as seen on ideone.com):

import java.util.*;

public class LOLUnknowns1 {
    static void probablyIllegal(List<List<?>> lol, List<?> list) {
        lol.add(list); // this compiles!! how come???
    }
}

The above code compiles for me in Eclipse and on sun-jdk-1.6.0.17 in ideone.com, but should it? Is it not possible that we have a List<List<Integer>> lol and a List<String> list, the analogous two unrelated wildcards situations from TwoListsOfUnknowns?

In fact the following slight modification towards that direction does not compile, which is to be expected (as seen on ideone.com):

import java.util.*;

public class LOLUnknowns2 {
    static void rightfullyIllegal(
            List<List<? extends Number>> lol, List<?> list) {

        lol.add(list); // DOES NOT COMPILE! As expected!!!
            // The method add(List<? extends Number>) in the type
            // List<List<? extends Number>> is not applicable for
            // the arguments (List<capture#1-of ?>)
    }
}

So it looks like the compiler is doing its job, but then we get this (as seen on ideone.com):

import java.util.*;

public class LOLUnknowns3 {
    static void probablyIllegalAgain(
            List<List<? extends Number>> lol, List<? extends Number> list) {

        lol.add(list); // compiles fine!!! how come???
    }
}

Again, we may have e.g. a List<List<Integer>> lol and a List<Float> list, so this shouldn’t compile, right?

In fact, let’s go back to the simpler LOLUnknowns1 (two unbounded wildcards) and try to see if we can in fact invoke probablyIllegal in any way. Let’s try the “easy” case first and choose the same type for the two wildcards (as seen on ideone.com):

import java.util.*;

public class LOLUnknowns1a {
    static void probablyIllegal(List<List<?>> lol, List<?> list) {
        lol.add(list); // this compiles!! how come???
    }

    public static void main(String[] args) {
        List<List<String>> lol = null;
        List<String> list = null;
        probablyIllegal(lol, list); // DOES NOT COMPILE!!
            // The method probablyIllegal(List<List<?>>, List<?>)
            // in the type LOLUnknowns1a is not applicable for the
            // arguments (List<List<String>>, List<String>)
    }
}

This makes no sense! Here we aren’t even trying to use two different types, and it doesn’t compile! Making it a List<List<Integer>> lol and List<String> list also gives a similar compilation error! In fact, from my experimentation, the only way that the code compiles is if the first argument is an explicit null type (as seen on ideone.com):

import java.util.*;

public class LOLUnknowns1b {
    static void probablyIllegal(List<List<?>> lol, List<?> list) {
        lol.add(list); // this compiles!! how come???
    }

    public static void main(String[] args) {
        List<String> list = null;
        probablyIllegal(null, list); // compiles fine!
            // throws NullPointerException at run-time
    }
}

So the questions are, with regards to LOLUnknowns1, LOLUnknowns1a and LOLUnknowns1b:

  • What types of arguments does probablyIllegal accept?
  • Should lol.add(list); compile at all? Is it typesafe?
  • Is this a compiler bug or am I misunderstanding the capture conversion rules for wildcards?

Appendix A: Double LOL?

In case anyone is curious, this compiles fine (as seen on ideone.com):

import java.util.*;

public class DoubleLOL {
    static void omg2xLOL(List<List<?>> lol1, List<List<?>> lol2) {
        // compiles just fine!!!
        lol1.addAll(lol2);
        lol2.addAll(lol1);
    }
}

Appendix B: Nested wildcards — what do they really mean???

Further investigation indicates that perhaps multiple wildcards has nothing to do with the problem, but rather a nested wildcard is the source of the confusion.

import java.util.*;

public class IntoTheWild {

    public static void main(String[] args) {
        List<?> list = new ArrayList<String>(); // compiles fine!

        List<List<?>> lol = new ArrayList<List<String>>(); // DOES NOT COMPILE!!!
            // Type mismatch: cannot convert from
            // ArrayList<List<String>> to List<List<?>>
    }
}

So it looks perhaps a List<List<String>> is not a List<List<?>>. In fact, while any List<E> is a List<?>, it doesn’t look like any List<List<E>> is a List<List<?>> (as seen on ideone.com):

import java.util.*;

public class IntoTheWild2 {
    static <E> List<?> makeItWild(List<E> list) {
        return list; // compiles fine!
    }
    static <E> List<List<?>> makeItWildLOL(List<List<E>> lol) {
        return lol;  // DOES NOT COMPILE!!!
            // Type mismatch: cannot convert from
            // List<List<E>> to List<List<?>>
    }
}

A new question arises, then: just what is a List<List<?>>?

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-16T10:26:49+00:00Added an answer on May 16, 2026 at 10:26 am

    As Appendix B indicates, this has nothing to do with multiple wildcards, but rather, misunderstanding what List<List<?>> really means.

    Let’s first remind ourselves what it means that Java generics is invariant:

    1. An Integer is a Number
    2. A List<Integer> is NOT a List<Number>
    3. A List<Integer> IS a List<? extends Number>

    We now simply apply the same argument to our nested list situation (see appendix for more details):

    1. A List<String> is (captureable by) a List<?>
    2. A List<List<String>> is NOT (captureable by) a List<List<?>>
    3. A List<List<String>> IS (captureable by) a List<? extends List<?>>

    With this understanding, all of the snippets in the question can be explained. The confusion arises in (falsely) believing that a type like List<List<?>> can capture types like List<List<String>>, List<List<Integer>>, etc. This is NOT true.

    That is, a List<List<?>>:

    • is NOT a list whose elements are lists of some one unknown type.
      • … that would be a List<? extends List<?>>
    • Instead, it’s a list whose elements are lists of ANY type.

    Snippets

    Here’s a snippet to illustrate the above points:

    List<List<?>> lolAny = new ArrayList<List<?>>();
    
    lolAny.add(new ArrayList<Integer>());
    lolAny.add(new ArrayList<String>());
    
    // lolAny = new ArrayList<List<String>>(); // DOES NOT COMPILE!!
    
    List<? extends List<?>> lolSome;
    
    lolSome = new ArrayList<List<String>>();
    lolSome = new ArrayList<List<Integer>>();
    

    More snippets

    Here’s yet another example with bounded nested wildcard:

    List<List<? extends Number>> lolAnyNum = new ArrayList<List<? extends Number>>();
        
    lolAnyNum.add(new ArrayList<Integer>());
    lolAnyNum.add(new ArrayList<Float>());
    // lolAnyNum.add(new ArrayList<String>());     // DOES NOT COMPILE!!
    
    // lolAnyNum = new ArrayList<List<Integer>>(); // DOES NOT COMPILE!!
    
    List<? extends List<? extends Number>> lolSomeNum;
        
    lolSomeNum = new ArrayList<List<Integer>>();
    lolSomeNum = new ArrayList<List<Float>>();
    // lolSomeNum = new ArrayList<List<String>>(); // DOES NOT COMPILE!!
    

    Back to the question

    To go back to the snippets in the question, the following behaves as expected (as seen on ideone.com):

    public class LOLUnknowns1d {
        static void nowDefinitelyIllegal(List<? extends List<?>> lol, List<?> list) {
            lol.add(list); // DOES NOT COMPILE!!!
                // The method add(capture#1-of ? extends List<?>) in the
                // type List<capture#1-of ? extends List<?>> is not 
                // applicable for the arguments (List<capture#3-of ?>)
        }
        public static void main(String[] args) {
            List<Object> list = null;
            List<List<String>> lolString = null;
            List<List<Integer>> lolInteger = null;
    
            // these casts are valid
            nowDefinitelyIllegal(lolString, list);
            nowDefinitelyIllegal(lolInteger, list);
        }
    }
    

    lol.add(list); is illegal because we may have a List<List<String>> lol and a List<Object> list. In fact, if we comment out the offending statement, the code compiles and that’s exactly what we have with the first invocation in main.

    All of the probablyIllegal methods in the question, aren’t illegal. They are all perfectly legal and typesafe. There is absolutely no bug in the compiler. It is doing exactly what it’s supposed to do.


    References

    • Angelika Langer’s Java Generics FAQ
      • Which super-subtype relationships exist among instantiations of generic types?
      • Can I create an object whose type is a wildcard parameterized type?
    • JLS 5.1.10 Capture Conversion

    Related questions

    • Any simple way to explain why I cannot do List<Animal> animals = new ArrayList<Dog>()?
    • Java nested wildcard generic won’t compile

    Appendix: The rules of capture conversion

    (This was brought up in the first revision of the answer; it’s a worthy supplement to the type invariant argument.)

    5.1.10 Capture Conversion

    Let G name a generic type declaration with n formal type parameters A1…An with corresponding bounds U1…Un. There exists a capture conversion from G<T1…Tn> to G<S1…Sn>, where, for 1 <= i <= n:

    1. If Ti is a wildcard type argument of the form ? then …
    2. If Ti is a wildcard type argument of the form ? extends Bi, then …
    3. If Ti is a wildcard type argument of the form ? super Bi, then …
    4. Otherwise, Si = Ti.

    Capture conversion is not applied recursively.

    This section can be confusing, especially with regards to the non-recursive application of the capture conversion (hereby CC), but the key is that not all ? can CC; it depends on where it appears. There is no recursive application in rule 4, but when rules 2 or 3 applies, then the respective Bi may itself be the result of a CC.

    Let’s work through a few simple examples:

    • List<?> can CC List<String>
      • The ? can CC by rule 1
    • List<? extends Number> can CC List<Integer>
      • The ? can CC by rule 2
      • In applying rule 2, Bi is simply Number
    • List<? extends Number> can NOT CC List<String>
      • The ? can CC by rule 2, but compile time error occurs due to incompatible types

    Now let’s try some nesting:

    • List<List<?>> can NOT CC List<List<String>>
      • Rule 4 applies, and CC is not recursive, so the ? can NOT CC
    • List<? extends List<?>> can CC List<List<String>>
      • The first ? can CC by rule 2
      • In applying rule 2, Bi is now a List<?>, which can CC List<String>
      • Both ? can CC
    • List<? extends List<? extends Number>> can CC List<List<Integer>>
      • The first ? can CC by rule 2
      • In applying rule 2, Bi is now a List<? extends Number>, which can CC List<Integer>
      • Both ? can CC
    • List<? extends List<? extends Number>> can NOT CC List<List<Integer>>
      • The first ? can CC by rule 2
      • In applying rule 2, Bi is now a List<? extends Number>, which can CC, but gives a compile time error when applied to List<Integer>
      • Both ? can CC

    To further illustrate why some ? can CC and others can’t, consider the following rule: you can NOT directly instantiate a wildcard type. That is, the following gives a compile time error:

        // WildSnippet1
        new HashMap<?,?>();         // DOES NOT COMPILE!!!
        new HashMap<List<?>, ?>();  // DOES NOT COMPILE!!!
        new HashMap<?, Set<?>>();   // DOES NOT COMPILE!!!
    

    However, the following compiles just fine:

        // WildSnippet2
        new HashMap<List<?>,Set<?>>();            // compiles fine!
        new HashMap<Map<?,?>, Map<?,Map<?,?>>>(); // compiles fine!
    

    The reason WildSnippet2 compiles is because, as explained above, none of the ? can CC. In WildSnippet1, either the K or the V (or both) of the HashMap<K,V> can CC, which makes the direct instantiation through new illegal.

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

Let's have an example like below: package xliiv.sandbox; import android.app.Activity; import android.os.Bundle; import android.util.Log;
Let's consider the following scenario: I've a master table with a detail table. The
Let's imagine I have a Java class of the type: public class MyClass {
Let's say I have a method in java, which looks up a user in
Let me try to explain by example. Say website is hosted at example.com (NOT
Let's say I have an facebook application running using the JS SDK. First user
Let's say, if I need to assign an id to element with first name,
Let's say I have multiple requirements for a password. The first is that the
Let's say I have the following classes : public class MyProductCode { private String
Let say I've this URL: http://example.com/image-title/987654/ I want to insert download to the part

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.