• 8.5 泛型和数组


    Java设计及的一个原则——如果一段代码在编译时没有提出“unchecked未经检查的转换”的警告,则程序在运行时不会引发ClassCastException异常。正是基于这个原因,所以数组元素的类型不能包含泛型变量、泛型形参,除非时无上限的类型通配符。但可以声明元素类型包含泛型变量或泛型形参的数组。也就是说List<String>[]数组,但不能创建ArrayList<String>[10]这样的数组。

    假设Java支持创建ArrayList<String>[10]这样的数组对象,则有以下程序:

    //下面代码实际上时不允许的
    List<String>[] lsa=new ArrayList<String>[10];
    //将lsa向上转型为Object[]类型的变量
    Object[] oa=lsa;
    List<Integer> li=new ArrayList<>();
    li.add(3);
    //将List<Integer>对象作为oa的第二个元素
    //下面代码没有任何警告
    oa[1]=li;
    //下面代码也不会出现任何警告,但会引发ClassCastException异常
    String s=lsa[1].get(0);

    上面代码违背了Java泛型设计的原则。上述过程,图示为:

     将程序改成下面形式:

     1 import java.util.*;
     2 public class GenericAndArray1
     3 {
     4     public static void main(String[] args)
     5     {
     6         // 下面代码编译时有“[unchecked] 未经检查的转换”警告
     7         List<String>[] lsa = new ArrayList[10];
     8         // 将lsa向上转型为Object[]类型的变量
     9         Object[] oa = lsa;
    10         List<Integer> li = new ArrayList<>();
    11         li.add(3);
    12         oa[1] = li;
    13         // 下面代码引起ClassCastException异常
    14         String s = lsa[1].get(0);              //
    15     }
    16 }
    17 ---------- 编译Java ----------
    18 注: GenericAndArray1.java使用了未经检查或不安全的操作。
    19 注: 有关详细信息, 请使用 -Xlint:unchecked 重新编译。
    20 
    21 输出完成 (耗时 1 秒) - 正常终止

     上面代码List<String>[]类型的数组变量是可以的,但是不允许创建new List<String>[]类型的对象,所以创建一个类型为ArrayList[10]的数组对象,这也是允许的。只是把一个ArrayList[10]对象赋给List<String>[]变量时,将会有编译警告:“[unchecked] 未经检查的转换”,即编译器不保证上面这段代码是类型安全的。因此当程序运行到String s = lsa[1].get(0); 将出现运行错误。

    Java允许创建无上限的通配符泛型数组,例如new ArrayList<?>[10],因此可以将第一段代码改为使用无上限的通配符泛型数组,在这种情况下,程序不得不进行强制类型转换。下面代码正确:

     1 import java.util.*;
     2 public class GenericAndArray2
     3 {
     4     public static void main(String[] args)
     5     {
     6 
     7         List<?>[] lsa = new ArrayList<?>[10];
     8         Object[] oa = lsa;
     9         List<Integer> li = new ArrayList<>();
    10         li.add(3);
    11         oa[1] = li;
    12         Object target = lsa[1].get(0);
    13         //程序在进行强制类型转换时,需要通过instanceOf运算符判断它的数据类型
    14         if (target instanceof String)
    15         {
    16             // 下面代码安全了
    17             var s = (String) target;
    18         }
    19     }
    20 }
  • 相关阅读:
    Delphi对象的产生和消亡过程
    WIN32的时空观
    PHP类的用法
    D7的System.pas单元的实现部分
    PHP的最简单用法
    C调用Lua
    js连连看
    动态属性的一个架构
    Entity Framework开源了
    apachesolr4.0.0ALPHA中文分析器IKAnalyzer4.0
  • 原文地址:https://www.cnblogs.com/weststar/p/12614253.html
Copyright © 2020-2023  润新知