1

I have a GenericList class that must initialise an array with type but it force me to declare it as Object in compile time. When I declare the generic as String in Main, the program stops with ClassCastException when i assign the list.items to a variable called items, which compile time also recognise it as String[]. Error is like this:

Exception in thread "main" java.lang.ClassCastException: class [Ljava.lang.Object; cannot be cast to class [Ljava.lang.String; ([Ljava.lang.Object; and [Ljava.lang.String; are in module java.base of loader 'bootstrap')
    at com.advanced.Main.main(Main.java:51)". 

Why and how to solve this? Thank you.

public class GenericList<T> {   
    public T[] items = (T[]) new Object[10];
    private int count;
    public void add(T item){
        items[count++] = item;
    }
    public T get(int index){
        return items[index];
    }
    public T[] getItems() {
        return items;
    }
}

public class Main {

    public static void main(String[] args) {

        var list = new GenericList<String>();
        list.add("a");
        list.add("b");
        var items = list.items;
        for(var item: items){
            System.out.println(item);
        }
    }
}
Abra
  • 19,142
  • 7
  • 29
  • 41
Edith
  • 95
  • 5
  • 2
    Your problem is that `Object[]` and `String[]` are different types and not part of the same hierarchy (both extend `Object` but that's it). Have a look here for some more info: https://stackoverflow.com/questions/529085/how-to-create-a-generic-array-in-java - You could also have a look at the `ArrayList` sources which internally mains the array as `Object[]` and casts upon retrieval. – Thomas Oct 14 '21 at 06:09
  • 1
    https://www.baeldung.com/java-generic-array – pleft Oct 14 '21 at 06:13
  • 1
    Class `java.util.ArrayList` is also a generic list that is backed by an array (of `Object`). You can look at the source code of that class to see how they did it. – Abra Oct 14 '21 at 06:14
  • And just for the future: when you have an exception stack trace with a line number, then please **mark** that line somehow (for example with a comment) in the source code we are showing. Dont expect us to copy your code, and compile it locally to figure such details ourselves. – GhostCat Oct 14 '21 at 06:19
  • Oh,I see. Generic is only for type checking at compile time. No wonder when I add a break point to see the type of item, it is still Object[]. Thank you for the hints :) – Edith Oct 14 '21 at 06:25

1 Answers1

3

You must to inject explicitly the array constructor for T type.

E.g. move your new T[10] as

static class GenericList<T> {
    final public T[] items;
    private int count;

    public GenericList(IntFunction<T[]> arrayConstructor) {
        items = arrayConstructor.apply(10);
    }

And create the object injecting the constructor

var list = new GenericList<>(String []::new);

Now all works

a
b
null
null
null
null
null
null
null
null

(Note: with T[] items = (T[]) new Object[10] you are not creating a T array, you are creating an Object array casting to a T array, which is incorrect)

josejuan
  • 9,338
  • 24
  • 31