- 浏览: 772300 次
- 性别:
- 来自: 太原
博客专栏
-
Java编程Step-by...
浏览量:161269
文章分类
最新评论
-
liuwei1981:
尘土飞扬 写道取整的函数,返回值是double?测试下就能看出 ...
86.Math类的使用 -
尘土飞扬:
取整的函数,返回值是double?
86.Math类的使用 -
尘土飞扬:
终于清楚了Date和Calendar的来龙去脉谢谢
90.Java日期处理 -
谁说我不是会员:
liuwei1981 写道hupu_2014 写道根据你的执行 ...
65.对象的构造以及初始化 -
谁说我不是会员:
有的地方能优化,有的不能,不能一概而论。
有必要用StringBuilder的append代替String的+字符串连接运算么
一个容器(container)是用一个对象来“存放”一组对象,其中的每个对象作为容器的一个元素。所有的容器类都放在java.util包中。
在Java 2 中,对JDK1.0和JDK1.1中的容器工具作了重新的设计,它由《Effective Java》的作者Joshua Bloch主持设计。重新设计后的容器类库,提供了更严谨的实现,更丰富的类库。
容器类库中,分为两大类:Collection(集合)和Map(映像)。Collection存放的是一组各自独立的对象;Map存放的是一群成对的“键-值”对象。
在容器 API中,代表对象集合的接口有:
Collection:抽象的集合;
Set:Collection的子接口,一个无重复集;
List:Collection的子接口,一个有序可重复列表。
而Map接口有:
Map:一个用于放置“键-值”对的映像。
1 Collection接口
Collection是一个接口,它有三个基本的方法:
boolean add(Object obj):用于将一个对象放入到集合中,当原有Collection对象改变后,它返回true;
boolean addAll(Collection col):将另一个Collection对象中的所有元素插入该Collection对象中,当目标Collection对象改变后,它将返回true;
Iterator iterator():它返回一个Iterator(遍历器)接口对象
在Collection还定义了一些其他的方法,请参考API文档。
2 List
List是Collection的子接口,它用于保存有序的可重复的对象,它增加了对于索引的定义,放置在List内的对象被有序排列,可以通过一个整数索引来访问其中的对象,索引的值从0开始。List还重载了add()和addAll()方法,使得程序员可以通过索引值来指定插入对象在List中的位置:
add(int idx,Object obj):将指定对象obj插入到List中指定索引idx的位置,原来位于该位置的对象和其后的对象依次后移;
addAll(int idx,Collection col):将Collection参数col中的所有子对象依次插入到List中指定索引idx的位置,原来位于该位置的对象和其后的对象依次后移。
另外,在List中,还定义了一个方法set(int idx,Object obj),可以用来将指定索引idx的对象替换成obj,并返回被替换的对象。
有几个实现了这个接口的类:AbstractList, ArrayList, LinkedList和 Vector。在实际应用中,比较常用的是ArrayList和Vector。
可以将ArrayList想象成一种可以自动增加容量可以存放不同类型对象的数组(Array),它的使用方式非常简单,只需遵循如下步骤就可以了:
创建ArrayList实例;
调用ArrayList的add()方法将对象存入;
利用ArrayList的get()方法取得相应下标对应的对象,可以使用ArrayList的size()方法取得ArrayList的元素个数。
下面我们来看一个ArrayList的例子。
import java.util.*;
public class ListExample {
public static void main(String[] args) {
List list = new ArrayList();
list.add("one");
list.add("second");
list.add("3rd");
list.add(new Integer(4));
list.add(new Float(5.0F));
list.add("second");
list.add(new Integer(4));
System.out.println(list);
}
}
List是一个有序的可重复集合,所以,在这边有几个重复的元素,也可以向list中加入。
程序运行结果如下:
[one, second, 3rd, 4, 5.0, second, 4]
可以看出,调用ArrayList对象list,它会返回它里面的所有对象。
注意:
在集合中操纵的一定是对象,而不可能是简单类型数据,如,不能将简单类型数据直接放入到ArrayList中,而只能使用它对应的封装类对象。
在Java SE 5中引入了自动装箱/拆箱的概念后,可以直接往容器中加入简单类型数据,但是,实际上并非是容器可以真正存放简单类型数据,而是从简单类型数据转换成相对应的封装类型对象这个动作,已经由自动装箱功能自动帮我们完成了,这点也需要提醒读者注意。
还有一个比较常用的List类是Vector,它和ArrayList非常类似,它们之间最大的区别在于,Vector是线程安全的,而ArrayList不是。
因为这个原因,Vector在执行效率上会比ArrayList低,所以,如果你不用考虑多线程问题,请优先考虑ArrayList,否则,应该使用Vector。
在ArrayList和Vector中,采用的是数组的形式来保存对象的,这种方式将对象放在连续的位置中,它有一个很大的缺点是对它们进行删除或者插入操作的时候非常麻烦,例如,如果我们删除列表中的某个元素,那么,在这个元素之后的其他元素都必须向前挪动,而当往里插入数据的时候,在插入位置后的其他元素都必须往后挪动。(当然,作为Java程序员,我们可以不用考虑它的实现细节,但我们在选择这些列表的时候,我们应该知道它们的特性,并做出合适的选择。)
在JDK中还提供另外一种列表的实现,就是链接列表(LinkedList)。链接列表将每个对象放在独立的空间中,而且,在每个空间中还保存有下一个链接的索引,如果是双向链接列表,那么它还保存有上一个链接的索引,在Java中提供的是双向链接列表。另外,在LinkedList中不支持快速随机访问,如果想要访问LinkedList中的第n个元素,必须从头开始查找,然后跳过前面的n-1个元素。并且,虽然LinkedList提供了一个get()方法,可以根据指定的索引来获取对应的元素,但是,正因为它不支持快速随机访问,所以,它的效率比较低下,例如,我们来看下面的代码:
for(int j = 0;j<myLinkedList.size();j++)
{
System.out.println(myLinkedList.get(j));
}
它的效率是非常低下的,每次循环读取一个元素时,都需要从myLinkedList的第一个元素重新搜索。
根据前面对ArrayList和LinkedList的说明,我们现在大致能够知道如何在在ArrayList和LinkedList之间作出取舍:如果你的列表需要快速的读取,但不经常进行元素的插入和删除操作,那么,应该选择ArrayList会好一些;而如果你需要对列表进行频繁的插入和删除操作,那么,应该选择LinkedList。
3 Iterator
遍历是指从集合中取出每一个元素的过程。
在Collection接口中,有一个iterator()方法,通过这个方法可以返回一个遍历器接口Iterator对象,通过这个对象,可以遍历Collection中的所有元素。在Iterator接口中,定义了一些用于从集合中取得元素的方法:
boolean hasNext()---判断在Iterator中是否还存在元素;
Object next()---使用这个方法从遍历器中取得元素;
remove()---从遍历器中删除集合。
通过Iterator,可以方便的遍历集合中的每一个元素。下面我们来看一个例子:
public class IteratorTest {
public static void main(String[] args) {
Book b1 = new Book("isbn-7-111", "Thinking in Java", "Bruce Eckel");
Book b2 = new Book("isbn-7-5382", "The Moments", "Jimmy");
Book b3 = new Book("isbn-7-5004", "Class", "Paul Fussell");
Book b4 = new Book("isbn-7-5600", "The Scarlet Letter",
"Nathaniel Hawthorne");
Book b5 = new Book("isbn-7-5611", "The Portrait Of a Lady",
"Henry James");
Book b6 = new Book("isbn-7-302-06986-7",
"Programming With J2ME","Alex Wen");
ArrayList al = new ArrayList();
al.add(b1);
al.add(b2);
al.add(b3);
al.add(b4);
al.add(b5);
al.add(b6);
Iterator iterator = al.iterator();
while (iterator.hasNext()) {
System.out.println((Book) iterator.next());
}
}
}
class Book {
private String isbn, title, author;
public Book(String theIsbn, String theTitle, String theAuthor) {
isbn = theIsbn;
title = theTitle;
author = theAuthor;
}
public String getIsbn() {
return isbn;
}
public String getTitle() {
return title;
}
public String getAuthor() {
return author;
}
public String toString() {
return "[isbn=" + isbn + " ,title=" + title + " ,author=" + author
+ "]";
}
}
这里定义了一个类Book用于测试。实例化6个Book对象放入到ArrayList对象al中,我们将在下一节详细论述ArrayList。然后,利用ArrayList的iterator()方法,可以得到一个Iterator对象,通过这个对象的hasNext()方法判断是否已经遍历完Iterator,用Iterator的next()方法取得Iterator中的元素,并将它打印出来。通过这种方式,可以将在集合中的对象全部取出来。在这边需要注意的是,next()方法返回的是Object对象,所以需要将它造型成Book对象。
编译运行,将得到如下的输出结果:
[isbn=isbn-7-111 ,title=Thinking in Java ,author=Bruce Eckel]
[isbn=isbn-7-5382 ,title=The Moments ,author=Jimmy]
[isbn=isbn-7-5004 ,title=Class ,author=Paul Fussell]
[isbn=isbn-7-5600 ,title=The Scarlet Letter ,author=Nathaniel Hawthorne]
[isbn=isbn-7-5611 ,title=The Portrait Of a Lady ,author=Henry James]
[isbn=isbn-7-302-06986-7 ,title=Programming With J2ME ,author=Alex Wen]
注意因为在类Book中覆盖了toString()方法,所以,打印Book对象将会打印出toString()方法中返回的字符串。
和Iterator相似的另一个用于遍历集合的接口是Enumeration(枚举器),这个接口通常用于遍历Vector对象中的元素,通过Vector的elements()方法,可以得到一个Enumeration对象,然后,就和Iterator一样,可以通过它的一些方法来将
Vector中的元素一个个的取出来:
boolean hasMoreElements():和Iterator中的hasNext()方法类似,用于判断集合中是否还有元素未被访问;
Object nextElement():和Iterator中的next()类似,用于取出下一个集合元素。
4 Set
Set接口和List接口不同的地方在于,它是不重复的对象集合。如果试图向Set中加入一个已经在它里面存在的对象,将不会成功。
Set有AbstractSet、 HashSet、 LinkedHashSet、 TreeSet这些子类。比较常用的是HashSet和TreeSet类,它可以从中快速查找指定的对象。
HashSet是一个无序的集,但是它能够快速的查找指定的对象,这是因为它采用了能够适应这个需求的散列码(hash code),我们在此不详细讨论散列码的基本概念,只需要知道,每个对象都有自己的散列码,在Object类中,有一个用于给对象产生散列码的方法hashCode(),它将会给每一个对象产生一个int的数据作为散列码,理想情形下,如果对象不是同一个对象,它们的散列码不会相同。
但是,或许你定义的类中,对于散列码的定义不是这样的,那么你也可以(而且经常也是必须)给自定义的类定义自己的hashCode()方法。而且,正如在前面所说的,对于自己定义的类,通常还需要定义自己的equals()方法。而如果你自己定义的类会用在HashSet、LinkedHashSet或者其他和散列码相关的地方,那么,你必须同时定义自己的hashCode()方法和equals()方法,并且这两个方法必须遵循如下的法则:对于MyObject类的实例x和y,如果x.equals(y),那么x.hashCode()必须和y.hashCode()相等。
从这个角度来看,我们在前面定义的类Citizen是不完整的:它没有覆盖hashCode()方法,下面我们来看如何给它定义自己的hashCode()方法:
public class Citizen {
// 身份证号
String id;
// 其他属性略
public Citizen(String theId) {
id = theId;
}
// 覆盖equals()方法
public boolean equals(Object obj) {
// 首先需要判断o是否为null,
// 如果为null,返回false
if (obj == null) {
return false;
}
// 判断测试的是否为同一个对象,
// 如果是同一个对象,无庸置疑,它应该返回true
if (this == obj) {
return true;
}
// 判断它们的类型是否相等,
// 如果不相等,则肯定返回false
if (this.getClass() != obj.getClass()) {
return false;
}
// 将参数中传入的对象造型为Citizen类型
Citizen c = (Citizen) obj;
// 只需比较两个对象的id属性是否一样,
// 就可以得出这两个对象是否相等
return id.equals(c.id);
}
public int hashCode() {
return id.hashCode();
}
}
因为String类已经覆盖了Object的hashCode()方法,而在这个Citizen类中,id可以作为Citizen对象的唯一标识符,所以,在这个例子中,我们将它的散列码作为Citizen的散列码。
对于hashCode()方法的定义,没有一个统一的规则,在定义它的时候,可以参考Joshua Bloch在《Effective Java》中提出的方法:
将一个非零常数, 保存在 int类型的 result 变量中;
对对象中每一个“主要属性” f (应该是说被方法 equals() 考虑的每一个属性), 进行以下计算:
2.1 对这个属性计算出类型为 int 的 hash 值 c:
2.1.1 如果这个属性是个 boolean, 计算 (f ? 0 : 1);
2.1.2 如果这个属性是个 byte,char,short, 计算 (int)f;
2.1.3 如果这个属性是个 long, 计算 (int)(f ^ (f >>> 32));
2.1.4 如果这个属性是个 float, 计算 Float.floatToIntBits(f);
2.1.5 如果这个属性是个 double, 计算 Double.doubleToLongBits(f), 然后将计算结果按步骤2.1.3 计算;
2.1.6 如果这个属性是个 object reference, 调用该对象的 hashCode(), 如果属性值是 null, 就传回 0;
2.1.7 如果属性是个 array, 请将每个元素视为独立属性, 对每个元素实行上述原则, 再依 2.2 的步骤将这些数值组合起来。
2.2 将步骤 2.1 所计算出来的 hash 码 c 按照下列公式组合到变量 result 中:
result = 37*result + c;
返回result;
完成hashCode()方法定义后,测试相同的实例是否具有相同的hash码,如果不同,寻找原因,修改hashCode()定义。
下面我们来看一个HashSet的例子。
import java.util.*;
public class SetExample {
public static void main(String[] args) {
Set set = new HashSet();
set.add("one");
set.add("second");
set.add("3rd");
set.add(new Integer(4));
set.add(new Float(5.0F));
// 重复元素,将不会被加入
set.add("second");
// 重复元素,将不会被加入
set.add(new Integer(4)); // 1
System.out.println(set);
}
}
HashSet是一个无序无重复的集,所以,如果试图向其中加入已经存在的对象,将不会成功,如在上面的//1中,将返回一个false,表示该对象没有被加入到HashSet中。
程序运行后的结果如下:
[one, 4, 5.0, 3rd, second]
除了HashSet,在Set的实现类中,还有一个比较典型的Set实现,就是TreeSet。TreeSet是一个有序无重复的集。我们可以用任何的顺序向TreeSet中加入对象,但是,当使用iterator()方法进行遍历时,我们可以得到一个有序的结果。例如,我们来看下面的例子:
import java.util.*;
public class SortedTreeSet {
public static void main(String[] args) {
TreeSet ts = new TreeSet();
ts.add("Tom");
ts.add("Jerry");
ts.add("Mickey");
ts.add("Donald");
Iterator iterator = ts.iterator();
while (iterator.hasNext())
System.out.println(iterator.next());
}
}
在这个程序中,我们定义了一个TreeSet,并且向它里面随机放进了四个String对象,然后我们使用遍历器将所有的元素遍历一次,并且将它打印出来,下面是它的运行结果:
Donald
Jerry
Mickey
Tom
可以看出,虽然我们往TreeSet对象插入数据的时候是无序的,但是,我们用遍历器去遍历它的时候,得到的结果是有序的。
上面的例子中,我们往TreeSet中加入了String对象,它会根据String的比较方式排序。但是,如果我们想把我们自己定义的类的对象放到TreeSet中,将会发生什么情况?它怎么对这些元素进行排序呢?例如,我们前面定义的Citizen类,我们没有给它定义任何的排序的算法,如果将它插入到TreeSet集中,将会发生什么情况呢?TreeSet又是如何对它们进行排序呢?
如果我们往TreeSet集中插入相互之间不能进行比较的对象,那么,将会发生ClassCastException异常。所以,在TreeSet中,只能用于保存可以相互进行比较大小的对象。
现在的问题是,如何让自定义的类的对象可以比较?答案是,让你的类实现Comparable接口,并且实现这个接口的唯一的方法compareTo(),它接受一个Object对象,你可以在这个方法中定义对象的排序规则,它应该返回一个整数值,根据这个值的是大于0、小于0还是等于0可以确定两个对象的顺序。String类就是因为实现了这个Comparable接口,才可以对它进行比较。
下面我们还是来看让前面的Citizen类成为“可比较”对象:
public class Citizen implements Comparable {
// 身份证号
private String id;
// 其他属性略
public Citizen(String theId) {
id = theId;
}
// 覆盖equals()方法
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (this == obj) {
return true;
}
if (this.getClass() != obj.getClass()) {
return false;
}
Citizen c = (Citizen) obj;
return id.equals(c.id);
}
// 覆盖hashCode()方法
public int hashCode() {
return id.hashCode();
}
// 覆盖toString()方法
public String toString() {
return id;
}
public String getId() {
return id;
}
// 定义compareTo方法
public int compareTo(Object other) {
Citizen c = (Citizen) other;
return id.compareTo(c.getId());
}
}
我们让这个自定义的Citizen类实现Comparable接口,并且实现了它的compareTo()方法:首先将参数的Object对象造型为Citizen,然后,用对象本身的属性id和参数中的Citizen对象的getId()方法得到的id进行比较,因为它们都是String类型的,所以在此直接调用String类的compareTo()方法来进行比较就可以了,也就是说,两个Citizen的比较是通过它们的String类型的id属性来比较的。
然后我们就可以将这个Citizen对象加入到TreeSet中了。
public class SortedTreeSet {
public static void main(String[] args) {
TreeSet ts = new TreeSet();
Citizen c1 = new Citizen("a10");
Citizen c2 = new Citizen("a02");
Citizen c3 = new Citizen("a99");
ts.add(c1);
ts.add(c2);
ts.add(c3);
Iterator iterator = ts.iterator();
while (iterator.hasNext())
System.out.println(iterator.next());
}
}
运行这个程序将会输出如下的结果:
a02
a10
a99
可以看到,输出的结果是有序的。
提示:
虽然没有规定往TreeSet中插入的元素必须是“同类”的,但是,因为它会对插入其中的对象进行比较,所以,通常,我们往TreeSet中插入的元素是相同类型的对象,或者相互之间有继承关系的类的对象。
发表评论
-
cas4实现sso(一)cas简介
2015-01-15 16:59 971sso(单点登录)在实际的应用开发中经常会用到,特别是软件 ... -
学习编程,实践和理论哪个更重要?
2014-11-24 10:21 1366最近面试了几位还在校 ... -
JMS消息传送模型
2014-07-03 12:12 856jms支持两类消息传送模型:点对点模型(p2p)和发布/订 ... -
为什么使用Java消息服务
2014-03-31 21:36 816Java消息服务有着众多 ... -
SSH+ExtJs完成CKEditor富文本编辑器整合
2013-05-13 11:31 2424最近根据项目需要,在当前项目开发框架中整合入了CKEdi ... -
工作经验与时间无关
2013-03-12 11:20 938工作经验和时间无关! 总是听到这样的说法,我已经工作 ... -
4.判断jbpm流程实例流转完毕
2013-03-11 10:41 2943在使用jbpm4.x进行业务 ... -
3.JBPM与SSH框架整合
2013-02-27 10:13 1008使用Jbpm进行软件开发 ... -
2.Jbpm环境搭建
2012-12-10 15:28 13321.准备工作 首先我 ... -
90.Java日期处理
2012-12-07 09:16 29021 Date类 在编 ... -
89.文件操作初步
2012-12-06 09:19 22351 基本文件操作 ... -
87.String类
2012-12-04 09:24 1670在Java中,使用String和StringBuffer来表示 ... -
1.Jbpm初步了解
2012-12-03 10:40 884因为工作的关系,使用到了Jbpm来进行工作流程的应用开发。开始 ... -
86.Math类的使用
2012-12-03 10:15 1542在实际编程中,大量的数据运算是不可避免的。在Java类库中,已 ... -
85.IO操作入门
2012-11-30 09:25 1464多数应用程序在运行过程中要与用户进行交互,通常的交互方式是:用 ... -
84.系统属性操作
2012-11-27 09:50 1598这里首先要说明的是,Java并不能够直接操作底层操作系统的属 ... -
83.Java编程语法基础说明
2012-11-22 09:17 1663到此为止,有关Java编程基础语法部分的内容就结束了。 ... -
82.处理异常
2012-11-20 09:39 21341.常见异常 下 ... -
81.Java异常概述
2012-11-19 09:40 1446没有人敢保证说它写的程序永远没有错。即使写的程序没有错,也不要 ... -
80.Java修饰符适用范围
2012-11-14 09:50 1634我们学习了不少的修饰符,如用于访问控制的public、prot ...
相关推荐
1.2 什么是 Servlet 容器?...............................................................................................................................13 1.3 例子 .......................................
13 什么是Servlet容器?...............................................................................................................................13 例子...............................................
2.3.3 异常类...........................................67 2.4 方法与技巧................................................67 2.4.1 设置代码模板................................67 2.4.2 设置提示信息.........
Seam - 语境相关的组件[满江红20071230]............................................................................................................................ 1 Java EE 框架...........................
Tong Tec h ® ® ........................................................................................................................... 1 第 1 章 TongWeb6.1 应用服务器概述 ..........................
1. 目录 1. 2. 目录 .........................................................................................................................................................1 JVM ........................
9.3.2 定义自己的插件类..... 225 9.3.3 安装自己的插件..... 226 9.4 使用插件开发环境...... 227 9.4.1 PDE视图和编辑器..... 227 9.4.2 管理运行时环境和开发环境..... 230 9.4.3 创建并运行插件..... 231 ...
在Java Web开发中,Tomcat是应用最广泛的Servlet容器之一,它是Java EE规范的实现,特别是Servlet和JSP规范。Tomcat 8.5.8是该系列的一个重要版本,因为它引入了许多增强功能和性能改进,旨在提升开发人员的体验以及...
9.3.2 定义自己的插件类..... 225 9.3.3 安装自己的插件..... 226 9.4 使用插件开发环境...... 227 9.4.1 PDE视图和编辑器..... 227 9.4.2 管理运行时环境和开发环境..... 230 9.4.3 创建并运行插件...
9.3.2 定义自己的插件类..... 225 9.3.3 安装自己的插件..... 226 9.4 使用插件开发环境...... 227 9.4.1 PDE视图和编辑器..... 227 9.4.2 管理运行时环境和开发环境..... 230 9.4.3 创建并运行插件...
5. 压力容器上的标识:使用单位应将使用登记证固定在压力容器本体上,并在明显位置喷涂使用登记证号,确保设备合规使用并便于监管。 6. 登记证变更的规定:即使压力容器的使用地点发生变化,其注册代码仍然保持不变...
《压力容器安全附件》 压力容器安全附件是保障压力容器安全运行的重要组成部分,它们通过监控、控制和防止超压等方式,确保压力容器的稳定运行,防止因设备故障或操作失误导致的事故。广州市特种承压设备检测研究院...
压力容器根据介质可分为两类:第一组介质容器,涉及极度和高度危害的化学物质、易爆介质和液化气体;第二组介质容器则包括除第一组外的其他介质。 按压力等级,压力容器分为低压、中压、高压和超高压容器。低压容器...
Java作为一款广泛应用的编程语言,其基础知识面试题涵盖了众多方面,包括JDK和JRE的区别、对象的比较、字符串操作、抽象类与接口、容器、多线程、反射以及Java Web相关知识等。下面将详细解释这些知识点: 1. JDK...
标准不适用于直接用火焰加热的容器、核能装置中的容器、旋转或往复运动的机械设备中的受压部件、经常搬运的容器、设计压力低于0.1MPa的容器、真空度低于0.02MPa的容器、内直径小于150mm的容器、需要进行疲劳分析的...
Day91-100\92.Docker容器详解.md Day91-100\93.MySQL性能优化.md Day91-100\94.网络API接口设计.md Day91-100\95.使用Django开发商业项目.md Day91-100\96.软件测试和自动化测试.md Day91-100\97.电商网站技术要点...
##### 88. EPrinter `EPrinter`处理打印机操作中的错误。 ##### 89. EPropertyConvertError `EPropertyConvertError`处理属性类型转换错误。 ##### 90. EPropertyError `EPropertyError`处理属性操作中的错误。 #...
- **二类压力容器**:易燃介质或毒性程度为中度危害介质的低压反应容器和储存容器被归类为二类压力容器。(《容规》第6条) - **无类别容器**:例如某容器最高工作压力为真空度670mmHg,设计压力为0.15MPa,则该容器...