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[]了。

时间: 2024-10-26 06:52:07

Java泛型的一些限制的相关文章

Java泛型中的PECS原则

今天在写代码的时候使用到了这样一个方法签名: public void foo(Map<String, String> map); 在写这个参数的时候正好在想一些关于泛型的东西,于是: public void foo(Map<? extends String, ? extends String> map); 这两种写法有什么区别呢?记得以前和同学讨论过这个问题,但后来没有记下来,渐渐又淡忘了.今天又去翻了好多资料,总算找到一些可以参考的,赶紧记在这里方便以后温故知新啦.好了,言归正传

Java泛型的协变

在上篇<Java泛型的基本使用>这篇文章中遗留下面问题,即将子类型也能加入到父类型的泛型中.要实现这样的功能必须借助于协变. 实验准备 如今在上篇文章展示的Decorator类型的基础上,添加一些代码,如代码清单1所看到的. 代码清单1 /** * * 描 述:Exp2使用br/> * 作 者:jiaan.gja<br/> * 历 史: (版本号) 作者 时间 凝视 <br/> * @param itemList */ public void doDecorate

2017.4.5 Java 泛型

Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型. 泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数. 假定我们有这样一个需求:写一个排序方法,能够对整形数组.字符串数组甚至其他任何类型的数组进行排序,该如何实现? 答案是可以使用 Java 泛型. 使用 Java 泛型的概念,我们可以写一个泛型方法来对一个对象数组排序.然后,调用该泛型方法来对整型数组.浮点数数组.字符串数组等进行排

关于Java泛型的使用

在目前我遇到的java项目中,泛型应用的最多的就属集合了.当要从数据库取出多个对象或者说是多条记录时,往往都要使用集合,那么为什么这么使用,或者使用时有什么要注意的地方,请关注以下内容. 感谢Windstep. 原文链接:http://www.cnblogs.com/lwbqqyumidi/p/3837629.html 原文标题:Java总结篇系列:Java泛型 (我的第一篇水文,233)

java 泛型 窜讲

一.为什么使用泛型      复用性:泛型的本质就是参数化类型,因而使用编写的泛型代码可以被许多不同类型的对象所复用.      安全性:在对类型Object引用的参数操作时,往往需要进行显式的强制类型转换.这种强制类型转换需要在运行时才能被发现是否转换异常,通过引入泛型能将在运行时才能检查类型转换,提前到编译时期就能检查. 二.自定义泛型 java中自定义泛型分为三种:泛型类.泛型接口.泛型方法. 下面使用一个案例演示泛型类.泛型方法,泛型接口类似,所以不再演示. // 自定义泛型类publi

1月21日 - (转)Java 泛型

java泛型 什么是泛型? 泛型(Generic type 或者 generics)是对 Java 语言的类型系统的一种扩展,以支持创建可以按类型进行参数化的类.可以把类型参数看作是使用参数化类型时指定的类型的一个占位符,就像方法的形式参数是运行时传递的值的占位符一样. 可以在集合框架(Collection framework)中看到泛型的动机.例如,Map 类允许您向一个 Map 添加任意类的对象,即使最常见的情况是在给定映射(map)中保存某个特定类型(比如 String)的对象. 因为 M

Java泛型_上界extends_下界super

?Java泛型_上界extends_下界super ? 通配符类型 <? extends T> 表示类型的上界,表示参数化类型的可能是T或是T的子类 <? super T> 表示类型下界(Java Core中叫超类型限定),表示参数化类型是此类型(T)的超类型(父类型),直至Object 当使用 Upper Bound 通配符时 如下代码, /**  * 代码中通配符<?> 是 <? extends Object> 的简写  *  * @param list

C++泛型 &amp;&amp; Java泛型实现机制

C++泛型 C++泛型跟虚函数的运行时多态机制不同,泛型支持的静态多态,当类型信息可得的时候,利用编译期多态能够获得最大的效率和灵活性.当具体的类型信息不可得,就必须诉诸运行期多态了,即虚函数支持的动态多态. 对于C++泛型,每个实际类型都已被指明的泛型都会有独立的编码产生,也就是说list<int>和list<string>生成的是不同的代码,编译程序会在此时确保类型安全性.由于知道对象确切的类型,所以编译器进行代码生成的时候就不用运用RTTI,这使得泛型效率跟手动编码一样高.

java 泛型详解(普通泛型、 通配符、 泛型接口,泛型数组,泛型方法,泛型嵌套)

JDK1.5 令我们期待很久,可是当他发布的时候却更换版本号为5.0.这说明Java已经有大幅度的变化.本文将讲解JDK5.0支持的新功能-----Java的泛型. 1.Java泛型  其实Java的泛型就是创建一个用类型作为参数的类.就象我们写类的方法一样,方法是这样的method(String str1,String str2 ),方法中参数str1.str2的值是可变的.而泛型也是一样的,这样写class Java_Generics<K,V>,这里边的K和V就象方法中的参数str1和st

java泛型的讲解

java泛型 什么是泛型? 泛型(Generic type 或者 generics)是对 Java 语言的类型系统的一种扩展,以支持创建可以按类型进行参数化的类.可以把类型参数看作是使用参数化类型时指定的类型的一个占位符,就像方法的形式参数是运行时传递的值的占位符一样. 可以在集合框架(Collection framework)中看到泛型的动机.例如,Map 类允许您向一个 Map 添加任意类的对象,即使最常见的情况是在给定映射(map)中保存某个特定类型(比如 String)的对象. 因为 M