0

I am writing junit test for toArray method which is one of the method of ArrayBasedStack. This class has an array inside and toArray method copies the element and return. The method is given by the class, and I amd trying to print out each element in the array.

This method copy the local array and return the copy array with the type of the Object.

public T[] toArray() {
    T[] copy = (T[]) new Object[this.size()];
    for (int i = 0; i < this.size(); i++) {
        copy[i] = (T) this.myArray[i];
    }

    return copy;
}

For the test, I set up String array as like below:

private ArrayBasedStack stack;

public void setUp(){
    stack = new ArrayBasedStack<String>();
}

To test toArray() method, I tried:

   public void testToArray(){
        stack.push("000");
        stack.push("111");
        assertEquals(2, stack.toArray().length);
        assertEquals("111", stack.toArray()[0]);
    }

Other than toArray() method, other methods' test passed well such as: peek(), push(), clear(), equals()... etc.

However, only this test returns error for both assertEquals:

    assertEquals(2, stack.toArray().length);
    assertEquals("111", stack.toArray()[0]);

The error is:

>java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.String;
        at arraystack.ArrayBasedStackTest.testToArray(ArrayBasedStackTest.java:82)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
        at java.lang.reflect.Method.invoke(Unknown Source)
        at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
        at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
        at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
        at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
        at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
        at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
        at org.junit.internal.runners.statements.FailOnTimeout$CallableStatement.call(FailOnTimeout.java:298)
        at org.junit.internal.runners.statements.FailOnTimeout$CallableStatement.call(FailOnTimeout.java:292)
        at java.util.concurrent.FutureTask.run(Unknown Source)
        at java.lang.Thread.run(Unknown Source)
bmargulies
  • 91,317
  • 38
  • 166
  • 290
Jieun Chon
  • 141
  • 9
  • 4
    Well yes, you're creating an `Object[]`, and then when you call it, that's effectively casting to `String[]`, and that cast isn't valid. Basically, you can't create the right kind of array without actually knowing the element type at execution time. – Jon Skeet Sep 21 '16 at 21:08
  • Have you considered using `Arrays.copyOf()` to copy the internal array? You should be able to get a *bona fide* `T[]` (i.e. `String[]`) that way. And no casting needed. – John Bollinger Sep 21 '16 at 21:14
  • 1
    This may be helpful: http://stackoverflow.com/questions/529085/how-to-create-a-generic-array-in-java – uoyilmaz Sep 21 '16 at 21:20

1 Answers1

2
    T[] copy = (T[]) new Object[this.size()];

Here you are lying to the compiler. It isn't a T[], unless T[] is Object[].

The correct way to write this method is the same way Collections do it, by supplying a prototype that if you're lucky is already the right size:

import java.lang.ref.Array;

public T[] toArray(T[] a)
{
    if (a.length != this.size())
    {
        a = Array.newInstance(a.getClass().getComponentType(), this.size());
    }
    for (int i = 0; i < this.size(); i++)
    {
        a[i] = (T) this.myArray[i];
    }
    return a;
}

or alternatively:

import java.util.Arrays;

public T[] toArray(T[] a)
{
    return Arrays.copyOf(this.myArray, this size());
}
user207421
  • 289,834
  • 37
  • 266
  • 440