newInstance, generics, and "unchecked or unsafe operations"

Discussion in 'Java' started by Eric I., Aug 15, 2008.

  1. Eric I.

    Eric I. Guest

    Hi Everyone,

    I'm trying to create a method in a class that takes some type of
    genericized collection and creates a new, empty instance of it by
    calling the newInstance method. I can get the code to work, but I do
    get compiler warnings of "unchecked or unsafe operations".

    Please note, I would like this code to be flexible, so whether the
    method gets an ArrayList<Integer> or a LinkedList<String> it will work
    and not generate compiler warnings.

    In trying to hunt down a solution by reading comp.lang.java.programmer
    and other online sources, I became aware of the issue of "type
    erasure". In fact, at compile time I should know the full type of the
    collection. Is there a way to "nicely" re-write this code, so it
    doesn't generate the warning? If not "nicely" how about "nastily"?

    ====

    import java.util.Collection;
    import java.util.ArrayList;

    class EmptyDuplicator<T>
    {
    public Collection<T> duplicateEmptyVersionOf(Collection<T>
    original)
    throws InstantiationException, IllegalAccessException
    {
    // COMPILER WARNING on next line; BUT I KNOW T at compile-
    time!!!
    Collection<T> emptyVersionOf =
    original.getClass().newInstance();
    return emptyVersionOf;
    }
    }


    public class Sample
    {
    public static void main(String[] args)
    throws InstantiationException, IllegalAccessException
    {
    ArrayList<Integer> original = new ArrayList<Integer>();
    original.add(1);
    original.add(2);

    EmptyDuplicator<Integer> duplicator = new
    EmptyDuplicator<Integer>();
    Collection<Integer> clone =
    duplicator.duplicateEmptyVersionOf(original);
    clone.add(4);

    System.out.println("original");
    for(int i : original) {
    System.out.println(i);
    }

    System.out.println("clone");
    for(int i : clone) {
    System.out.println(i);
    }
    }
    }

    ====

    Thanks in advance,

    Eric
     
    Eric I., Aug 15, 2008
    #1
    1. Advertising

  2. Eric I. wrote:
    > Hi Everyone,
    >
    > I'm trying to create a method in a class that takes some type of
    > genericized collection and creates a new, empty instance of it by
    > calling the newInstance method. I can get the code to work, but I
    > do
    > get compiler warnings of "unchecked or unsafe operations".


    Because of type erasure, the type of original.getClass().newInstance()
    is Collection rather than Collection<T>. I wouldn't worry too much
    about that warning. It really means "I can't verify that what you've
    done is safe, so you're on your own."

    The simplest way to prevent the warning from appearing is to annotate
    the method, thus:

    @SuppressWarnings("unchecked")
    public Collection<T> duplicateEmptyVersionOf(Collection<T>
    original)
    throws InstantiationException, IllegalAccessException
    {
    ...
     
    Mike Schilling, Aug 15, 2008
    #2
    1. Advertising

  3. Eric, as has been documented and bemoaned extensively in the past,
    generics is one of the few Java language features with which you can
    hang yourself before you feel the noose around your neck. I would
    humbly submit that, with generics, you need to learn things in a more
    formal way than reading our posts. An excellent book is "Java Generics
    and Collections" (O'Reilly). If you dive in to use generics before
    understanding their basics (and erasure is part of that), you'll hang
    yourself. I've done it, and I've seen others do it on a project-wide
    scale.. which really, really hurts.

    In my experience generics require you to be near 100% accurate in your
    typing for the feature to help you. As soon as you introduce any
    sloppiness in the typing, generics becomes a chronic obstacle course.

    My bottom-line advice with generics is to take it very, very slowly..
    and read up some authoritative text(s) on the subject.
     
    softwarepearls_com, Aug 15, 2008
    #3
  4. Eric I.

    Roedy Green Guest

    On Thu, 14 Aug 2008 21:05:00 -0700 (PDT), "Eric I."
    <> wrote, quoted or indirectly quoted someone
    who said :

    > If not "nicely" how about "nastily"?


    the secret is code like this:

    // Make sure the class we load implements Macro.
    final Class<? extends Macro> macroClass = Class.forName(
    binaryClassName ).asSubclass( Macro.class );


    --

    Roedy Green Canadian Mind Products
    The Java Glossary
    http://mindprod.com
     
    Roedy Green, Aug 15, 2008
    #4
  5. Fri, 15 Aug 2008 00:08:17 -0700, /Eric I./:

    > I'm trying to create a method in a class that takes some type of
    > genericized collection and creates a new, empty instance of it by
    > calling the newInstance method. I can get the code to work, but I do
    > get compiler warnings of "unchecked or unsafe operations".

    [...]
    > class EmptyDuplicator<T>
    > {
    > public Collection<T> duplicateEmptyVersionOf(Collection<T>
    > original)
    > throws InstantiationException, IllegalAccessException
    > {
    > // COMPILER WARNING on next line; BUT I KNOW T at compile-
    > time!!!
    > Collection<T> emptyVersionOf =
    > original.getClass().newInstance();
    > return emptyVersionOf;
    > }
    > }


    Recently one has mentioned the Class.asSubclass [1] method but I
    can't figure out which is the correct syntax, or if it is possible
    at all:

    Class<? extends Collection<T>> c;
    // Syntax error in the |Collection<T>.class| part.
    c = original.getClass().asSubclass(Collection<T>.class);
    Collection<T> emptyVersionOf = c.newInstance();

    [1]
    http://java.sun.com/javase/6/docs/api/java/lang/Class.html#asSubclass(java.lang.Class)

    --
    Stanimir
     
    Stanimir Stamenkov, Aug 15, 2008
    #5
  6. Stanimir Stamenkov wrote:
    > Class<? extends Collection<T>> c;
    > // Syntax error in the |Collection<T>.class| part.
    > c = original.getClass().asSubclass(Collection<T>.class);
    > Collection<T> emptyVersionOf = c.newInstance();


    Close, but you'll need to use Collection.class and not
    Collection<T>.class, which requires you to change it all to this:
    Class<? extends Collection> c;
    c = orginal.getClass().asSubclass(Collection.class);
    Collection<T> emptyVersionOf = c.newInstance();

    There's a bug, I'm not sure in the JLS or not, that Class<? extends
    Collection> is not the same as Class<? extends Collection<?>> and that
    Collection.class returns Class<Collection> instead of Class<Collection<?>>.

    Because of the class issue, this means that you are forced to use rare
    types (mixtures of generics and raw types), which is a problematic mess
    that I think is underspecified in the JLS.

    --
    Beware of bugs in the above code; I have only proved it correct, not
    tried it. -- Donald E. Knuth
     
    Joshua Cranmer, Aug 15, 2008
    #6
  7. Eric I.

    Eric I. Guest

    Thank you all (Mike, Roedy, Stanimir, Joshua, and softwarepearls) for
    your help.

    Eric
     
    Eric I., Aug 15, 2008
    #7
    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. Miguel De Anda

    ClassLoader or Class.newInstance

    Miguel De Anda, Jul 14, 2003, in forum: Java
    Replies:
    1
    Views:
    837
    John C. Bollinger
    Jul 15, 2003
  2. Glenn Robinson

    newInstance and rmi

    Glenn Robinson, Aug 24, 2004, in forum: Java
    Replies:
    0
    Views:
    371
    Glenn Robinson
    Aug 24, 2004
  3. Axl
    Replies:
    2
    Views:
    15,629
    John C. Bollinger
    Sep 2, 2004
  4. hiwa
    Replies:
    0
    Views:
    2,446
  5. Replies:
    3
    Views:
    1,396
Loading...

Share This Page