The problem with generals and arrays

Sorry, I could not come up with a shorter title.

My question is why the following code snippet works:

public abstract class TObjectPool<T> { protected Object[] availableObjects; TObjectPool(int size){ availableObjects = new Object[size]; } protected class RenderElementPool extends TObjectPool<RenderElement>{ @Override public void fill() { for (int i = 0; i < capacity; i++) { availableObjects[i] = new RenderElement(); } } } 

when it will not work, creating an Object array like this:

 public abstract class TObjectPool<T> { protected T[] availableObjects; TObjectPool(int size){ availableObjects = (T[]) new Object[size]; } 

When available objects are available [i] = new RenderElement (); the line is executed in this last example, I get a ClassCastException. I understand why it works in the first example, but not why it is not in the second. Available objects must be a RenderElement array, and I'm trying to give it a RenderElement. What important bit of information do I miss?

Thanks for the help.

Updating ...

Thanks so much for the answers. I thought I understood, but again I managed to confuse myself:

If I add a function:

 public void add(int index, T object){ availableObjects[index] = object; } 

for the TObjectPool class. It will work with the array T [].

So, the new TObjectPool and subclassed pool looks like this:

 public abstract class TObjectPool<T> { T[] availableObjects; TObjectPool(int size){ availableObjects = (T[])new Object[size]; capacity = size; count = capacity; fill(); } public void add(int index, T object){ availableObjects[index] = object; } protected class RenderElementPool extends TObjectPool<RenderElement>{ @Override public void fill() { for (int i = 0; i < capacity; i++) { add(i, new RenderElement()); //this works //availableObjects[i] = new RenderElement(); //this gives an exception } } } 

I know how I can get around this now after reading your answers, but I'm curious. Can anyone shed some light on this feature?

Thanks again.

+6
source share
4 answers

The failure occurs because Object[] is the superclass of T[] for all T, but not a subtype for any T except Object .

If at run time there is a Class<T> , you can use Array.newInstance to create T[] .

+4
source

You can try using an array of type T.

Here's how you can do it: How to create a shared array in Java?

Use strong or weak typing. You are trying to use weak typing.

+1
source

Arrays in Java are not common, so you cannot apply Java generators to arrays. In particular, dropping from Object[] to T[] , as you do in the constructor, is incorrect, and this is most likely the cause of your error.

Knowing this, you can use the same trick that you use when you need to instantiate something that is not common to a universal class: pass a specific class object

 TObjectPool(int size, Class<T> klass) { availableObjects = Array.newInstance(klass, size); } ... protected class RenderElementPool extends TObjectPool<RenderElement>{ // Pass the class object to super constructor public RenderElementPool(int size) { super(size, RenderElement.class); } ... @Override public void fill() { for (int i = 0; i < capacity; i++) { availableObjects[i] = new RenderElement(); } } } 
+1
source

I would recommend you use Object[] here for simplicity. See My Arguments in Creating Arrays of Generic Types in Java

+1
source

Source: https://habr.com/ru/post/889890/


All Articles