Java 泛型 泛型数组

@author ixenos

  • 先给结论
    • 不能(直接)创建泛型数组
    • 泛型数组实际的运行时对象数组只能是原始类型( T[]为Object[],Pair<T>[]为Pair[] ),而实际的运行时数组对象可能是T类型( 虽然运行时会擦除成原始类型 )
    • 一般解决方案:(泛型数组包装器):使用ArrayList收集泛型数组对象的对象元素,如ArrayList<T>、ArrayList<Pair<String>>
      • 将获得数组的行为,以及由泛型提供的编译期的类型安全
  • 直接创建泛型数组不能通过编译,而转型对象数组通过编译但是不能在JVM运行
      • public class ArrayOfGeneric{
        static Generic<Integer>[] gia;
        @SupperssWarnings("unchecked")
        public static void main(String[] args){
        gia = (Generic<Integer>[])new Generic[100]; // 通过类型转换匿名对象
        //! gia[0] = new Object(); //编译不通过,不能(直接)创建泛型数组实例
        }
        }
    • 问题在于数组将跟踪他们的实际类型,而这个类型是在数组被创建时确定的,因此,即使gia已经被转型为Generic<Integer>[],但这个信息只存在于编译期(并且如果没有@SuppressWarning("unchecked")注解,将得到这个转型的警告)。在运行时,它仍旧是Object数组
    • 因此,成功创建泛型数组的唯一方式就是创建一个被擦出类型的新数组,然后对其转型(而且是在运行时转型)
      •  直接对整个数组强制转型,在编译时依旧会被擦除掉类型!所以应该在运行时转型,而这时最好的办法就是使用一个泛型数组包装器,维护一个原始类型的数组,通过数组入口方法进行元素编译期的类型安全检测(对应返回值)和强制类型转换(对于运行时不重要),从而保证类型安全。
    • 对整个数组强制转型的例子(错误方法)
    • public class GenericArray<T> {
      private T[] array;
      @SupperessWarning("unchecked")
      public GenericArray(int sz) {
      array = (T[]) new Object[sz];
      }
      public void put(int index, T item) {
      array[index] = item;
      }
      public T get(int index) { return array[index]; }
      public T[] rep() { return array; } //应该在运行时出口做文章
      public static void main (String[] args){
      GenericArray<Integer> gai = new GenericArray<Integer>(10);
      // Integer[] ia = gai.rep(); //ClassCastException
      Object[] oa = gai.rep(); //只能返回对象数组类型为Object[]
      • 实际的运行时对象数组是Object[],而实际的运行时数组对象可能是T类型。
    • 因此,应该在运行时,数组对象的出口做转型输出,入口方法在编译期已实现类型安全,所以出口方法可以放心强制类型转换,保证成功。如下

      • public class GenericArray2<T> {
        private Object[] array; //维护Object[]类型数组
        @SupperessWarning("unchecked")
        public GenericArray2(int sz) {
        array = new Object[sz];
        }
        public void put(int index, T item) {
        array[index] = item;
        }
        public T get(int index) { return (T)array[index]; }//数组对象出口强转
        public T[] rep() { return (T[])array; } //运行时无论怎样都是Object[]类型
        public static void main (String[] args){
        GenericArray<Integer> gai = new GenericArray<Integer>(10);
        // Integer[] ia = gai.rep(); //依旧ClassCastException
        Object[] oa = gai.rep(); //只能返回对象数组类型为Object[]
        gai.put(0,11);
        System.out.println(gai.get(0)); // 11 ,出口成功转型
        }
        }
  •  通过反射在运行时构出实际类型为type[]的对象数组,避免了类型擦除,从而转换成功,无ClassCastException
import java.lang.reflect.*; 

public class GenericArrayWithTypeToken<T> {
private T[] array;
@SuppressWarning("unchecked")
public GenericArrayWithTypeToken(Class<T> type, int sz) {
array = (T[]) Array.newInstance(type, sz);//通过反射在运行时构出实际类型为type[]的对象数组,避免了类型擦除,从而转换成功,无ClassCastException
}
public void put(int index, T item){
array[index] = item;
}
public T get(int index) { return array[index]; }
public T[] rep() { return array; } //能成功返回了~
public static void main(String[] args) {
GenericArrayWithTypeToken<Integer> gawtt = new GenericArrayWithTypeToken<>(Integer.class, 10);
Integer[] ia = gawtt.rep(); //能成功返回了!
}
}

Java 泛型 泛型数组的更多相关文章

  1. 《徐徐道来话Java》(2):泛型和数组,以及Java是如何实现泛型的

    数组和泛型容器有什么区别 要区分数组和泛型容器的功能,这里先要理解三个概念:协变性(covariance).逆变性(contravariance)和无关性(invariant). 若类A是类B的子类, ...

  2. Java“禁止”泛型数组

    Java“禁止”泛型数组 原文:https://blog.csdn.net/yi_Afly/article/details/52058708 1. 泛型定义泛型编程是一种通过参数化的方式将数据处理与数 ...

  3. Java 泛型 五:泛型与数组

    简介 上一篇文章介绍了泛型的基本用法以及类型擦除的问题,现在来看看泛型和数组的关系.数组相比于Java 类库中的容器类是比较特殊的,主要体现在三个方面: 数组创建后大小便固定,但效率更高 数组能追踪它 ...

  4. Java泛型与数组深入研究

    Java中的泛型与数组平时开发用的很多,除了偶尔遇到"NullPointerException"和"IndexOutOfBoundsException"一般也不 ...

  5. (转载)Java里新建数组及ArrayList java不允许泛型数组

    java中新建数组: String[] s;//定义的时候不需要设置大小 s = new String[5];//为数组分配空间时就要设置大小   对于ArrayList, ArrayList< ...

  6. Java笔记--泛型总结与详解

    泛型简介: 在泛型没有出来之前,编写存储对象的数据结构是很不方便的.如果要针对每类型的对象写一个数据结构,     则当需要将其应用到其他对象上时,还需要重写这个数据结构.如果使用了Object类型, ...

  7. [改善Java代码]Java的泛型是类型擦除的

    泛型可以减少强制类型的转换,可规范集合的元素类型,还可以提高代码的安全性和可读性,正是因为有了这些优点,自从Java引入泛型之后,项目的编码规则上便多了一条,优先使用泛型. Java泛型(Generi ...

  8. Java 中泛型的全面解析(转)

    Java泛型(generics) 是JDK 5中引入的一个新特性,允许在定义类和接口的时候使用类型参数(type parameter).声明的类型参数在使用时用具体的类型来替换.泛型最主要的应用是在J ...

  9. Java中泛型 类型擦除

    转自:Java中泛型是类型擦除的 Java 泛型(Generic)的引入加强了参数类型的安全性,减少了类型的转换,但有一点需要注意:Java 的泛型在编译器有效,在运行期被删除,也就是说所有泛型参数类 ...

随机推荐

  1. Android进程回收的一些知识

    关于OOM_ADJ说明: Android 进程易被杀死的情形: 参考:Android进程保活招式大全

  2. centos下安装Jenkins轻松搞定

    jenkins安装步骤如下: 命令:yum -y list java* yum -y install java-1.7.0-openjdk.x86_64                         ...

  3. ios开发设置不同字体

    最近项目开发中遇到需要设置指定字体的需求,研究了一下字体设置,最后附有我写的一个小demo,先来看一下效果: 开始上网搜了一下,普遍说到以下方法 for(NSString *fontfamilynam ...

  4. jQuery操作radio

    JQuery获取选中的radio $radio = $('input:radio[name="sex"][class="xxxx"]:checked') 获取n ...

  5. 关于Objective-C Associated Objects

    一.相关函数 与Associated Objects相关的函数有三个 1 void objc_setAssociatedObject(id object, const void *key, id va ...

  6. Symfony没有安装依赖_PHP Fatal error: require(): Failed opening required

    $ php bin/console server:run PHP Warning: require(D:\home\workspace\pd\app/../vendor/autoload.php): ...

  7. iOS SDWebImage的使用

    现在把代码贴出来,供大家参考.尤其是新手,看完这篇博客,图片缓存so easy.最后有demo供大家下载,先学习. 第一步,下载SDWebImage,导入工程.github托管地址https://gi ...

  8. vue实例生命周期

    实例生命周期 var vm = new Vue({ data: { a: 1 }, created: function () { // `this` 指向 vm 实例 console.log('a i ...

  9. [Q]注册申请码获取工具问题

    问题一: 异常信息: 有关调用实时(JIT)调试而不是此对话框的详细信息, 请参见此消息的结尾. ************** 异常文本 ************** System.Reflectio ...

  10. AJAX在Struts2中使用

    前台页面: <%@ page language="java" contentType="text/html; charset=UTF-8" pageEnc ...