开发者

Why can't add Strings in List?

开发者 https://www.devze.com 2022-12-18 16:08 出处:网络
As we know know that we can add strings and integers in list if we declare generic type for list. but the code seems not adding up the strings. what is the problem i can\'t understand.开发者_如何学编程

As we know know that we can add strings and integers in list if we declare generic type for list. but the code seems not adding up the strings. what is the problem i can't understand.开发者_如何学编程.

class GHJ{String s;GHJ(String s){this.s=s;}}

class DFR{
    public static void main(String[] g){
        List<? extends Object> list=new ArrayList();
        list.add((new String("ffg")));// compiler error
        list.add("df");// compiler error
        list.add("sdd");// compiler error
        list.add(new GHJ("dff"));// compiler error
        String s= list.get(0);// compiler error
        System.out.println(list+" "+s);
    }   
}


The proper way is to use generics.

Create your list like:

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

Then you don't need to cast.

Edited:

As dpb noted there're multiple types of objects. From my point of view, mixing different type of objects in a list is asking for problems. The only way of solving it is:

  • Don't use generics, everything will be an Object in the list
  • When you need to retrieve something is needed to do something like:

    if (list.get(0) instanceof String) {
    } else if (list.get(0) instanceof GHJ) { 
    } ..... 
    


In your case, there's no need for you to make your list generic. Just use

List list = new ArrayList();

This will create a list of Object types.


Just to supplement Carlos's answer:

Suggested reading from Java language guide -> http://java.sun.com/j2se/1.5.0/docs/guide/language/generics.html

and for more comprehensive coverage:

http://java.sun.com/j2se/1.5/pdf/generics-tutorial.pdf


You have told the compiler that the type in your list is something that extends object. then you add things to the list and try and get one out. All the compiler can know that what you get out will extend object, not that it will definitely be a string. You need to tell the compiler that you are getting a string out of the list.

if you said

Object a= new String("blah");
String s;

you would need to cast a to a string to assign it to s

s= (String) a;

what happens in your example if you do

String s = list.get(3);

where you have put your new GHJ("dff")?

how is the compiler to know what type of object is in each position?


You can, but only by either using an untyped (get rid of

<? super String> 

entirely, so:

List x = new List(); x.add(new Object()); x.add("blah!");

or by finding a common superclass (in this case, only Object) for the generic argument

List<Object> x = new List<Object>(); x.add(new Object()); x.add("blah!");

You can pull tricks to stuff elements into lists, bypassing generic typechecks, but this is Very Bad Juju.


list is of type List<? super String> so if you want to add something to it, then it needs to be either a String or something that's a superclass of String. The only thing that's a superclass of String is Object. GHJ is not a superclass of String so you can't add an instance of GHJ to that list.


if you add different types to the list, you have to tell the compiler which type you are getting out of the list, you can't get around that.

could you not keep separate lists for each type of object and maybe keep a map which contains lists of individual types? Then you can get each list by type and all the elements in the list will be the same type?


Yes, you can add a list and an object in the list, but the only way to do that is be to have an untyped List. In that case you loose the type information and have to manually cast the objects your are getting out of the list back to their original type.

You could use instanceof to check into which type you can cast the objects, but that's particularly ugly...

Question is : do you really need to put both Strings and Objects in the same list ? that looks like a code smell to me.


You need to cast your String from Object, like this:

String s = (String)list.get(0);


Why would it add up the string? It doesn't compile because needs a cast :

String str = (String)list.get(0);


The wild card will mess you up here because it's not doing what you intend it to do. Wild cards are traditionally used when you need to refer to some set of generic generics.

For example, if you wanted to let the user give you a collection that contained any type of Object then your method could take a Collection<? extends Object> as its parameter. You would want to do this because if you just used Collection<Object> as the parameter then they couldn't pass a Collection<String>.

So, the problem is that List<? extends Object> has some limitations because the compiler cannot know what specific type that List takes. For example, it could be a List<String>... the compiler has no idea. For that reason, you could never call any method on List that takes a <? extends Object> as its parameter. In other words, you cannot call add().

You could call get()... because the compiler knows what type the receiving variable is and can check that it's ok. Object foo = myList.get(0) is fine.

I think in this case you really want List<Object> and to make sure to declare the type parameter on the ArrayList as well.

List<Object> list = new ArrayList<Object>();

And if you want strings then you will have to specifically convert the Objects to string. I suggest String.valueOf() personally.

Incidentally, the above is documented pretty well in the wildcards section of the Generics chapter in Core Java volume 1 (well, at least my ancient JDK 1.5 edition).

0

精彩评论

暂无评论...
验证码 换一张
取 消