李林超博客
首页
归档
留言
友链
动态
关于
归档
留言
友链
动态
关于
首页
Java
正文
持有对象--泛型和类型安全的容器
Leefs
2019-11-26 AM
1831℃
0条
### 持有对象--泛型和类型安全的容器 ### 前言 在本小节开篇之前,小编抛出几个问题? 1. 1.在之前的篇章中都是在学习怎样创建对象,如何使用对象,对象那么多,在搬运的过程中是否可以用一个袋子将这些对象装起来去统一运输 2. 2.如果我想在任意时刻和任意位置创建任意数量的对象,又该如何保存呢? ### 一、基本概念 在开始本小节之前,小编对**持有对象**这个词比较模糊,虽然每天都在用,本篇要揭开它的神秘面纱,废话不多说,正文开始。 Java有多种方式保存对象(应该说是对象的引用)。例如之前曾经学习过的**数组**,它是编译器支持的类型。**数组是保存一组对象的最有效的方式,如果你想保存一组基本类型的数据,也推荐使用这种方式**。但是数组具有固定的尺寸,你在写程序时并不知道将需要多少个对象。这时候想,是否需要更复杂的方式来存储对象? 为了能够**装**这些情况复杂的对象Java语言提供了一套相当完整的容器类来解决这些问题。最基本的类型是List、Set、Queue和Map。这些对象类型也叫集合类,因为Java的类库中使用了Collection这个名字来指定该类库的一个特殊子集,所以也叫做**容器**。 在容器中你可以存放任意数量的对象,并且不需要担心容器应该设置为多大。 ### 二、泛型和类型安全的容器 使用java SE5之前的容器的一个主要问题就是编译器允许你向容器插入不正确的类型, 例如: ```java package ThinkInJava.InterfaceTest; import java.util.ArrayList; class Apple { private static long counter; private final long id = counter++; public long id() { return id; } } class Orange {} public class ApplesAndOrangesWithoutGenerics { @SuppressWarnings("unchecked")//@SuppressWanrings注解及其参数表示只有有关"不受检查的异常"的警告信息应该被抑制 public static void main(String[] args) { ArrayList apples = new ArrayList(); //一个apple容器 for(int i = 0; i < 3; i++) apples.add(new Apple()); // Not prevented from adding an Orange to apples: apples.add(new Orange()); //却可以插入一个Orange对象 for(int i = 0; i < apples.size(); i++) ((Apple)apples.get(i)).id(); //由于Orange 和Apple没有可以转型的关系,转型失败,运行错误 // Orange is detected only at run time } } /* (Execute to see output) *///:~ ``` 在上个示例中使用`ArrayList`容器来保存对。 `ArrayList`的方法说明: > 1. 1.创建一个实例 > 2. 2.可以使用add()来实现对象插入 > 3. 3.通过使用get()来访问对象,此时需要使用索引,就像数组一样,但是不需要使用方括号 > 4. 4.size()方法可以查看容器中元素数量,避免索引越界 > 代码分析 1. 1.创建一个`ArrayList`容器实例 2. 2.向容器中添加Apple对象 3. 3.同时向容器中添加Orange对象 4. 4.遍历输出Apple对象中的元素 5. 5.运行时抛出异常:`java.lang.ClassCastException: ThinkInJava.InterfaceTest.Orange cannot be cast to ThinkInJava.InterfaceTest.Apple` `@SuppressWanrings`注解及其参数表示只有有关"不受检查的异常"的警告信息应该被抑制 在示例中Apple和Orange类是有区别的,它们除了都是Object之外没有任何共性(记住,如果一个类没有显式地声明继承自哪个类,那么它自动地继承自Object)。 因为`ArrayList`保存的是Object,因此apples容器不仅可以添加Apple对象,还可以添加Orange对象,而且无论在编译期还是运行时都不会有问题。 但是在运行时,当试图将Orange对象转型为Apple时,就会得到异常: ```java Exception in thread "main" java.lang.ClassCastException: ThinkInJava.InterfaceTest.Orange cannot be cast to ThinkInJava.InterfaceTest.Apple at ThinkInJava.InterfaceTest.ApplesAndOrangesWithoutGenerics.main(ApplesAndOrangesWithoutGenerics.java:22) ``` **通过使用泛型,就可以在编译期防止将错误类型的对象放置到容器中。** ```java public class ApplesAndOrangesWithoutGenerics2 { public static void main(String[] args) { ArrayList
apples = new ArrayList
(); for (int i = 0; i < 3; i++) { apples.add(new Apple()); } // Compile-time error: // apples.add(new Orange()); for (int i = 0; i < apples.size(); i++) { System.out.println(apples.get(i).id()); } for (Apple c : apples) { System.out.println(c.id()); } } } ``` > 运行结果 ```java 0 1 2 0 1 2 ``` 现在,编译器可以阻止你将Orange放置到apples中,因此它变成了一个编译期错误,而不再是运行时错误。 通过使用泛型,你不仅知道编译器将会检查你放置到容器中的对象类型,而且在使用容器中的对象时,可以使用更加清晰的语法。 当你指定了某个类型作为泛型参数时,你并不仅限于只能将该确切类型的对象放置到容器中。向上转型也可以像作用于其他类型一样作用于泛型: ```java class GrannySmith extends Apple {} class Gala extends Apple {} class Fuji extends Apple {} class Braeburn extends Apple {} public class GenericsAndUpcasting { public static void main(String[] args) { ArrayList
apples = new ArrayList
(); apples.add(new GrannySmith()); apples.add(new Gala()); apples.add(new Fuji()); apples.add(new Braeburn()); for (Apple c : apples) { System.out.println(c); } } } ``` > 运行结果 ``` java com.java.chapter11.GrannySmith@325dfb22 com.java.chapter11.Gala@147e8bd9 com.java.chapter11.Fuji@f5e12 com.java.chapter11.Braeburn@70e8efc5 ``` 因此,你可以将Apple的子类型添加到被指定为保存Apple对象的容器中。
标签:
Java编程思想
,
持有对象
非特殊说明,本博所有文章均为博主原创。
如若转载,请注明出处:
https://lilinchao.com/archives/223.html
上一篇
内部类之--闭包与回调
下一篇
SQL语句练习题(一)
评论已关闭
栏目分类
随笔
2
Java
326
大数据
229
工具
31
其它
25
GO
47
NLP
4
标签云
Tomcat
Quartz
Hbase
Hadoop
Java工具类
NIO
持有对象
Python
Spark
Elastisearch
并发编程
nginx
Docker
HDFS
工具
Spark RDD
链表
算法
排序
pytorch
Stream流
字符串
JavaScript
Netty
Livy
Java
正则表达式
Java阻塞队列
容器深入研究
JavaSE
友情链接
申请
范明明
庄严博客
Mx
陶小桃Blog
虫洞
评论已关闭