Java 泛型 泛型数组

@author ixenos

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

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

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. JDK安装(CentOS/rpm方式)

    1. 用如下命令检验是否已经自带了OpenJDK java -version 如果打印如下,则表示安装了OpenJDK java version "1.6.0" OpenJDK R ...

  2. chap1 C++泛型技术基础--模板 #STL

    0 缘起 有一点编程经验和积累,想系统的学习下STL,以前都是随意做的笔记,现在想着成主题的输出一下. 书的原型是ISBN:9787302421757 <C++泛型STL原理和应用>,是从 ...

  3. asp.net mvc + mysql + ef6

    1.通过NuGet包管理器安装:EntityFramework6.1.3.MySql.Data.Entity6.9.9 2.添加新建项→ADO.NET实体对象模型(命名MyContext)→空Code ...

  4. jmeter java性能测试

    本篇文章主要讲解jmeter如何测试java请求,以项目中某个接口为例,请求数据为post,返回也为post 1:新建maven工程,pom文件为 <project xmlns="ht ...

  5. Payload Inject And Fake

    常见捆绑注入payload手法 Payload捆绑注入 注入exe型+编码: msfvenom -a <arch> --plateform <platform> -p < ...

  6. jffs2reset 实现分析

    在脚本 reset2default中看到如下内容: #!/usr/bin/lua local hwm = require "hwm" hwm.myexec("jffs2r ...

  7. 使用$_SERVER['HTTP_HOST']时需注意的

    在php中,我们一般通过$_SERVER['HTTP_HOST']来活得URL中网站的域名或者ip地址. $_SERVER['HTTP_HOST']在客户的环境里,取得的值总是程序所在的服务器在其局域 ...

  8. 7、Objective-C中的各种遍历(迭代)方式

    一.使用for循环 要遍历字典.数组或者是集合,for循环是最简单也用的比较多的方法,示例如下: //普通的for循环遍历 -(void)iteratorWithFor { //////////处理数 ...

  9. ORACLE ORDER BY用法总结

    order by后面的形式却比较新颖(对于我来说哦),以前从来没看过这种用法,就想记下来,正好总结一下ORDER BY的知识. 1.ORDER BY 中关于NULL的处理 缺省处理,Oracle在Or ...

  10. winsock编程IOCP模型实现代码

    winsock编程IOCP模型实现代码 话不多说,上代码.借鉴<windows核心编程>部分源码和CSDN小猪部分代码. stdafx.h依赖头文件: #include <iostr ...