在一个数据持久化处理中定义了数据保存和读取的 泛型函数的,但是在运行时出现类型转换错误,类型不匹配,出错的位置不是load方法,而是在调用load方法之后,得到了列表数据,对列表数据进行使用时出现的。结果列表里面的元素实际是A类型,调用load方法传递的是B类型的class,但是仍然load成功。
很是疑惑,最终修改代码调试后,解决问题。
import android.content.Context; import android.text.TextUtils; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.ObjectInputStream; import java.util.ArrayList; /** * 从私有文件加载对象 * @param context * @param key 键值(文件名) * @return */ public static Object loadFromPrivateFile(Context context, String key) { if (context == null || TextUtils.isEmpty(key)) { return null; } ObjectInputStream objectIn = null; Object result = null; try { FileInputStream fileIn = context.openFileInput(key); objectIn = new ObjectInputStream(fileIn); result = objectIn.readObject(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } finally { if (objectIn != null) { try { objectIn.close(); } catch (IOException e) { } } } return result; } /** * 加载实体对象 * @param context * @param key 键值(文件名) * @param clazzOfT 类类型 */ public static <T> T loadEntityObject(Context context, String key, Class<T> clazzOfT) { Object object = loadFromPrivateFile(context, key); if (object != null && clazzOfT != null && clazzOfT.isInstance(object)) { return clazzOfT.cast(object); } try { return (T) clazzOfT.newInstance(); } catch (Exception e) { e.printStackTrace(); } return null; } /** * 加载数组列表 * @param context * @param key 键值(文件名) * @param clazzOfT 类类型 * @return */ @SuppressWarnings("unchecked") public static <T> ArrayList<T> loadArrayList(Context context, String key, Class<T> clazzOfT) { Object object = loadFromPrivateFile(context, key); if (object instanceof ArrayList<?>) { try { return (ArrayList<T>)object; } catch (Exception e) { } } return null; } /** * 加载数组列表 * @param context * @param key 键值(文件名) * @param clazzOfT 类类型 * @return */ @SuppressWarnings("unchecked") public static <T> ArrayList<T> loadArrayList2(Context context, String key, Class<T> clazzOfT) { ArrayList<T> result = null; Object object = loadEntityObject(context, key, Object.class); if (object instanceof ArrayList<?>) { result = new ArrayList<T>(); ArrayList<?> list = (ArrayList<?>)object; try { final String className = clazzOfT. getName(); for (Object item : list) { if (item. getClass().getName().equals(className)) { result. add((T)item); } } } catch (Exception e) { e.printStackTrace(); } } return result; }
loadArrayList方法是错误的实现,下面的loadArrayList2是正确的实现。
原因分析:泛型的类型信息在运行时是丢弃掉的,准确叫擦除(erasure),只有在编译时起到语法检查的作用。最初的loadArrayList方法只是检查了列表类型,没有检查列表中的元素的类型,所以是不严谨的。