再回首Java第二十七天

泛型与数组

JDK1.5还有一个很重要的设计原则:如果一段代码在编译时系统没有产生:”unchecked未经检测的转换“,则程序在运行时不会引发”ClassCastException“异常。正是基于这个原因,所以数组元素的类型不能包含类型变量或类型形参,除非是无上限的类型通配符。但可以声明这样的数组,即使声明元素类型包含类型变量或类型形参的数组。也就是说:只能声明List<String>[]数组,但不能创建ArrayList<String>[10]这样的数组对象

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

//下面代码实际上是不允许的

List<String>[]  lsa=new ArrayList<String>[10];

//强制类型转化为一个Object数组

Object[] oa=(Object[])lsa;

List<Integer> li=new ArrayList<Integer>();

li.add(new Integer(3));

//将List<Integer>对象作为oa的第一个元素

//下面代码没有任何警告

oa[1]=li;

//下面代码也不会有任何警告,但是会引起ClassCastException异常

String s=lsa[1].get(0);

如果能够创建ArrayList<String>[10]这样的数组,经过中间系列的程序运行,势必在代码最后一行引起异常,这就违背Java泛型的设计原则

如果将程序该成如下形式

//下面代码编译时有 “[unchecked]未经检查的转换”警告

List<String>[] lsa=new ArrayList[10];

Object[] oa=(Object[]) lsa;

List<Integer> li=new ArrayList<Integer>();

li.add(new Integer(3));

oa[1]=li;

//下面代码将一起ClassCastException异常

String s=lsa[1].get(0);

上面代码:声明List<String>[]类型的数组变量时允许的;但不允许创建List<String>[]类型的对象,所以创建了一个ArrayList[10]的数组对象,这是允许的。只是把ArrayList<10>对象赋值给List<String>[]变量时会有编译警告:未经检查的转换,即编译器不保证这段代码的类型安全的。所以后面代码会引发ClassCastException异常,但因为编译器 已经提出了警告,所以完全有可能发生这种异常

Java运行创建无上限的通配符泛型数组,例如new ArrayList<?>[10],在这种情况下程序不得不进行强制类型转换,如下代码所示

List<?>[] lsa=new ArrayList<?>[10];

Object[] oa=(Object[]) lsa;

List<Integer> li=new ArrayList<Integer>();

li.add(new Integer(3));

oa[1]=li;

//下面代码将一起ClassCastException异常

String s=lsa[1].get(0);

编译上面代码不会引起任何警告,当程序运行到最后引发ClassCastException异常,因为程序将lsa的第一个元素的第一个集合元素赋值给String类型的变量,所以程序应该自己通过instanceof运算符来保证它的数据类型

List<?>[] lsa=new ArrayList<?>[10];

Object[] oa=(Object[]) lsa;

List<Integer> li=new ArrayList<Integer>();

li.add(new Integer(3));

oa[1]=li;

Object target=lsa[1].get(0);

if(target instanceof String){

String s=(String)target;

}

与此类似的是:创建元素类型是类型变量的数组对象也将导致编译错误。如下面代码所示:

<T> T[] makeArray(Collection<T> coll){

//下面代码将导致编译错误

return new T[coll.size()];

}

因为类型变量在运行时并不存在,所以编译器无法确定实际类型是什么

时间: 2024-11-08 15:47:05

再回首Java第二十七天的相关文章

再回首Java第二十二天

类加载器的种类: 1.Bootstrap ClassLoader: 负责加载Java核心类,即$JAVA_HOME/jre/lib/rt.jar,由C++实现 2.Extension ClassLoader: 负责加载Java平台扩展功能的一些jar,包括$JAVA_HOME/jre/lib/*.jar和$JAVA_HOME/jre/lib/ext/*.jar 3.System(App) ClassLoader:负责加载classpath中指定的jar或.class 4.Custom Class

再回首Java第二十六天

推回输入流在Java输入.输出流体系中有两个特殊的流与众不同,就是PushbackInputStream/PashbackReader,它们都提供了如下三个方法:?void unread(byte[]/char[] buf):将以一个字节/字符数组内容推回到推回缓冲区里,从而允许重复读取刚刚读取的内容.?void unread(byte[] /char[] buf, int off,int ben):把一个字节/字符数组从off开始,长度为len字节/字符的内容推回到推回缓冲区里,从而允许重复读

再回首Java第二十五天

流的分类按照流的流向来分,可以分为输入流和输出流?输入流:只能从中读取数据,不能向其写数据?输出流:只能向其写数据,不从能从中读数据 Java输入流主要有InputStream和Reader作为基类,Java输出流主要以OutputStream和Writer作为基类 字节流和字符流字节流和字符流的用法几乎完全一样,区别在于字节流和字符流所操作的数据单元不一样:字节流操作的最小数据单元是8位的字节,而字符流操作的最小数据单元是16位的字符 节点流和处理流可以从向一个特定的IO设备(如磁盘.网络)读

再回首Java第二十四天

Callable和FutureJava1.5开始,Java提供了Callable接口,Callable接口提供了一个call()方法作为线程的执行体,但call()方法run()方法的功能更强大:?call()方法可以有返回值?call()方法可以声明抛出异常因此我们完全可以提供一个Callable对象作为Thread的target,而该线程的执行体就是该Callable对象的call方法.问题是:Callable对象时JDK1.5开始新增的接口,而它并不是Runnable的子接口,所以Call

再回首Java第十七天

同步锁JDk1.5之后,java提供了另一种线程同步机制:它通过显式定义同步锁对象来实现线程同步,在这种机制下,同步锁应该使用Lock对象充当.通常认为:Lock提供了比synchronized方法和synchronized代码块更广泛的操作,Lock实现允许更灵活的结构,可以具有很大的差别的属性,并且可以支持多个相关的Condition对象Lock是控制多个线程对共享资源进行访问的工具.通常Lock提供了对共享资源的独占访问,每次只允许一个线程对Lock对象加锁,线程访问共享资源之前应先获得L

再回首Java第二十三天

序列化版本问题由于反序列化Java对象时必须提供该对象的class文件,现在的问题是随着项目的升级,系统class文件也会升级,Java如何保证两个class文件的兼容性呢Java序列化机制允许为序列化类提供一个private static final 的serialVersionUID属性值,该属性用于该Java类的序列化版本,也就是说如果一个类升级后,只要它的serialVersionUID属性值保持不变,序列化机制也会把它们当成同一个序列化版本为了在反序列化时,确保序列化版本的兼容性,最好

再回首Java第二十一天

DOM和SAX解析技术的实现 实现DOM和SAX即系技术的方法有多种,下面列出了常用的几种方法 JAXP(Java API for XML:JAXP是对应用程序隐藏了特定解析器的接口,它提供了访问DOM和SAX实现的抽象层机制 JDOM:JDOM是一种使用XML的独特Java工具包,用于快速开发XML应用程序,它基于树型结构,利用纯Java的技术对XML文旦实现解析.生成.序列化以及多种操作.JDOM直接为Java编程服务.它利用更为请有力的Java语言的诸多特性(方法重载.集合概念以及樱色),

再回首Java第十三天

Java异常处理机制主要依赖与五个关键字try catch throw throws finally.try代码块中放置可以发生异常的代码,catch后面参数用表明捕获的异常的类型,异常处理机制将会把抛出的异常实例赋值给这个参数,catch代码块中代码用于打印异常,处理异常,catch可以有多个用于捕获不同类型的异常.最后还可以有一个finally用于回收try代码块中打开的资源,不管讨try代码块中有没有出现异常Java异常处理机制会保证finally块总会被执行.Throws关键字在方法的签

再回首Java第三天

JDK(Java SE Development Kit) 即Java标准版开发包,提供了编译.运行Java程序所需的各种工具和资源包括Java编译器,Java运行时环境,以及常用的Java类库. JRE(Java Runtime Environment) 即Java运行时环境,包含了JVM.类加载器.字节码校验器及大量的基础类库. Java运行时数据区分为:1.程序计数器 2.Java栈 3.本地方法栈 4.方法区 5.堆 程序计数器占用小部分内存区域,程序通过它的值寻找要执行的语句的字节码,由