码迷,mamicode.com
首页 > 编程语言 > 详细

Java泛型的一些限制

时间:2015-06-07 11:10:10      阅读:185      评论:0      收藏:0      [点我收藏+]

标签:泛型   java   

    本文主要参考《Java编程思想(第4版)》的Java泛型章节,仅当一个简单的读书笔记。

    和C++泛型对比,Java泛型只是一种编译期间的擦拭机制。这是由于考虑到和以前的兼容而考虑的一种折中方案。在编译好的泛型代码里,编译期间已经把所有的泛型信息给擦拭掉,因此无法获得任何有关泛型参数类型的信息。因此List<String>和List<Integer>实际上是同一类型。

    参考以下代码:

    //以下3个例子都无法通过编译
    public <T> void testGeneric(Object arg) {
        if (arg instanceof T) {}    //1
        T var = new T();             //2
        T[] array = new T[100]; //3
    }

    从以上代码可以看到,这种擦拭机制的限制包括如下:

1、instanceof无法使用

2、无法实例化泛型类

3、无法实例化泛型数组

    以上3种方法无法通过编译的主要原因是,泛型的擦拭机制把具体的类型信息都擦拭,无法在运行时知道确切的类型信息。不过Java提供了另外的方法去绕过这些限制。

解决1

对于第1种,无法使用instanceof语法,我们可以利用动态的isInstance():

    //testInstance(String.class, "abc") == true
    public static <T> boolean testInstance(Class<T> c, Object arg) {
        return c.isInstance(arg);
    }<
解决2 

    对于第2种,无法实例化泛型类,如果对于要实例化的泛型类,拥有无参默认构造函数,我们可以利用Class对象:

    public static <T> T createGeneric(Class<T> c) {
        T x = null;
        try {
            x = c.newInstance();
        } catch (Exception e) {
            throw new RuntimeException(e); //createGeneric<Integer.class>会抛出异常,由于Integer没有默认构造函数
        }
        return x;
     }
    由于以上代码采用Class对象实例化拥有一定限制,因此我们还可以借助工厂方法,显示创建对应的类:

    interface GenericFactory<T> {
        T create();
    }
    
    class IntegerFactory implements GenericFactory<Integer> {
        @Override
        public Integer create() {
            return new Integer(0);
        }
    }
解决3

对于第3种,无法实例化泛型数组,我们可以借助ArrayList<T>来代替,但如果一定要获得数组的行为,以及泛型提供的编译期的安全类型,

    //GenericArray ga = new GenericArray<Integer>(10);
    //ga.put(3, 10);
    //int abc = (Integer) ga.get(3);
    //Integer[] aaa = (Integer[]) ga.array(); //抛出ClassCastException
    class GenericArrayEx<T> {
        private T[] array;
        public GenericArray(int size) {
            array = (T[]) new Object[size];
        }

        public void put(int index, T item) {
            array[index] = item;
        }

        public T get(int index) {
            return array[index];
        }

        public T[] array() {
            return array;
        }
    }
    对于以上代码,我们采用一个GenericArray的类进行包装,但内部实际还是一个Object[]的对象数组,在put和get的时候获得了编译期间的检查,但问题来了,如果我们使用array()方法企图获得内部数组并转型的时候,会抛出ClassCastException,这是由于数组实际还是Object[]对象!为了解决这个问题,我们可以使用Array.newInstance。

    //GenericArrayEx ga = new GenericArrayEx<Integer>(Integer.class, 10);
    //ga.put(3, 10);
    //int abc = (Integer) ga.get(3);
    //Integer[] aaa = (Integer[]) ga.array(); //可以成功转型
    class GenericArrayEx<T> {
        private T[] array;
        public GenericArrayEx(Class<T> type, int size) {
            array = (T[]) Array.newInstance(type, size);
        }

        public void put(int index, T item) {
            array[index] = item;
        }

        public T get(int index) {
            return array[index];
        }

        public T[] array() {
            return array;
        }
    }
    这样,就可以使用T[]了。


Java泛型的一些限制

标签:泛型   java   

原文地址:http://blog.csdn.net/pun_c/article/details/46398453

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!