如何修复:java.lang.ClassCastException:java.util.ArrayList 无法转换为 double[]
How to fix: java.lang.ClassCastException: java.util.ArrayList cannot be cast to double[]
我在尝试 运行 以下代码时遇到问题:
当我尝试从 ArrayList<double[]> list
获取项目时它抛出 ClassCastException
方法list.get(i)
也会抛出excexption
public void drawRoutes(ArrayList<String> routes) {
if (routes.isEmpty()) return;
for (int i = 0; i < routes.size(); i++) {
PolylineOptions polylineOptions = new PolylineOptions();
ArrayList<double[]> list = TransportRoutes.getRoutes(tag, routes).get(i);
for (double[] points : list) { // throws ClassCastException
map.addPolyline(polylineOptions
.add(new LatLng(points[0], points[1]))
.color(color)
.width(POLY_LINE_WIDTH));
}
}
}
方法 getRoutes() :
public static ArrayList<ArrayList<double[]>> getRoutes(String tag, ArrayList<String> numbers) {
ArrayList<ArrayList<double[]>> routes = new ArrayList<>();
for (String number : numbers) {
routes.add(sRoutesHashMap.get(tag).get(number));
}
return routes;
}
// sRoutesHashMap is a HashMap<String, HashMap<String, ArrayList<double[]>>>
// and taken from this method
protected static <T> T getSmth(Context context, String url) {
T data = null;
JSONParser jsonParser = new JSONParser(context);
String json;
ObjectMapper mapper = new ObjectMapper();
try {
json = jsonParser.execute(url).get();
if (json != null) {
data = mapper.readValue(json, new TypeReference<T>() {});
} else return null;
} catch (InterruptedException | ExecutionException | IOException e) {
e.printStackTrace();
}
return data;
}
完整的堆栈跟踪是:
java.lang.ClassCastException: java.util.ArrayList cannot be cast to double[]
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2211)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2261)
at android.app.ActivityThread.access0(ActivityThread.java:141)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1256)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:5103)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:525)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.ClassCastException: java.util.ArrayList cannot be cast to double[]
at in.transee.transee.Drawer.drawRoutes(Drawer.java:46)
at in.transee.transee.MapsActivity.onCreate(MapsActivity.java:45)
at android.app.Activity.performCreate(Activity.java:5133)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2175)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2261)
at android.app.ActivityThread.access0(ActivityThread.java:141)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1256)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:5103)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:525)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
at dalvik.system.NativeStart.main(Native Method)
当我使用这个方法时,一切都奏效了:
public static void getAllRoutes(Context context) {
String routesJson = sSPData.getString(sCity + ROUTES, EMPTY);
ObjectMapper mapper = new ObjectMapper();
JSONParser jsonParser = new JSONParser();
try {
routesJson = jsonParser.execute(URL + sCity + SEPARATOR + ROUTES).get().get(0);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
try {
sRoutesHashMap = mapper.readValue(routesJson,
new TypeReference<HashMap<String, HashMap<String, ArrayList<double[]>>>>() {});
} catch (IOException e) {
e.printStackTrace();
}
}
您似乎受到了堆污染 †。好消息是我认为你可以通过这样做很容易地绕过它。
protected static <T> T getSmth(TypeReference<T> typeRef, Context context, String url) {
...
data = mapper.readValue(json, typeRef);
并调用它:
sRoutesHashMap = getSmth(new TypeReference<HashMapOfBlahBlahBlah>(){}, context, url);
为什么堆污染?
mapper.readValue
returns Object
,或者 returns T
但标有 @SuppressWarnings("unchecked")
(我不能找出哪个,可能是后者)
- 您将 return 存储为您的通用类型(宾果游戏,这是您的堆污染)
- 但是在通用方法中,从
mapper.readValue
编辑的 Object
return 实际上不是您的通用类型
- 这只会在您的
ClassCastException
之后出现
注意:您在通用代码或库通用代码中看到 @SuppressWarnings("unchecked")
的任何地方,您应该小心,因为这种结果很可能
怎么堆污染?
原因可能是因为您的泛型 getSmth
方法中的匿名 new TypeReference<T>(){}
无法评估类型 T
作为您的具体类型参数。如果您查看 TypeReference
的源代码,由于它使用 getGenericSuperclass
和 getActualTypeArguments
.
的方式,这似乎很有意义
一个解决方案是在 getSmth
之外创建 TypeReference
的参数化类型,并将其作为参数传递给方法。
测试堆污染?
如果我运行这个测试程序,你可能会明白我的意思,在你的环境中这样做将确认一切:
static TypeFactory typeFactory = TypeFactory.defaultInstance();
public static void main(String[] args) {
TestRig.<List<String>>pharaoh(); // oh, that's bad
TestRig.sam(new TypeReference<List<String>>(){}); // no, that's good
}
public static <T> void pharaoh() {
TypeReference<?> typeRef = new TypeReference<T>() {};
JavaType typeT = typeFactory.constructType(typeRef); // this is what happens inside ObjectMapper
System.out.println("from generic TypeReference: " + typeRef.getType().toString());
System.out.println("from generic TypeReference: " + typeT.toString());
}
public static <T> void sam(TypeReference<T> typeRef) {
JavaType typeT = typeFactory.constructType(typeRef); // this is what happens inside ObjectMapper
System.out.println("from concrete TypeReference: " + typeRef.getType().toString());
System.out.println("from concrete TypeReference: " + typeT.toString());
}
结果:
from generic TypeReference: T <--- booooo
from generic TypeReference: [simple type, class java.lang.Object]
from concrete TypeReference: java.util.List <--- yaaaaaay
from concrete TypeReference: [collection type; class java.util.List, contains [simple type, class java.lang.String]]
† 参考:Java 教程 > Non-Reifiable Types
我在尝试 运行 以下代码时遇到问题:
当我尝试从 ArrayList<double[]> list
获取项目时它抛出 ClassCastException
方法list.get(i)
也会抛出excexption
public void drawRoutes(ArrayList<String> routes) {
if (routes.isEmpty()) return;
for (int i = 0; i < routes.size(); i++) {
PolylineOptions polylineOptions = new PolylineOptions();
ArrayList<double[]> list = TransportRoutes.getRoutes(tag, routes).get(i);
for (double[] points : list) { // throws ClassCastException
map.addPolyline(polylineOptions
.add(new LatLng(points[0], points[1]))
.color(color)
.width(POLY_LINE_WIDTH));
}
}
}
方法 getRoutes() :
public static ArrayList<ArrayList<double[]>> getRoutes(String tag, ArrayList<String> numbers) {
ArrayList<ArrayList<double[]>> routes = new ArrayList<>();
for (String number : numbers) {
routes.add(sRoutesHashMap.get(tag).get(number));
}
return routes;
}
// sRoutesHashMap is a HashMap<String, HashMap<String, ArrayList<double[]>>>
// and taken from this method
protected static <T> T getSmth(Context context, String url) {
T data = null;
JSONParser jsonParser = new JSONParser(context);
String json;
ObjectMapper mapper = new ObjectMapper();
try {
json = jsonParser.execute(url).get();
if (json != null) {
data = mapper.readValue(json, new TypeReference<T>() {});
} else return null;
} catch (InterruptedException | ExecutionException | IOException e) {
e.printStackTrace();
}
return data;
}
完整的堆栈跟踪是:
java.lang.ClassCastException: java.util.ArrayList cannot be cast to double[]
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2211)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2261)
at android.app.ActivityThread.access0(ActivityThread.java:141)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1256)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:5103)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:525)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.ClassCastException: java.util.ArrayList cannot be cast to double[]
at in.transee.transee.Drawer.drawRoutes(Drawer.java:46)
at in.transee.transee.MapsActivity.onCreate(MapsActivity.java:45)
at android.app.Activity.performCreate(Activity.java:5133)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2175)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2261)
at android.app.ActivityThread.access0(ActivityThread.java:141)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1256)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:5103)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:525)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
at dalvik.system.NativeStart.main(Native Method)
当我使用这个方法时,一切都奏效了:
public static void getAllRoutes(Context context) {
String routesJson = sSPData.getString(sCity + ROUTES, EMPTY);
ObjectMapper mapper = new ObjectMapper();
JSONParser jsonParser = new JSONParser();
try {
routesJson = jsonParser.execute(URL + sCity + SEPARATOR + ROUTES).get().get(0);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
try {
sRoutesHashMap = mapper.readValue(routesJson,
new TypeReference<HashMap<String, HashMap<String, ArrayList<double[]>>>>() {});
} catch (IOException e) {
e.printStackTrace();
}
}
您似乎受到了堆污染 †。好消息是我认为你可以通过这样做很容易地绕过它。
protected static <T> T getSmth(TypeReference<T> typeRef, Context context, String url) {
...
data = mapper.readValue(json, typeRef);
并调用它:
sRoutesHashMap = getSmth(new TypeReference<HashMapOfBlahBlahBlah>(){}, context, url);
为什么堆污染?
mapper.readValue
returnsObject
,或者 returnsT
但标有@SuppressWarnings("unchecked")
(我不能找出哪个,可能是后者)- 您将 return 存储为您的通用类型(宾果游戏,这是您的堆污染)
- 但是在通用方法中,从
mapper.readValue
编辑的Object
return 实际上不是您的通用类型 - 这只会在您的
ClassCastException
之后出现
注意:您在通用代码或库通用代码中看到 @SuppressWarnings("unchecked")
的任何地方,您应该小心,因为这种结果很可能
怎么堆污染?
原因可能是因为您的泛型 getSmth
方法中的匿名 new TypeReference<T>(){}
无法评估类型 T
作为您的具体类型参数。如果您查看 TypeReference
的源代码,由于它使用 getGenericSuperclass
和 getActualTypeArguments
.
一个解决方案是在 getSmth
之外创建 TypeReference
的参数化类型,并将其作为参数传递给方法。
测试堆污染?
如果我运行这个测试程序,你可能会明白我的意思,在你的环境中这样做将确认一切:
static TypeFactory typeFactory = TypeFactory.defaultInstance();
public static void main(String[] args) {
TestRig.<List<String>>pharaoh(); // oh, that's bad
TestRig.sam(new TypeReference<List<String>>(){}); // no, that's good
}
public static <T> void pharaoh() {
TypeReference<?> typeRef = new TypeReference<T>() {};
JavaType typeT = typeFactory.constructType(typeRef); // this is what happens inside ObjectMapper
System.out.println("from generic TypeReference: " + typeRef.getType().toString());
System.out.println("from generic TypeReference: " + typeT.toString());
}
public static <T> void sam(TypeReference<T> typeRef) {
JavaType typeT = typeFactory.constructType(typeRef); // this is what happens inside ObjectMapper
System.out.println("from concrete TypeReference: " + typeRef.getType().toString());
System.out.println("from concrete TypeReference: " + typeT.toString());
}
结果:
from generic TypeReference: T <--- booooo from generic TypeReference: [simple type, class java.lang.Object] from concrete TypeReference: java.util.List <--- yaaaaaay from concrete TypeReference: [collection type; class java.util.List, contains [simple type, class java.lang.String]]
† 参考:Java 教程 > Non-Reifiable Types