Вам не хватает кода, который инициализирует T
, но я собираюсь предположить, что это выглядит примерно так.Я добавил несколько строк, которые не изменяют никакой функциональности, но которые помогут продемонстрировать ошибку:
public class Clazz<T> {
T[] t = (T[]) new Object[5];
public Clazz<T> methodA(int... ints) {
Clazz<Integer> ints2 = new Clazz<Integer>();
int l1 = t.length;
int l2 = ints2.t.length;
int remInd[] = new int[l1 - l2];
return this;
}
public static void main(String...args) {
Clazz<String> clazz = new Clazz<String>();
clazz.methodA(54, 7);
}
}
С помощью этого кода я мог воспроизвести ошибку.Проблема здесь заключается в следующем коде:
int l2 = ints2.t.length
Поскольку компилятор знает параметр типа для ints2
и, следовательно, ints2.t
, это можно рассматривать как грубый эквивалент этого:
Integer[] temp = ints2.t;
int l2 = temp.length;
В неявном приведении к Integer[]
(чье простое имя класса [Ljava.lang.Integer
) это терпит неудачу, поскольку t
является Object[]
, а не Integer[]
, и его нельзя привестик другому.
Работа с универсальными массивами
Существует много сложностей при работе с массивами, объявленными для универсального типа, которые задокументированы в другом месте.Короче говоря, я скажу, что если вам нужен «универсальный массив», вместо этого рассмотрите возможность объявления и использования его как Object[]
во всех отношениях, , за исключением , когда вы взаимодействуете с клиентом классавы либо принимаете, либо возвращаете только T
вместо Object
(для возврата через непроверенный актерский состав).Например,
Object[] t = new Object[5];
public T getSomethingFromArray() {
return (T)t[2];
}
public void setSomethingInArray(T something) {
t[2] = something;
}
Так работает ArrayList
, кстати.Взгляните на его код на DocJar .
Edit
За исключением общих массивов, я не думаю, что вы понимаете идею неявного приведения.Вот гораздо более короткий код, который завершается с той же ошибкой:
public class Clazz<T> {
T t = (T) new Object();
public static void main(String...args) {
Clazz<String> clazz = new Clazz<String>();
clazz.t.toString();
}
}
Exception in thread "main" java.lang.ClassCastException: java.lang.Object cannot be cast to java.lang.String
at Clazz.main(Clazz.java:6)
...
Несмотря на то, что нет необходимости приводить clazz.t
к строке, он делает это неявно , просто ссылаясь на clazz.t
.Вот вывод javap -c
для этого скомпилированного класса:
Compiled from "Clazz.java"
public class Clazz extends java.lang.Object{
java.lang.Object t;
public Clazz();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: aload_0
5: new #2; //class java/lang/Object
8: dup
9: invokespecial #1; //Method java/lang/Object."<init>":()V
12: putfield #3; //Field t:Ljava/lang/Object;
15: return
public static void main(java.lang.String[]);
Code:
0: new #4; //class Clazz
3: dup
4: invokespecial #5; //Method "<init>":()V
7: astore_1
8: aload_1
9: getfield #3; //Field t:Ljava/lang/Object;
//BELOW is the line that will fail
12: checkcast #6; //class java/lang/String
15: invokevirtual #7; //Method java/lang/String.toString:()Ljava/lang/String;
18: pop
19: return
}
В случае вашего исходного кода вот вывод javap -c
methodA()
:
public Clazz methodA(int[]);
Code:
0: new #5; //class Clazz
3: dup
4: invokespecial #6; //Method "<init>":()V
7: astore_2
8: aload_0
9: getfield #4; //Field t:[Ljava/lang/Object;
12: arraylength
13: aload_2
14: getfield #4; //Field t:[Ljava/lang/Object;
//BELOW is the line that will fail
17: checkcast #7; //class "[Ljava/lang/Integer;"
20: arraylength
21: isub
22: newarray int
24: astore_3
25: aload_0
26: areturn