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

Posted 淡然为之 坦然受之 泰然处之 奋然斗之

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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方法只是检查了列表类型,没有检查列表中的元素的类型,所以是不严谨的。

以上是关于Java泛型函数的运行时类型检查的问题的主要内容,如果未能解决你的问题,请参考以下文章

Java泛型

java泛型总结

JAVA泛型总结

Java入门——泛型

Java 泛型泛型用法 ( 泛型类用法 | 泛型方法用法 | 泛型通配符 ? | 泛型安全检查 )

Java 泛型 (generics) 的使用