Results 1 to 11 of 11
  1. #1
    gib65 is offline Member
    Join Date
    Jun 2010
    Posts
    86
    Rep Power
    0

    Default confused about Generics

    Hello,

    I'm somewhat of a newbie to Generics (A.K.A. templates I believe) and I'm playing around with something pretty sophisticated. I'm encountering some warnings when compiling (unchecked calls) and I'm not sure how to deal with them. I'm also trying to deliberately create an error without much success.

    Here's a SSCCE:

    Java Code:
    import java.util.Vector;
    
    // Possession class
    class Possession<T> {
    
        private Vector<T> itemVector;
    
        public Possession() {
    
    	itemVector = new Vector<T>(10, 5);
        }
    
        public void add(T item) {itemVector.add(item);}
    
        public Vector<T> getVector() {return itemVector;}
    }
    
    
    // Item class
    class Item {
    
        protected String name;
    
        public Item() {}
    
        public void print() {
    	System.out.println("I am a " + name);
        }
    }
    
    
    // Lock class
    class Lock extends Item {
    
        public Lock() {name = "Lock";}
    }
    
    
    // Key class
    class Key extends Item {
    
        public Key() {name = "Key";}
    }
    
    
    // Main class
    public class Main {
    
        private Possession[] possessions;
    
        public Main() {
    
    	possessions = new Possession[2];
    	possessions[0] = new Possession<Lock>();
    	possessions[1] = new Possession<Key>();
        }
    
        public void addPossession(int index, Item i) {
    
    	possessions[index].add(i);
        }
    
        public void print() {
    
    	((Item)possessions[0].getVector().get(0)).print();
    	((Item)possessions[1].getVector().get(0)).print();
        }
    
        public static void main(String args[]) {
    
    	Main m = new Main();		// constructor creates possessions[2] = {new Possession<Lock>(), ...<Key>()}	
    	m.addPossession(0, new Key());  // add a Key to possessions[0] when it should be a Lock
    	m.addPossession(1, new Lock()); // add a Lock to possessions[1] when it should be a Key
    	m.print();			// print possessions to show they were indeed added without error
        }
    }
    So I have a couple questions:

    1) When compiling with -Xlint:unchecked, it tells me that the line possessions[index].add(i) in the method Main.addPossession(int,Item) is unchecked. I've looked up how to resolve this problem and everything I've found says to specify the generic type. But I don't see a way to do so in this case. For example, I've found this on the net:

    Java Code:
    ArrayList <Double> L = new ArrayList<Double>();
    L.add(new Double(56.3));
    But since I'm dealing with an entry in an array, and since each entry is of a different generic type, and since the value for the argument 'index' will vary, there's no way I can specify the exact generic type (short of it being an instance of Item).

    Is there some other way around this?

    2) Shouldn't my code result in a run time error? I'm adding a Key to possessions[0] whose generic type is Lock and I'm adding Lock to possessions[1] whose generic type of Key. Yet no error occurs (either at compile time or run time), and this is verified by the call to print().

  2. #2
    Tolls is offline Moderator
    Join Date
    Apr 2009
    Posts
    12,224
    Rep Power
    20

    Default

    1) Your possessions array is not an array of any old class T, though, is it?
    It's and array of Items, so it should be declared as such.

    2) No, your possessions array is of any class, since you did not declare it as Possession<Item> (for example)...consequently each entry in the array can be of any class.

  3. #3
    JosAH's Avatar
    JosAH is offline Moderator
    Join Date
    Sep 2008
    Location
    Voorschoten, the Netherlands
    Posts
    13,765
    Blog Entries
    7
    Rep Power
    21

    Default

    Arrays are covariant and generics and arrays don't go well together; e.g. the following compiles fine:

    Java Code:
    Integer[] ia= new Integer[1];
    Number[] na= ia;
    		
    na[0]= new Double(1.23);
    		
    System.out.println(ia[0]);
    ... but it generates an ArrayStoreException when run; not so with collections, i.e. a List<Number> isn't a List<Integer> although an Integer is a Number. Also read this article.

    kind regards,

    Jos

  4. #4
    Tolls is offline Moderator
    Join Date
    Apr 2009
    Posts
    12,224
    Rep Power
    20

    Default

    So what are you saying?
    That Possession<Item>[] is not correct?
    That you can't declare an array of generic things?
    ETA:
    Java Code:
    public class Scratch {
        public static void main (String[] args) {
            ArrayList<Scratch> scrarray = new ArrayList<Scratch>();
            ArrayList<Scratch>[] arrayArray = new ArrayList[10];
            arrayArray[0] = scrarray;
        }
    }
    That compiles, but I can't say if it'll run once you try and actually do things with the arrayArray.
    You do get an unchecked assignment on the arrayArray initialisation, though...
    Last edited by Tolls; 10-19-2010 at 11:07 AM.

  5. #5
    JosAH's Avatar
    JosAH is offline Moderator
    Join Date
    Sep 2008
    Location
    Voorschoten, the Netherlands
    Posts
    13,765
    Blog Entries
    7
    Rep Power
    21

    Default

    Quote Originally Posted by Tolls View Post
    So what are you saying?
    That Possession<Item>[] is not correct?
    That you can't declare an array of generic things?
    Yup, that's what I'm saying the covariance of arrays (an incorrect decision in hindsight) doesn't agree with the strict type checking of generics; the latter is full of compromises ... (that IBM article is a good one and has some nice links too that explain this mess quite well).

    kind regards,

    Jos

  6. #6
    Tolls is offline Moderator
    Join Date
    Apr 2009
    Posts
    12,224
    Rep Power
    20

    Default

    Got it.
    Because Possession<Lock> cannot be assigned to something that is a Possession<Item> (because a Possesion<Lock> is not a Possession<Item>), attempting to assign a Possession<subclass of Item> to an array of Possesion<Item>s will result in it falling over in a heap?

  7. #7
    JosAH's Avatar
    JosAH is offline Moderator
    Join Date
    Sep 2008
    Location
    Voorschoten, the Netherlands
    Posts
    13,765
    Blog Entries
    7
    Rep Power
    21

    Default

    Quote Originally Posted by Tolls View Post
    Got it.
    Because Possession<Lock> cannot be assigned to something that is a Possession<Item> (because a Possesion<Lock> is not a Possession<Item>), attempting to assign a Possession<subclass of Item> to an array of Possesion<Item>s will result in it falling over in a heap?
    Yup, that's it; o.t.o.h. if you have, say, a Number[] you can assign an Integer (a subclass of Number) to each element of that array. The same counts for collections<Number>.

    kind regards,

    Jos

  8. #8
    gib65 is offline Member
    Join Date
    Jun 2010
    Posts
    86
    Rep Power
    0

    Default

    Thanks both for your feedback. And thanks to JosAH for the article. The first section (Generics are not covariant) explained a lot, but the rest was a little over my head (as I said, I'm a newbie to generics); I did catch the gist of it though (I think) and it seemed less relevant to what I'm trying to do.

    At this point, I'm wondering if I should use an ArrayList<Possession> instead of the Possession[] array. Will I still encounter the problem with covariance? According to the article, the ArrayList class looks like this:

    Java Code:
    class ArrayList<V> {
      private V[] backingArray;
    //...
    }
    which means it still consists of an actual array, which in turn means I'll still probably encounter the covariance issue.

    I'm also wondering if this (or some variant thereof) is permissable:

    ArrayList<Possession<Item>> possessionList = new ArrayList<Possession<Item>>();

    (I haven't tried it but I will).

    I'm also wondering if wildcards might help me, but at the moment I don't see how.

    Anyway, what I'm trying to do with all this is place restrictions on my code so that if I inadvertently attempt to put a Possessions object of some generic type V (say a Lock) at an index reserved for some other type Q (say a Key), it will give me an error. This is just so that I will be able to identify inadvertent errors in my code when they happen.

    I have a set of static final ints that I plan to use an indecies. For example:

    static final int KEY = 0;
    static final int LOCK = 1;
    //...

    and I just want to make sure I don't inadvertently do something like:

    Java Code:
    Key k = new Key();
    possessions[LOCK].add(k);
    I was hoping that some kind of exception would occur (like a ClassCastException). But if necessary, I'll have to create some kind of method like the following (though this is what I'm trying to avoid):

    Java Code:
    boolean validateIndex(int index, Item i) {
    
        try {
            switch (index) {
                case KEY: (Key) i; break;
                case LOCK: (Lock) i; break;
    //...
            }
        } catch (ClassCastException e) {
            return false;
        }
     
        return true;
    }
    It's no big deal if I have to do this, but it would be nice (and more clean/elegant) if I didn't.

    I'm sorry if the right course of action here seems obvious to other more experienced coders, but like I said, I'm just new to this and brainstorming here. Any feedback would be much appreciated.

    Thanks.

  9. #9
    Tolls is offline Moderator
    Join Date
    Apr 2009
    Posts
    12,224
    Rep Power
    20

    Default

    You don't want to force certain types into particular indices in that array.
    That's not good.

    Something is wrong in your model if you find yourself having to do that.

    What are you attempting to model here?

  10. #10
    gib65 is offline Member
    Join Date
    Jun 2010
    Posts
    86
    Rep Power
    0

    Default

    Quote Originally Posted by Tolls
    Something is wrong in your model if you find yourself having to do that.

    What are you attempting to model here?
    It's just a way for me to keep different subclasses of Item organized.

    This is part of a video game I'm programming. The possessions array is a member of the GoodGuy class (the main character in the game). As he goes through the level, he collects Items such as weapons, health items, coins, keys, locks, etc. They get stored in the possessions array. In order to stay organized, I want to store a particular Item (like a Key) consistently at a particular index, and I'll be referencing that index with a static final int (for example, KEYS). To be precise, what I'll be storing there is not an Item object per se, but a Possession object. The Possession object contains a Vector that stores the Item object. That way, I don't have to deal with 2D array (that, for me, gets messy) - it's just a 1D array of Possessions - and yet there can be more than one Item of the same kind at a particular index (vis-a-vis the Possession's Vector).

    Again, your feedback is most value. Thank you.
    Last edited by gib65; 10-20-2010 at 05:20 PM.

  11. #11
    Tolls is offline Moderator
    Join Date
    Apr 2009
    Posts
    12,224
    Rep Power
    20

    Default

    I don't see why you should want to store each item at a particular index. I'm not sure what you gain by doing that?

    In any case, assuming that's somehow useful, it sounds more like a map to me, with the key being the type of possession. I'd be tempted to turn the types into an enum and use the enum as a key. So you'd have a PossessionType enum, consisting of KEY, LOCK etc etc. Each Possession subclass would be of one of these types, so would have a reference to one of these enums.

    The Map would then be a Map<PossessionType, List<Possession>>, allowing you to store and retrieve your types. You can pre-populate the map with empty lists for each type at the start (otherwise you have to check if there's an entry or not).

Similar Threads

  1. Help with generics
    By shai in forum New To Java
    Replies: 0
    Last Post: 08-12-2010, 08:07 AM
  2. Generics
    By sakshamkum in forum Advanced Java
    Replies: 3
    Last Post: 06-03-2010, 11:12 PM
  3. Generics
    By bschmitt78 in forum Advanced Java
    Replies: 3
    Last Post: 03-16-2010, 03:21 AM
  4. Generics
    By sireesha in forum New To Java
    Replies: 2
    Last Post: 01-11-2008, 12:08 AM
  5. Java confused over Generics?
    By Bibendum in forum New To Java
    Replies: 3
    Last Post: 12-26-2007, 07:23 AM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •