5

I'm trying to learn about the use of generic types and I've noticed something weird when I was experimenting with some lines of code.

The first piece of code is inside a class named "A":

public void func(int k, List list) {
    list.add(9);
    list.add(true);
    list.add("a string");
    }

The second piece of code is in a different class, inside the main function:

List<Integer> arr = new ArrayList<Integer>();
        arr.add(14);
        System.out.println(arr.toString());
        a.func(8, arr);
        System.out.println(arr.toString());

Running the code results in this lines being printed:

[14]

[14, 9, true, a string]

This got me pretty confused since arr is an ArrayList of type Integer, how can it contain objects of type boolean and String? Is there a transformation of the list in the function func to a raw type (which mean it becomes of generic type Object)? And if so how is it possible since you cannot do this for example: List<Integer> arr = new ArrayList<Object>();?

Would love some clarification on this, maybe it will help me grasp this subject of generic types better. Thanks!

Community
  • 1
  • 1
Mickey
  • 1,085
  • 2
  • 8
  • 25
  • You should read about [raw types](https://docs.oracle.com/javase/tutorial/java/generics/rawTypes.html) and also [heap pollution](https://docs.oracle.com/javase/tutorial/java/generics/nonReifiableVarargsType.html#heap_pollution). – Flown Jul 19 '17 at 08:59

3 Answers3

1

Java does not allow the creation of generic Arrays. The Java Collection Classes are mainly implemented using Object arrays. The ArrayList class may look like the following

public class ArrayList<T> implements List<T>, Serializable {
    private transient Object[] data;
    // more content...
}

When creating a new Instance of the ArrayList a new Object[] array is created that can hold objects of any type. Typesafety is only achieved through using the generic Type Parameter.

Since List did not provide any Type parameter it makes use of the rawtype and anything can be added to the list. Therefore always make sure to infer template arguments to keep the typesafety.

public void func(int k, List<Integer> list) {
    list.add(9);      // works
    list.add(true);   // compile error
    list.add("a string");  // compile error
}

You should never use rawtypes. Depending on your compiler settings warnings will be omitted. It's better to use (bound/unbound) wildcards.

surrz
  • 285
  • 2
  • 8
1

Reason behind such kind of output is that you are passing List as an parameter to func( int k , List list ) . And list in func method is non- generic which allows you to add string as well so you are getting such output.

 List<Integer> arr = new ArrayList<Integer>();
                arr.add(14);
                System.out.println(arr.toString());
                a.func(8, arr); // here you are passing a list 
                System.out.println(arr.toString());

    public void func(List list) { // here List in non-generic 
        list.add(9);
        list.add(true);
        list.add("a string");
        }
JavaLearner
  • 162
  • 2
  • 7
1

The whole point of a Generic code in Java is to provide type-safety before the actual code compilation. The compiled code have no type, that's why we don't face any problem in our code becuase when actually func() method is called, the List arr doesn't have any type.

When we're calling System.out.println(arr.toString()), we're just printing an object. This will fine on any type (i.e., int, boolean, String etc...). That's why we don't encounter any exception.

However, just try to assign a value from this list and we'll get java.lang.ClassCastException

...
func(8, arr);
System.out.println(arr.toString());
int a = arr.get(2);
Raman Sahasi
  • 24,890
  • 6
  • 51
  • 66