Java泛型函数的运行时类型检查的问题


在一个数据持久化处理中定义了数据保存和读取的 泛型函数的,但是在运行时出现类型转换错误,类型不匹配,出错的位置不是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方法只是检查了列表类型,没有检查列表中的元素的类型,所以是不严谨的。

相关内容