Reputation: 8609
I've written a small utility method but it always produces a ClassCastException
, any ideas why? and how to fix it?
<T> T[] subArray(int begin, int end, T[] array) {
int size = end - begin;
Object[] newArray = new Object[size];
for (int i = 0; i < size; i++) {
newArray[i] = array[begin + i];
}
return (T[]) newArray;
}
Here's the stack trace:
java.lang.ClassCastException: [Ljava.lang.Object;
at org.robert.distance.framework.FacadeTest.testSubArray(FacadeTest.java:48)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:592)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:76)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:46)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Upvotes: 1
Views: 1780
Reputation: 11017
I suspect the problem is you are returning an Object[]
. Instead of using new Object[size]
, you need to create a new array of the correct type. One way to do that is to use Array.newInstance(Class<?> componentType, int length).
Something like:
<T> T[] subArray(int begin, int end, T[] array) {
int size = end - begin;
T[] newArray = (T[])Array.newInstance(array.getClass().getComponentType(), size);
for (int i = 0; i < size; i++) {
newArray[i] = array[begin + i];
}
return newArray;
}
Upvotes: 5
Reputation: 1108642
<T> T[] subArray(int begin, int end, T[] array) {
return Arrays.copyOfRange(array, begin, end);
}
Heck, it even makes the whole subArray()
method superfluous :) It only requires JDK 1.6. If you're not on it yet for some reason, here's an extract of relevance:
public static <T> T[] copyOfRange(T[] original, int from, int to) {
int newLength = to - from;
if (newLength < 0) throw new IllegalArgumentException(from + " > " + to);
T[] copy = (T[]) Array.newInstance(original.getClass().getComponentType(), newLength);
System.arraycopy(original, from, copy, 0, Math.min(original.length - from, newLength));
return copy;
}
Upvotes: 7
Reputation: 597046
T[]
isn't Object[]
- try String[] ar = new Object[1];
You'd better use System.arraycopy(..)
. And the utility method Arrays.copyOf
uses Array.newInstance(newType.getComponentType(), newLength);
to create a new array, so combine these two methods to achieve your goal
Update: As noted in the comments, and in BalusC's answer, there is already Arrays.copyOfRange(..)
Upvotes: 4
Reputation: 103777
Yes, it's quite straightforward. You're creating an Object[]
array, and then casting it to T[]
. If T
is not Object
, this cast will fail.
Generics and arrays don't really mix very well. As ILMTitan says, you can use Array.newInstance, though then you'll have to have the caller pass an instance of Class<T>
into your method. Although a better approach would be to use System.arrayCopy as this seems to be exactly what you're doing here.
Upvotes: 1