2010-06-21 12 views
1

J'ai écrit une petite méthode d'utilitaire mais elle produit toujours un ClassCastException, des idées pourquoi? et comment le réparer?sous-liste pour les tableaux - ClassCastException lors de la conversion au type générique

<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; 
} 

est ici la trace de la pile:

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) 
+0

Pouvez-vous publier la trace de la pile? Cela aiderait. –

Répondre

7

Utilisez Arrays#copyOfRange()

<T> T[] subArray(int begin, int end, T[] array) { 
    return Arrays.copyOfRange(array, begin, end); 
} 

Heck, il est même méthode superflue :) l'ensemble subArray() Il ne nécessite JDK 1.6. Si vous n'y êtes pas encore pour quelque raison, voici un extrait de pertinence:

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; 
} 
+2

comment j'ai tendance à oublier ces méthodes utiles :) (+1) – Bozho

4

T[] n'est pas Object[] - essayez String[] ar = new Object[1];

Vous feriez mieux d'utiliser System.arraycopy(..). Et la méthode utilitaire Arrays.copyOf utilise Array.newInstance(newType.getComponentType(), newLength); pour créer un nouveau tableau, donc combiner ces deux méthodes pour atteindre votre objectif

Mise à jour: Comme il est indiqué dans les commentaires et dans la réponse de BalusC, il y a déjà Arrays.copyOfRange(..)

+1

Une autre option est l'utilisation de 'Arrays.copyOfRange (...)', pouvant être légèrement pire que 'System.arraycopy (...)' – MarcoS

+0

@MarcoS: 'Arrays.copyOfRange (...)' est uniquement disponible en Java 1.6+ – newacct

+0

@newacct: vous avez raison, mais la question n'a indiqué aucune restriction sur la version Java – MarcoS

5

Je soupçonne que la problème est que vous renvoyez un Object[]. Au lieu d'utiliser new Object[size], vous devez créer un nouveau tableau du type correct. Une façon de le faire est d'utiliser Array.newInstance(Class<?> componentType, int length).

Quelque chose comme:

<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; 
} 
+0

Comment le tableau sait-il quel est son type de composant? – OscarRyz

+0

@Sup: l'exacte 'Class' est toujours connue pendant l'exécution. – BalusC

1

Oui, il est assez simple. Vous créez un tableau Object[], puis vous le transposez en T[]. Si T n'est pas Object, cette conversion échouera.

Les génériques et les tableaux ne se mélangent pas vraiment très bien. Comme le dit ILMTitan, vous pouvez utiliser Array.newInstance, mais vous devrez alors faire passer une instance de Class<T> dans votre méthode. Bien qu'une meilleure approche serait d'utiliser System.arrayCopy car cela semble être exactement ce que vous faites ici.

Questions connexes