Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does ArrayList<Integer> allow adding of String?

I came across the following code, a simple example of adding elements to List

    List list = new ArrayList<Integer>();
    ListIterator<Integer> litr = null;
    list.add("A");

    list.add("1");

    list.add(5);

    litr = list.listIterator();
    while(litr.hasNext()){
        System.out.println("UIterating " + litr.next());
    }

I expected it to throw an ClassCastException, but rather it wrote this to the console

A
1
5

which looks weird. When i tried:

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

I got a compile time error.

I would be grateful if someone could explain how the String objects are added to the ArrayList

like image 939
Santhosh Avatar asked May 18 '15 13:05

Santhosh


People also ask

Can we add String and Integer in ArrayList?

Yeah, you can create an ArrayList<Object> but having said that, my advice for you is this: don't. Don't create Lists with mixed types since this suggests that your program design is broken and needs to be improved so that this sort of monster isn't needed.

Can we add String in ArrayList?

Java ArrayList. Java ArrayList class uses a dynamic array for storing the elements. It is like an array, but there is no size limit. We can add or remove elements anytime.

Can we add any data type in ArrayList?

ArrayList cannot hold primitive data types such as int, double, char, and long. With the introduction to wrapped class in java that was created to hold primitive data values. Objects of these types hold one value of their corresponding primitive type(int, double, short, byte).


2 Answers

You assigned the new ArrayList to an untyped List. Generic type restrictions don't apply to an untyped List, it will let you put whatever you want in it. The compiler does not keep track that your untyped List refers to something that was declared with a generic type.

In any case this wouldn't produce a ClassCastException, generics only affect compilation. At runtime

The case where you put the type on the list variable:

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

is preferred, it should generate a compiler error telling you you're putting the wrong type in the collection.

There's a description of how legacy, non-generic code and generic code interoperate in this article:

In proper generic code, Collection would always be accompanied by a type parameter. When a generic type like Collection is used without a type parameter, it's called a raw type.

Most people's first instinct is that Collection really means Collection<Object>. However, as we saw earlier, it isn't safe to pass a Collection<Part> in a place where a Collection<Object> is required. It's more accurate to say that the type Collection denotes a collection of some unknown type, just like Collection<?>.

But wait, that can't be right either! Consider the call to getParts(), which returns a Collection. This is then assigned to k, which is a Collection<Part>. If the result of the call is a Collection<?>, the assignment would be an error.

In reality, the assignment is legal, but it generates an unchecked warning. The warning is needed, because the fact is that the compiler can't guarantee its correctness. We have no way of checking the legacy code in getAssembly() to ensure that indeed the collection being returned is a collection of Parts. The type used in the code is Collection, and one could legally insert all kinds of objects into such a collection.

So, shouldn't this be an error? Theoretically speaking, yes; but practically speaking, if generic code is going to call legacy code, this has to be allowed. It's up to you, the programmer, to satisfy yourself that in this case, the assignment is safe because the contract of getAssembly() says it returns a collection of Parts, even though the type signature doesn't show this.

like image 108
Nathan Hughes Avatar answered Sep 28 '22 23:09

Nathan Hughes


This is possible because of how generics are implemented in Java - using type erasure, and because Java supports raw types for backward compatibility with old versions of Java (1.4 and older).

Generics only exist in your source code. The compiler uses them to check the types at compile-time, but then throws away the generics. At runtime, a List<Integer> is just a List of objects, and it doesn't know that it's a list that should contain only Integer objects.

Java supports the use of raw types such as List instead of List<Integer> for backward compatibility with old versions. When you use a raw type, as you are doing in your code above, you get a compiler warning. You should not use raw types in new code - only ever use them when you need to deal with old code that you can't change.

The combination of raw types and type erasure allows you to put types of objects in lists that you shouldn't be putting in there.

Because the List at runtime doesn't know anything about the type that its elements are supposed to have, it doesn't check anything so you will not get a ClassCastException.

like image 39
Jesper Avatar answered Sep 29 '22 00:09

Jesper