Java Generics: List, List<Object>, List<?>

后端 未结 12 1880
你的背包
你的背包 2020-11-22 17:08

Can someone explained, as detailed as possible, the differences between the following types?

List
List
List


Let me m

相关标签:
12条回答
  • 2020-11-22 17:44

    In my own simple terms:

    List

    Would declare an ordinary collection, can hold any type, and will always return Object.

    List<Object>

    Will create a list that can hold any type of object, but can only get assigned a another List<Object>

    For instance this doesn't work;

    List<Object> l = new ArrayList<String>();
    

    Of course you can add anything but only can pull Object.

    List<Object> l = new ArrayList<Object>();
    
    l.add( new Employee() );
    l.add( new String() );
    
    Object o = l.get( 0 );
    Object o2 = l.get( 1 );
    

    Finally

    List<?>

    Will let you assign any type, including

    List <?> l = new ArrayList(); 
    List <?> l2 = new ArrayList<String>();
    

    This would be called collection of unknown and since the common denominator of unknown is Object you will be able to fetch Objects ( a coincidence )

    The importance of unknown comes when its used with subclassing:

    List<? extends Collection> l = new ArrayList<TreeSet>(); // compiles
    
    List<? extends Collection> l = new ArrayList<String>(); // doesn't,
    // because String is not part of *Collection* inheritance tree. 
    

    I hope using Collection as the type doesn't create confusion, that was the only tree that came to my mind.

    The difference here, is that l is a collection of unknow that belongs to the Collection hierarchy.

    0 讨论(0)
  • 2020-11-22 17:44

    List, List<?>, and List<? extends Object> are the same thing. The second is more explicit. For a list of this type, you cannot know what types are legal to put into it, and you don't know anything about the types you can get out of it, except that they will be objects.

    List<Object> specifically means that the list contains any sort of object.

    Let's say we make a list of Foo:

    List<Foo> foos= new ArrayList<Foo>();
    

    It is not legal to put a Bar into foos.

    foos.add(new Bar()); // NOT OK!
    

    It is always legal to put anything into a List<Object>.

    List<Object> objs = new ArrayList<Object>();
    objs.add(new Foo());
    objs.add(new Bar());
    

    But you mustn't be allowed to put a Bar into a List<Foo> - that's the whole point. So that means that this:

    List<Object> objs = foos; // NOT OK!
    

    is not legal.

    But it's ok to say that foos is a list of something but we don't know specifically what it is:

    List<?> dontKnows = foos;
    

    But that then means that it must be prohibited to go

    dontKnows.add(new Foo()); // NOT OK
    dontKnows.add(new Bar()); // NOT OK
    

    because the variable dontKnows does't know what types are legal.

    0 讨论(0)
  • 2020-11-22 17:48

    I refer you to the excellent Java Generics tutorial, and the "advanced" Generics tutorial, both available from Sun Microsystems. Another great resource is the Java Generics and Collections book.

    0 讨论(0)
  • 2020-11-22 17:49

    As the other posts have noted, you are asking about a Java feature called generics. In C++, this is called templates. This feature in Java is usually easier to work with than the that found in C++.

    Let me answer your questions functionally (if that's not a naughty word for OO discussions).

    Before generics, there were concrete classes like Vector.

    Vector V = new Vector();
    

    Vectors hold any object you give them.

    V.add("This is an element");
    V.add(new Integer(2));
    v.add(new Hashtable());
    

    They do this by casting all values given to it into an Object (the root of all Java classes). When you attempt to retrieve the values stored in your Vector, you need to cast the value back into the original class (if you want to do anything meaningful with it).

    String s = (String) v.get(0);
    Integer i = (Integer) v.get(1);
    Hashtable h = (Hashtable) v.get(2);
    

    Casting gets old fast. More than that, the compiler complains to you about unchecked casts. The most urgent problem with casting like this is that consumers of your Vector have to know the classes of its values at compile time in order to cast correctly. In cases where the producer of the Vector and the consumer of the same are completely isolated from each other (think RPC messages), this can be a fatal issue.

    Enter generics. Generics attempt to create strongly typed classes to do generic operations.

    ArrayList<String> aList = new ArrayList<String>();
    aList.add("One");
    String element = aList.get(0); // no cast needed
    System.out.println("Got one: " + element); 
    

    The Design Patterns book encourages the reader to think in terms of contracts, not concrete types. There is wisdom (and code re-use) in divorcing variables from their implementing class.

    With this in mind, you might think that all implementations List objects should do the same set of things: add(), get(), size(), etc. With a little reflection, you can imagine many implementations of List operations that obey the List contract in various ways (e.g. ArrayList). However, the type of data these objects deal with is orthogonal to the actions performed on them.

    Put it all together and you'll see the following kinds of code frequently:

    List<String> L = new ArrayList<String>();
    

    You should read that as "L is a kind of List that deals with String objects". When you start dealing with Factory classes, it is critical to deal with contracts rather than specific implementations. Factories produce objects of various types at runtime.

    Using generics is pretty easy (most of the time).

    One day you may decide you want to implement your own generic class. Perhaps you want to write a new database abstraction interface that elides the differencesbetween various data stores. When you define that generic class, you will use <t> as a placeholder for the kind of object that will be manipulated by the methods.

    If you are still confused, use the generic classes for List until you are comfortable. Later, you can dive into the implementation with a bit more confidence. Or you can look at the source code for the various List classes that ship with the JRE. Open source is great that way.

    Have a look at the Oracle/Sun docs about generics. Cheers.

    0 讨论(0)
  • 2020-11-22 17:52

    When would I want to use

    public void CanYouGiveMeAnAnswer( List l ){}
    

    When you cant to do all the casting your self.

    When would I want to use

    public void CanYouGiveMeAnAnswer( List l<Object> ){}
    

    When you want to restrict the type of the List. For instance, this would be an invalid argument.

     new ArrayList<String>();
    

    When would I want to use

    public void CanYouGiveMeAnAnswer( List l<?> ){}
    

    Mostly never.

    0 讨论(0)
  • 2020-11-22 17:54

    Simplest explanation which is not "RTFM":

    List
    

    Will generate lots of compiler warnings, but is mostly equivalent to:

    List<Object>
    

    While:

    List<?>
    

    basically means its something generic, but you don't know what the generic type is. Its great for getting rid of compiler warnings when you cant modify the return types of other things that just returned List. Its much more useful in the form:

    List<? extends SomeOtherThing>
    
    0 讨论(0)
提交回复
热议问题