A problem regarding generics

Discussion in 'Java' started by Vikram, Jun 6, 2010.

  1. Vikram

    Vikram Guest

    Hi,

    In java generics, the following code gives compile time error.

    List<Object> list = new ArrayList<String>(); // compile time error

    Where as the following does not give any compile time error

    List list = new ArrayList<String>();


    If no generics is specified, isin't it implied that it contains
    object? What is the reason the second statement does not give any
    compile time error?
    Vikram, Jun 6, 2010
    #1
    1. Advertising

  2. Vikram

    Tom Anderson Guest

    On Sun, 6 Jun 2010, Vikram wrote:

    > In java generics, the following code gives compile time error.
    >
    > List<Object> list = new ArrayList<String>(); // compile time error
    >
    > Where as the following does not give any compile time error
    >
    > List list = new ArrayList<String>();
    >
    > If no generics is specified, isin't it implied that it contains object?


    No. If it's omitted, it's what's called a 'raw' type, which means generics
    isn't used at all. That second list could contain anything. It would be
    legal to write:

    list.add("one");
    list.add(2);
    list.add(3.14159);

    See:

    http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#110257

    tom

    --
    Everything that has transpired has done so according to my design.
    Tom Anderson, Jun 6, 2010
    #2
    1. Advertising

  3. Vikram

    Eric Sosman Guest

    On 6/6/2010 7:02 AM, Vikram wrote:
    > Hi,
    >
    > In java generics, the following code gives compile time error.
    >
    > List<Object> list = new ArrayList<String>(); // compile time error


    I'll rewrite this slightly, to make it easy to refer
    to the left-hand and right-hand sides independently:

    List<String> slist = new ArrayList<String>();
    List<Object> olist = slist; // compile error

    When we fetch something from slist, we know that we'll get a
    String, right? That's the purpose of the <String> notation: It
    tells the compiler to complain if we try to put a non-String into
    slist. Since the compiler will ensure that we never put anything
    except Strings into slist, we know we will get only Strings out.

    Suppose, though, that the second line were legal, and that we
    could get olist to refer to the same ArrayList object as slist.
    Now, we could do

    olist.add("forty-two");
    olist.add(new Integer(42));
    olist.add(new Double(42.0);
    olist.add(new Color(42, 42, 42));
    olist.add(new JLabel("42"));

    .... since all of the things we are adding are Objects, and hence
    are acceptable to the <Object> notation of olist. Clear?

    But olist and slist refer to the same ArrayList, so what happens
    when we start fetching things from slist? We get all the things
    that were added through olist. Are they all Strings? Obviously not.
    What next? ClassCastException -- the very run-time error generics
    were invented to prevent.

    > Where as the following does not give any compile time error
    >
    > List list = new ArrayList<String>();


    Here, the `list' List makes no guarantees. The compiler will
    allow you to add anything at all via the `list' reference. Also,
    the compiler will not assume that everything you fetch from `list' is
    a String. By omitting all <> notation, you are telling the compiler
    that all bets are off: You and you alone are responsible for what
    goes into and what comes out of the List, and the compiler will not
    try to prevent you from doing something silly.

    > If no generics is specified, isin't it implied that it contains
    > object? What is the reason the second statement does not give any
    > compile time error?


    Mostly for interoperability with Java code written before generics
    came along. Suppose you are using somebody else's class, written in
    the pre-generic days, that has a method like

    /** Do something to a List of Strings.
    * @param list A List containing Strings.
    * @throws ClassCastException if "list" contains any
    * non-Strings.
    */
    void doSomething(List list) {
    for (Iterator it = list.iterator(); it.hasNext(); ) {
    String s = (String)it.next();
    ...
    }
    }

    You, being a modern and forward-looking person, are using generics
    in your own code, and since you need a List containing Strings and
    nothing but Strings, you've built a List<String>. Now, you'd like
    to call this other class' doSomething() method on your List<String>,
    but doSomething() takes a plain List. Clearly, your List<String>
    meets all the requirements of the List that doSomething() wants, so
    this should be allowed. And that, more or less, is why it's all
    right to use a "decorated" generic object where an "undecorated"
    non-generic version is called for.

    The on-line Java Tutorial has a section on generics that you
    might find helpful:

    <http://java.sun.com/docs/books/tutorial/java/generics/index.html>

    --
    Eric Sosman
    lid
    Eric Sosman, Jun 6, 2010
    #3
  4. Vikram

    Lew Guest

    Vikram wrote:
    >> Where as the following does not give any compile time error
    >>
    >> List list = new ArrayList<String>();


    Really? No error? What about the "unchecked" warning, then?

    Hm?

    Because I get errors (well, ok, warnings, but a warning is a flavor of error)
    about the use of a "raw type conversion" if I try that construct.

    >> If no generics is specified, isin't it implied that it contains
    >> object? What is the reason the second statement does not give any
    >> compile time error?


    "Foo extends Bar" does not mean "List <Foo> extends List <Bar>". This is
    explained in detail in every generics tutorial and reference.

    Which of course you've read.

    They then go on to explain that generics wildcards ("?" notation) resolve
    this, sort of.

    <http://java.sun.com/docs/books/tutorial/java/generics/subtyping.html>
    & ff.

    Eric Sosman wrote:
    > The on-line Java Tutorial has a section on generics that you
    > might find helpful:
    >
    > <http://java.sun.com/docs/books/tutorial/java/generics/index.html>


    Since you've read this tutorial thoroughly and it hasn't answered all our
    question, now read the free chapter (ch. 5) on generics from Joshua Bloch's
    /Effective Java/, available as a PDF download from
    <http://java.sun.com/docs/books/effective/java>

    <http://www.google.com/search?q=Java+generics+introduction>
    is another good resource. AMong other sources, that will steer you to
    <http://www.angelikalanger.com/Articles/JavaPro/01.JavaGenericsIntroduction/JavaGenerics.html>

    --
    Lew
    Lew, Jun 6, 2010
    #4
  5. In article <>,
    Tom Anderson <> wrote:

    > On Sun, 6 Jun 2010, Vikram wrote:
    >
    > > In java generics, the following code gives compile time error.
    > >
    > > List<Object> list = new ArrayList<String>(); // compile time error
    > >
    > > Where as the following does not give any compile time error
    > >
    > > List list = new ArrayList<String>();
    > >
    > > If no generics is specified, isin't it implied that it contains object?

    >
    > No. If it's omitted, it's what's called a 'raw' type, which means generics
    > isn't used at all. That second list could contain anything. It would be
    > legal to write:
    >
    > list.add("one");
    > list.add(2);
    > list.add(3.14159);
    >
    > See:
    >
    > http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#110257
    >
    > tom


    Java sometimes adds a non-generics method like this:

    public void add (Object foo)
    {
    add((SomeClass)foo);
    }

    It can lead to ClassCastException on nonexistent lines.
    --
    I won't see Google Groups replies because I must filter them as spam
    Kevin McMurtrie, Jun 6, 2010
    #5
  6. Vikram

    Lew Guest

    Tom Anderson wrote:
    >> See:
    >>
    >> http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#110257


    Kevin McMurtrie wrote:
    >>
    >> tom


    Don't quote sigs.

    > Java sometimes adds a non-generics method like this:


    When you say "Java ... adds", do you mean in the java[x].* packages?

    > public void add (Object foo)
    > {
    > add((SomeClass)foo);
    > }


    Can you give an example from the API?

    > It can lead to ClassCastException on nonexistent lines.


    What do you mean?

    --
    Lew
    Lew, Jun 6, 2010
    #6
  7. On 06/06/2010 07:02 AM, Vikram wrote:
    > Hi,
    >
    > In java generics, the following code gives compile time error.
    >
    > List<Object> list = new ArrayList<String>(); // compile time error


    Step back and think for a moment. Since we have a list of Strings, we
    need to forbid adding a generic Object to the list. Allowing you to cast
    List<String> to List<Object> would permit a list.add(new Object()),
    which is clearly not what we want to allow [1].

    What we want then is a list of things whose type we don't know--but we
    can guarantee them to be at least of type Object. The proper type for
    this is the wildcard List<? extends Object>; the typing rules would then
    allow you to observe a list.getFirst() as returning Object but prohibit
    you from adding a plain old Object to that list.

    > Where as the following does not give any compile time error
    >
    > List list = new ArrayList<String>();


    It doesn't give an error, but it does give you the unchecked conversion
    for using a raw type.

    > If no generics is specified, isin't it implied that it contains
    > object? What is the reason the second statement does not give any
    > compile time error?


    Actually, a raw type is roughly equivalent to List<?> [2]; List<?> is
    equivalent to List<? extends Object>.

    [1] The reason that the array analogue allows you to do Object[] o = new
    String[5]; is because the type of the array is stored, so actually
    saying o[1] = new Object(); will fail at runtime with an
    ArrayStoreException. The generic types are not reified in Java [3], so
    the compiler can't do the same guarantee at runtime that arrays do.

    [2] A main point of distinction: List.class is of type Class<List>, not
    Class<List<?>>, and you can't really convert between the two. Even the
    Java developers admit this is a mistake, but they won't fix it since
    doing so would break existing code. This has caused me a great deal of
    frustration...

    [3] Well, Collections.checkedList (et al.) do actually let you achieve
    the same runtime storage checking, and it is always possible to make
    your own wrappers for types you create. But it's not given to your for
    free by the language, owing mostly to the desire to gain
    backwards/forwards compatibility and partial library migration.
    --
    Beware of bugs in the above code; I have only proved it correct, not
    tried it. -- Donald E. Knuth
    Joshua Cranmer, Jun 6, 2010
    #7
  8. Vikram

    Daniel Pitts Guest

    On 6/6/2010 4:02 AM, Vikram wrote:
    > Hi,
    >
    > In java generics, the following code gives compile time error.
    >
    > List<Object> list = new ArrayList<String>(); // compile time error
    >
    > Where as the following does not give any compile time error
    >
    > List list = new ArrayList<String>();
    >
    >
    > If no generics is specified, isin't it implied that it contains
    > object? What is the reason the second statement does not give any
    > compile time error?


    List<? extends Object> list = new ArrayList<String>(); // compiles fine

    The difference between all three:

    List<Object> list = new ArrayList<String>();
    This says "A reference to List which can have any type of Objects added
    and retrieved is assigned a List which can only have Strings added and
    retrieved "

    List list = new ArrayList<String>();
    This says "A reference to a List which is of a Raw type, is assigned a
    List which can only have Strings added and retrieved. "
    The raw type remains as a backward compatibility in Java, and should not
    be used in new code if possible.

    List<? extends Object> list = new ArrayList<String>();
    This says "A reference to a List which can have any Object retrieved,
    but only objects of an unknown type can be added, is assigned a List
    which can only have Strings added and retrieved. "

    --
    Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>
    Daniel Pitts, Jun 6, 2010
    #8
  9. Vikram

    markspace Guest

    Daniel Pitts wrote:

    > List<? extends Object> list = new ArrayList<String>(); // compiles fine


    > List<? extends Object> list = new ArrayList<String>();
    > This says "A reference to a List which can have any Object retrieved,
    > but only objects of an unknown type can be added, is assigned a List
    > which can only have Strings added and retrieved. "



    Small note: Since Object is the upper bound of all objects, <? extends
    Object is the same as just <?>:

    List<?> list = new ArrayList<String>();

    And of course for either both <?> and <? extends Object>, any generic
    type on the right hand side is compatible and can be assigned.

    Also, "only objects of an unknown type can be added" isn't quite
    correct. Since the type is unknown, you can't add any types, period.
    (Except possibly null, I'd have to check.) You can only remove Objects.
    markspace, Jun 7, 2010
    #9
  10. In article <hugmeo$5cm$>, Lew <>
    wrote:

    > Tom Anderson wrote:
    > >> See:
    > >>
    > >> http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#1102
    > >> 57

    >
    > Kevin McMurtrie wrote:
    > >>
    > >> tom

    >
    > Don't quote sigs.
    >
    > > Java sometimes adds a non-generics method like this:

    >
    > When you say "Java ... adds", do you mean in the java[x].* packages?
    >
    > > public void add (Object foo)
    > > {
    > > add((SomeClass)foo);
    > > }

    >
    > Can you give an example from the API?
    >
    > > It can lead to ClassCastException on nonexistent lines.

    >
    > What do you mean?


    Doh! I accidentally sent before I finished.

    Generics can break inheritance. For example, the generics declaration
    below demands that an override of put() take only a String as the key.
    At the same time, HashMap without generics must take an Object as a key.
    The compiler fixes this by adding a hidden method.

    This compiles with a warning:

    public class SnoopingMap<V> extends java.util.HashMap<String, V>
    {
    @Override
    public V put(String key, V value)
    {
    System.out.println(key + " -> " + value);
    return super.put(key, value);
    }

    public static void main (String args[])
    {
    SnoopingMap m= new SnoopingMap();
    m.put(new Integer(4), new Integer(5));
    }
    }

    But fails to run with an error on a bogus line number:

    Exception in thread "main" java.lang.ClassCastException:
    java.lang.Integer cannot be cast to java.lang.String
    at SnoopingMap.put(SnoopingMap.java:1)
    at SnoopingMap.main(SnoopingMap.java:13)


    The javap utility shows the hidden method:

    public java.lang.Object put(java.lang.Object, java.lang.Object);
    Signature: (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
    Code:
    0: aload_0
    1: aload_1
    2: checkcast #16; //class java/lang/String
    5: aload_2
    6: invokevirtual #17; //Method
    put:(Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;
    9: areturn

    LineNumberTable:
    line 1: 0


    That translates to this code, which will not compile if you add it
    yourself:

    public Object put(Object key, Object value)
    {
    return put((String)key, value);
    {
    --
    I won't see Google Groups replies because I must filter them as spam
    Kevin McMurtrie, Jun 7, 2010
    #10
  11. Vikram

    Lew Guest

    Kevin McMurtrie wrote:
    >>> It can lead to ClassCastException on nonexistent lines.


    Lew wrote:
    >> What do you mean?


    Kevin McMurtrie wrote:
    > Doh! I accidentally sent before I finished.
    >
    > Generics can break inheritance. For example, the generics declaration
    > below demands that an override of put() take only a String as the key.
    > At the same time, HashMap without generics must take an Object as a key.
    > The compiler fixes this by adding a hidden method.


    It adds an override method, but that's not so weird.

    > This compiles with a warning:
    >
    > public class SnoopingMap<V> extends java.util.HashMap<String, V>
    > {
    > @Override
    > public V put(String key, V value)
    > {
    > System.out.println(key + " -> " + value);
    > return super.put(key, value);
    > }
    >
    > public static void main (String args[])
    > {
    > SnoopingMap m= new SnoopingMap();
    > m.put(new Integer(4), new Integer(5));
    > }
    > }
    >
    > But fails to run with an error on a bogus line number:
    >
    > Exception in thread "main" java.lang.ClassCastException:
    > java.lang.Integer cannot be cast to java.lang.String
    > at SnoopingMap.put(SnoopingMap.java:1)


    I see what you mean by "bogus" line number, though I would not have chosen
    such an emotion-laden term myself.

    > at SnoopingMap.main(SnoopingMap.java:13)


    And there's your real error.

    > The javap utility shows the hidden method:
    > public java.lang.Object put(java.lang.Object, java.lang.Object);
    > Signature: (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
    > Code:
    > 0: aload_0
    > 1: aload_1
    > 2: checkcast #16; //class java/lang/String
    > 5: aload_2
    > 6: invokevirtual #17; //Method
    > put:(Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;
    > 9: areturn
    >
    > LineNumberTable:
    > line 1: 0
    >
    >
    > That translates to this code, which will not compile if you add it
    > yourself:
    >
    > public Object put(Object key, Object value)
    > {
    > return put((String)key, value);
    > {


    Adding that method by hand won't compile because it's erasure-equivalent to an
    override and doesn't conform to the generics requirements, and you can't have
    two erasure-equivalent methods in the same class.

    They have to have some method for doing type erasure. From what you show it's
    done by creating an override that does the class cast that you would have to
    have done by hand in pre-generics times.

    This does illustrate perfectly why you should avoid raw types - it defeats the
    purpose of generics and leads to ClassCastException to use them.

    --
    Lew
    Lew, Jun 7, 2010
    #11
  12. Vikram

    Daniel Pitts Guest

    On 6/6/2010 5:38 PM, markspace wrote:
    > Daniel Pitts wrote:
    >
    >> List<? extends Object> list = new ArrayList<String>(); // compiles fine

    >
    >> List<? extends Object> list = new ArrayList<String>();
    >> This says "A reference to a List which can have any Object retrieved,
    >> but only objects of an unknown type can be added, is assigned a List
    >> which can only have Strings added and retrieved. "

    >
    >
    > Small note: Since Object is the upper bound of all objects, <? extends
    > Object is the same as just <?>:
    >
    > List<?> list = new ArrayList<String>();
    >
    > And of course for either both <?> and <? extends Object>, any generic
    > type on the right hand side is compatible and can be assigned.
    >
    > Also, "only objects of an unknown type can be added" isn't quite
    > correct. Since the type is unknown, you can't add any types, period.
    > (Except possibly null, I'd have to check.) You can only remove Objects.

    You can't have an untyped reference, so I don't think the distinction is
    useful.

    Let me know the result of your test, I'd be interested in seeing it, and
    I'm too lazy/busy right now to right my own SSCCE.

    --
    Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>
    Daniel Pitts, Jun 8, 2010
    #12
  13. Vikram

    Arne Vajhøj Guest

    On 07-06-2010 20:04, Daniel Pitts wrote:
    > On 6/6/2010 5:38 PM, markspace wrote:
    >> Daniel Pitts wrote:
    >>> List<? extends Object> list = new ArrayList<String>(); // compiles fine

    >>
    >>> List<? extends Object> list = new ArrayList<String>();
    >>> This says "A reference to a List which can have any Object retrieved,
    >>> but only objects of an unknown type can be added, is assigned a List
    >>> which can only have Strings added and retrieved. "

    >>
    >> Small note: Since Object is the upper bound of all objects, <? extends
    >> Object is the same as just <?>:
    >>
    >> List<?> list = new ArrayList<String>();
    >>
    >> And of course for either both <?> and <? extends Object>, any generic
    >> type on the right hand side is compatible and can be assigned.
    >>
    >> Also, "only objects of an unknown type can be added" isn't quite
    >> correct. Since the type is unknown, you can't add any types, period.
    >> (Except possibly null, I'd have to check.) You can only remove Objects.

    > You can't have an untyped reference, so I don't think the distinction is
    > useful.
    >
    > Let me know the result of your test, I'd be interested in seeing it, and
    > I'm too lazy/busy right now to right my own SSCCE.


    If you mean add null, then it works.

    Arne
    Arne Vajhøj, Jun 8, 2010
    #13
  14. Vikram

    Roedy Green Guest

    On Sun, 6 Jun 2010 04:02:19 -0700 (PDT), Vikram
    <> wrote, quoted or indirectly quoted someone who
    said :

    >
    >In java generics, the following code gives compile time error.
    >
    >List<Object> list = new ArrayList<String>(); // compile time error
    >
    >Where as the following does not give any compile time error
    >
    >List list = new ArrayList<String>();
    >
    >
    >If no generics is specified, isin't it implied that it contains
    >object? What is the reason the second statement does not give any
    >compile time error?


    The problem comes because generics are implemented with purely
    compile-time checking. There is no record of the generic typing
    information available at run time. I think this was a mistake, but
    too late now.

    So there is on way Java could do a run-time check to make sure you did
    not add a Date to your List.

    The compiler can't reliably follow your logic at compile time to know
    that list is REALLY an ArrayList<String>, so it can't put in a compile
    time check to make you did not add a Date to your List. It goes by
    the type of List.

    --
    Roedy Green Canadian Mind Products
    http://mindprod.com

    Have you ever noticed that any computer search in the movies, is always linear, with, for example, candidate fingerprints flashing up on the screen one after another? The public is still under the delusion that electronic files are microscopic filing cabinets made out of tiny wires or magnetic patches inside the computer. Most lay people are surprised that it is easy for a computer to file things simultaneously by a dozen different schemes, and that they can have any report printed in any number of different sorted orders. With physical files, they are limited to one ordering/access.
    Roedy Green, Jun 9, 2010
    #14
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. tamas.hauer

    Cast, generics and clone problem

    tamas.hauer, Mar 12, 2005, in forum: Java
    Replies:
    15
    Views:
    906
    Thomas G. Marshall
    Mar 19, 2005
  2. Juergen Berchtel
    Replies:
    1
    Views:
    5,975
    John C. Bollinger
    May 20, 2005
  3. madmax
    Replies:
    1
    Views:
    820
    madmax
    Oct 5, 2008
  4. madmax
    Replies:
    0
    Views:
    589
    madmax
    Oct 4, 2008
  5. Soul
    Replies:
    0
    Views:
    508
Loading...

Share This Page