浅谈java泛型的类型转换问题

来源:互联网 发布:java程序调用rest api 编辑:程序博客网 时间:2024/06/09 14:59

浅谈java泛型的类型转换问题

  • 先引出问题如下:

下面代码编译时<1>处不报错,<2>处报错,为何?

public class Test {    public static <T> void printList(List<T> lists) {        @SuppressWarnings("unchecked")        List<Object> mLists = (List<Object>) lists;//<1>此处为什么不报错?        System.out.println(mLists.toString());    }    public static void main(String[] args) {        List<Object> list_1 = new ArrayList<Object>();        List<String> list_2 = new ArrayList<String>();        list_1.add("Test");        list_1.add(23);        list_2.add("zhong");        list_2.add("guo");        list_1 = (List<Object>)list_2; //<2>此处是编译时检查,显然这种类型转换时不被允许的。        printList(list_1);        printList(list_2);    }}

程序运行结果如下:

运行结果



我们知道,形如下面的转换在java中是不被允许的:

class A{}class B extends A{}List<B> listB = new ArrayList<B>();List<A> listA = (List<A>)listB; //编译报错

List<B>是不能转换为List<A>的,这两种类型看似向上转型合理,其实是没有任何继承关系,理解这点,也就明白刚开始的<2>处为什么编译报错了。那我们现在讨论一下<1>处为什么不报错?

public static <T> void printList(List<T> lists) {        @SuppressWarnings("unchecked")        List<Object> mLists = (List<Object>) lists;//<1>        System.out.println(mLists.toString());    }

我的理解是,调用printList函数时,所涉及到的转型(针对泛型)是一种动态的运行时转型(编译期不做检查,也没法做),而根据java泛型的类型擦除,到时不管List<Object>中的类型参数是什么都擦除为List<Object>,所以从这个意义上说,只要是List类型,不管类型参数是什么,理论上都不会报错。下面我们对其进行验证如下:

  • List 类型参数为A(List<A>)
public class Test {    class A{}    public static <T> void printList(List<T> lists) {        @SuppressWarnings("unchecked")        List<A> mLists = (List<A>) lists; //<1>        System.out.println(mLists.toString());    }    public static void main(String[] args) {        List<Object> list_1 = new ArrayList<Object>();        List<String> list_2 = new ArrayList<String>();        list_1.add("Test");        list_1.add(23);        list_2.add("zhong");        list_2.add("guo");//      list_1 = (List<Object>)list_2; //(1)此处是编译时检查,显然这种类型转换时不被允许的。        printList(list_1);        printList(list_2);    }}

编译后结果如下:
这里写图片描述

其中类型A是我们自己定义的内部类型,同样不报错,同样的执行结果。
由此可验证我们的想法。




备注:

    刚开始接触java,理解不深,今天看LoaderManager时,看到如下调用,顿感困惑,所以才有这一篇文章,下面我将LoaderManager中令我困惑的地方贴出,以供同仁们参考,有理解不正确的地方望大胆指出。
@SuppressWarnings("unchecked")@SuppressWarnings("unchecked")    public <D> Loader<D> initLoader(int id, Bundle args, LoaderManager.LoaderCallbacks<D> callback) {        if (mCreatingLoader) {            throw new IllegalStateException("Called while creating a loader");        }        LoaderInfo info = mLoaders.get(id);        if (DEBUG) Log.v(TAG, "initLoader in " + this + ": args=" + args);        if (info == null) {            // Loader doesn't already exist; create.            //注意此处callback的类型转换,            info = createAndInstallLoader(id, args,  (LoaderManager.LoaderCallbacks<Object>)callback);            if (DEBUG) Log.v(TAG, "  Created new loader " + info);        } else {            if (DEBUG) Log.v(TAG, "  Re-using existing loader " + info);            info.mCallbacks = (LoaderManager.LoaderCallbacks<Object>)callback;        }        if (info.mHaveData && mStarted) {            // If the loader has already generated its data, report it now.            info.callOnLoadFinished(info.mLoader, info.mData);        }        return (Loader<D>)info.mLoader;    }
原创粉丝点击