问题
I've implemented an ArrayLinearList class on the following way
public class ArrayLinearList<T> implements LinearList<T>, Iterable<T>
which contains the class member
protected T[] element
In order to extend the functionality of the class I create a new class that inherits from the first one
class SuperList<T extends Comparable<T>> extends ArrayLinearList<T>
Here I ensure that the type T implements the Comparable interface (this cannot be changed).
In the SuperList class I have the following method
public void replace( int pedro, T maria ){
element[ pedro ] = maria;
}
The line of the method generate the following error
Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.Comparable;
But if I declare the class on the following way I don't have this problem anymore (but in this way I'm no longer able to compare class objects)
class SuperList<T> extends ArrayLinearList<T>{
I would appreciate any help to solve this issue. I'm not allowed to modify the class \ [ ArrayLinearList, just the class SuperList.
Thanks in advance.
回答1:
Based on the exception, it looks like you're initializing element
with new Object[someLength]
and doing an unchecked cast to T[]
. This is likely happening in ArrayLinearList
. The problem is that in this code:
element[ pedro ] = maria;
element
is treated as a Comparable[]
at runtime, and an Object[]
isn't a Comparable[]
.
There are many existing posts related to generic array creation, but your issue is interesting because you've thrown inheritance into the mix (with a narrowing of a type parameter's bounds). The best solution seems to be only interacting with element
within the ArrayLinearList
class. Make it private
and expose getters and setters. This should avoid runtime failures like this (which take some thought to avoid when doing unchecked casts like (T[])new Object[someLength]
).
For example:
public class ArrayLinearList<T> implements LinearList<T>, Iterable<T> {
private final T[] elements;
public ArrayLinearList(final int length) {
@SuppressWarnings("unchecked") // won't be exposed outside this class
final T[] withNarrowedType = (T[])new Object[length];
elements = withNarrowedType;
}
public final void set(final int index, final T element) {
elements[index] = element;
}
}
EDIT: I just noticed your disclaimer "I'm not allowed to modify the class ArrayLinearList
just the class SuperList
." Well that's unfortunate, because the author of ArrayLinearList
has written type-unsafe code. But the question becomes why a method like SuperList.replace
needs to interact with the array directly (or exist at all). It looks like it's simply assigning a new element to the specified index - is there no ArrayLinearList
method you can use to do that?
If all else fails, here's a last-ditch workaround:
((Object[])element)[pedro] = maria;
But that's an awful solution that duct-tapes over the underlying problem.
来源:https://stackoverflow.com/questions/18454854/casting-between-an-object-of-generic-type-t-and-an-object-of-generic-type-t