1

For class we have to implement data structures in java without using those already implemented by default, so no I cannot use Lists. Previously there were situations where it was necessary to create an array of a generic type T and the following works without problem:

class Test<T> {
  private T[] array;

  @SuppressWarnings("unchecked")
  public Test(int sz) {
    array = (T[]) new Object[sz];
  }

  public static void main(String[] args) {
    Test test = new Test(1);
  }
}

Now instead of an array of type T, it was necessary to create an array of type Thing<T> where Thing is a class... The same approach gives runtime error (java.lang.ClassCastException):

class Thing<T> { }

class Test<T> {
  private Thing<T>[] array;

  @SuppressWarnings("unchecked")
  public Test(int sz) {
    array = (Thing<T>[]) new Object[sz];
  }

  public static void main(String[] args) {
    Test<Object> test = new Test<>(1);
  }
}

What can be done about the second case?

slideshowp2
  • 38,463
  • 29
  • 127
  • 255
  • 2
    Instead of doing `array = (Thing[]) new Object[sz];`, why can't you just do `array = new Thing[sz];` ? – Ashishkumar Singh Dec 29 '19 at 14:33
  • @AshishkumarSingh I can... but why? –  Dec 29 '19 at 14:44
  • Does this answer your question? [How to create a generic array in Java?](https://stackoverflow.com/questions/529085/how-to-create-a-generic-array-in-java) – Priyam Dec 29 '19 at 15:15
  • @Priyam I believe not. That question seems to ask to create an array of a type `T` , not an array of type `SomeClass`. –  Dec 29 '19 at 15:19
  • @CarlaCvekla Your attempted casting is the equivalent of "This array of objects is actually an array of things", to which the JVM then says "no it's not" and throws a `ClassCastException`. So you would use `new Thing[sz]` because it's correct. – Kayaman Dec 29 '19 at 15:22
  • @Kayaman why does the JVM not complain about the first case "This array of objects is actually an array of T's", but does about an array of Thing's? –  Dec 29 '19 at 15:29
  • @CarlaCvekla What about the answer which I have mentioned below with Array.newInstance? If that also doesn't solve your problem, could you explain why? – Priyam Dec 29 '19 at 15:35
  • @CarlaCvekla because thanks to type erasure `T` is actually `Object`, so the JVM sees it during runtime as `(Object[]) new Object[sz];` and it can never fail. The reason for this kind of behaviour is historic, and it's probably not something you need to worry about for your homework. In regular work you don't come across this too often, since you're usually working with collections instead of arrays anyway. – Kayaman Dec 29 '19 at 15:36
  • @Priyam the solution given in the comment of Ashishkumar seems to be working, I haven't accepted an answer because I don't know which answer is the best. –  Dec 29 '19 at 15:38
  • @Priyam I'm the one who upvoted. If you can justify your use of a dynamic array constructor in your answer, I'll give you an upvote too. – Kayaman Dec 29 '19 at 15:39
  • @Kayaman I was not sure originally if OP has accepted the answer to go with new operator as mentioned in the followup comment, hence I gave an alternative solution. It seems now the OP has finally used Ashish's answer. Anyhow I'll keep my answer there as an alternative. I too have upvoted Ashish's answer as it is a better solution than mine. – Priyam Dec 29 '19 at 15:53

3 Answers3

2

You are trying to cast a list of Object to Thing which an Object is not, so it will not work.

The problem you are facing is that in Java you can't instantiate an array of generic types.

So instead create an array of raw type Thing[] and cast it to generic type Thing<T>[], which is OK in this case given that there is type erasure happening anyways.

class Thing<T> {
}

class Test<T> {
    private Thing<T>[] array;

    @SuppressWarnings("unchecked")
    public Test(int sz) {
        array = (Thing<T>[]) new Thing[sz];
    }

    public static void main(String[] args) {
        Test<Object> test = new Test<>(1);
    }
}
Adwait Kumar
  • 1,388
  • 8
  • 19
  • Is there any reason to cast the `new Thing[sz]` to `Thing[]` though? It seems to work even without the cast. –  Dec 29 '19 at 20:30
  • @CarlaCvekla, no it's essentially the same. In one case it is an unchecked cast and in other it is an unchecked assignment. – Adwait Kumar Dec 29 '19 at 21:08
0

Try this:

public class Thing<T> {
}

class Test<T> {
    private Thing<T>[] array;

    @SuppressWarnings("unchecked")
    public Test(int sz) {
        array = (Thing[]) Array.newInstance(Thing.class, sz);
    }

    public static void main(String[] args) {
        Test<Object> test = new Test<>(1);
    }
}

You can further refer here

Priyam
  • 131
  • 9
0

When you cast Object[] to T[], it is a lie because it is incorrect if T is anything other than Object. However, it does not cause a class cast exception inside the class because the inside of the class is within the scope of the type variable T, so the type of the variable array, T[], is erased to Object[] at runtime, so casting Object[] to it does not fail (though if you somehow expose the array to the outside of the class as type T[], the outside caller may get a class cast exception).

If T had an upper bound like <T extends MyClass>, then the erasure of T[] would be MyClass[], so casting Object[] to it would immediately throw a class cast exception, and you would have to do new MyClass[sz] for it to not immediately throw a class cast exception.

Here, the variable is of type Thing<T>[], the erasure of which is Thing[]. So you would have to create an array with new Thing[sz] for it not to throw a class cast exception.

newacct
  • 110,405
  • 27
  • 152
  • 217