zoukankan      html  css  js  c++  java
  • 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[]了。


  • 相关阅读:
    杂货铺
    oracle修改已存在数据的字段类型
    使用python读取配置文件并从mysql数据库中获取数据进行传参(基于Httprunner)
    HttpRunner完整笔记(从搭建到应用)
    使用jmeter发送put请求的三种方式
    电脑同时安装了python2和python3后,随意切换版本并使用pip安装
    python+request+HTMLTestRunner+unittest接口自动化测试框架
    redis简介
    spring cloud gateway之服务注册与发现
    spring cloud gateway 之限流篇
  • 原文地址:https://www.cnblogs.com/blfshiye/p/5409425.html
Copyright © 2011-2022 走看看