Java高级特性----->>>>集合

集合框架简述
在 JDK API 中专门设计了一组类,这组类的功能就是实现各种各样方
式的数据存储,这样一组专门用来存储其它对象的类,一般被称为对象容器类,
简称容器类,这组类和接口的设计结构也被统称为集合框架(Collection
Framework)。
这组类和接口都包含在 java.util 包中。
为了使整个集合框架中的类便于使用,在设计集合框架时大量的使用
接口,实际实现的功能类实现对应的接口,这样可以保证各个集合类的使用方式
保持统一。
在集合框架中,提供的存储方式共有两种:
1、按照索引值操作数据
在这种存储方式中,为每个存储的数据设定一个索引值,存储在容器中的第一个
元素索引值是 0,第二个索引值是 1,依次类推。在操作数据时按照索引值操作
对应的数据,实现这种方式的集合类都实现 java.util.Collection 接口。
2、按照名称操作数据
在这种存储方式中,为每个存储的数据设定一个名称(任意非 null 的对象都可以
作为名称),以后按照该名称操作该数据,要求名称不能重复,每个名称对应唯
一的一个值。这种存储数据的方式也称作名称-数值对,也就是名值对存储。实
现这种方式的几个类都实现 java.util.Map 接口。
这里“按照索引值操作数据”的存储方式,又按照容器内部是否能够存储
重复的元素,划分成两类:
1、允许存储重复元素。
这种存储方式中,所有的类都实现了 java.util.List 接口。
2、不允许存储重复元素。
这种存储方式中,所有的类都实现了 java.util.Set 接口。
这样,集合框架中的类就分成了三大类:
1List 系列
该系列中的类按照索引值来操作数据,允许存放重复的元素。
2Set 系列
该系列中的类按照索引值来操作数据,不允许存放重复的元素。
3Map 系列
该系列中的类按照名称来操作数据,名称不允许重复,值可以重复,一个名称对
应一个唯一的值。
而在数据结构中,实现数据的存储又可以使用不同的数据结构类型进
行存储,例如数组、链表、栈、队列和树等,则以上三类集合框架可以使用不同
的数据结构类进行实现,使用每种数据结构则具备该中数据结构的特点。例如使
用数组则访问速度快,使用链表则便于动态插入和删除等,这样就造成了集合框
架的复杂性。
另外,在将对象存储到集合类中,为了加快存储的速度,要求被存储
对象的类中必须覆盖 equals 方法和 hashCode 方法。
对于这些集合类,下面按照以上三个系列的顺序一一进行说明。
List 系列
List 系列的类均实现 List 接口,大部分的类都以 List 作为类名的后
缀,也有部分该体系中的类命名比较特殊。
该系列中的类,比较常见的有 ArrayList 和 LinkedList 两个。其中
ArrayList 是以数组为基础实现的 List,而 LinkedList 则是以链表为基础实现
的 List,ArrayList 拥有数组的优点,而 LinkedList 拥有链表的优点。
由于该体系中的类均实现 List 接口,所以在这些类的内部,相同的功
能方法声明是保持一致的,下面进行一一介绍:
aadd 方法
boolean add(Object o)
该方法的作用是追加对象 o 到已有容器的末尾。
另外一个 add 方法:
void add(int index, Object element)
该方法的作用是将对象 element 插入到容器中索引值为 index 的位置,原来位于
该位置的对象以及后续的内容将依次向后移动。
baddAll 方法
boolean addAll(Collection c)
该方法的作用是将容器对象 c 中的每个元素依次添加到当前容器的末尾。
另外一个 addAll 方法:
boolean addAll(int index, Collection c)
该方法的作用是将容器对象 c 中的第一个元素插入到当前容器中索引值为 index
的位置,第二个元素插入到当前容器中索引值为 index+1 的位置,依次类推。而
当前容器中原来位于 index 以及 index 索引值以后的元素则依次向后移动。
cget 方法
Object get(int index)
该方法的作用是返回当前容器对象中索引值为 index 的元素的内容。
dindexOf 方法
int indexOf(Object o)
该方法的作用是查找当前容器中是否存在对象 o,如果存在则返回该对象第一次
出现位置的索引值,如果不存在则返回-1。
另外一个方法 lastIndexOf 则是从末尾向前查找,返回从末尾向前第一次出现位
置的索引值,如果不存在则返回-1。
eremove 方法
Object remove(int index)
该方法的作用是删除索引值为 index 的对象的内容,如果删除成功则返回被删除
对象的内容。
另外一个 remove 方法:
boolean remove(Object o)
该方法的作用是删除对象内容为 o 的元素,如果相同的对象有多个,则只删除索
引值小的对象。如果删除成功则返回 true,否则返回 false。
无论使用哪一个 remove 方法,类内部都自动移动将被删除位置后续的所有元素
向前移动,保证索引值的连续性。
fset 方法
Object set(int index, Object element)
该方法的作用是修改索引值为 index 的内容,将原来的内容修改成对象 element
的内容。
gsize 方法
int size()
该方法的作用是返回当前容器中已经存储的有效元素的个数。
htoArray 方法
Object[] toArray()
该方法的作用是将当前容器中的元素按照顺序转换成一个 Object 数组。
下面是一个简单的以 ArrayList类为基础实现的 List系列中类基本使用的示
例,代码如下:

import java.util.*;
/**
* 以 ArrayList 类为基础演示 List 系列类的基本使用
*/
public class ArrayListUse {
public static void main(String[] args) {
//容器对象的初始化
List list = new ArrayList();
//添加数据
list.add("1");
list.add("2");
list.add("3");
list.add("1");
list.add("1");
//插入数据
list.add(1,"12");
//修改数据
list.set(2, "a");
//删除数据
list.remove("1");
//遍历
int size = list.size(); //获得有效个数
//循环有效索引值
for(int i = 0;i < size;i++){
System.out.println((String)list.get(i));
}
}
}


该程序的运行结果为:
12
a 3 1 1
在 List 系列中,还包含了 Stack(栈)类和 Vector(向量)类,Stack 类除了实
现 List 系列的功能以外,还实现了栈的结构,主要实现了出栈的 pop 方法和入
栈的 push 方法。
而 Vector 类由于需要兼容老版本 JDK 中缘故,所以在实现的方法中需要提
供老版本 Vector 类中对应的方法,这样导致 Vector 类中相同或类似的功能方法
一般是成对出现的。
Set 系列
Set 系列中的类都实现了 Set 接口,该系列中的类均以 Set 作为类名
的后缀。该系列中的容器类,不允许存储重复的元素。也就是当容器中已经存储
一个相同的元素时,无法实现添加一个完全相同的元素,也无法将已有的元素修
改成和其它元素相同。
Set 系列中类的这些特点,使得在某些特殊场合的使用比较适合。
该系列中常见的类有:
1CopyOnWriteArraySet
以数组为基础实现的 Set 类。
2HashSet
以哈希表为基础实现的 Set 类。
3LinkedHashSet
以链表为基础实现的 Set 类。
4TreeSet
以树为基础实现的 Set 类。
以不同的数据结构类型实现的 Set 类,拥有不同数据结构带来的特性,在实
际使用时,根据逻辑的需要选择合适的 Set 类进行使用。
Set 系列中的类的方法和 List 系列中的类的方法要比 List 系列中少很多,
例如不支持插入和修改,而且对于 Set 系列中元素的遍历也需要转换为专门的
Iterator(迭代器)对象才可以进行遍历,遍历时顺序和 Set 中存储的顺序会有所
不同。
下面是以 HashSet 类为基础实现的示例代码,代码如下:

import java.util.*;
/**
* 以 HashSet 为基础演示 Set 系列类的基本使用
*/
public class HashSetUse {
public static void main(String[] args) {
//容器对象的初始化
Set set = new HashSet();
//添加元素
set.add("1");
set.add("2");
set.add("3");
set.add("1");
set.add("1");
//删除数据
//set.remove("1");
//遍历
Iterator iterator = set.iterator();
while(iterator.hasNext()){
System.out.println((String)iterator.next());
}
}
}


该程序的运行结果为:
3 2 1
Map 系列
Map 系列中的类都实现了 Map 接口,该系列中的部分类以 Map 作为类
名的后缀。该系列容器类存储元素的方式和以上两种完全不同。
Map 提供了一种使用“名称:值”这样的名称和数值对存储数据的方
法,在该存储方式中,名称不可以重复,而不同的名称中可以存储相同的数值。
具体这种存储的格式将在示例代码中进行实现。
在这种存储结构中,任何不为 null 的对象都可以作为一个名称(key)
来作为存储的值(value)的标识,使用这种形式更利于存储比较零散的数据,也
方便数据的查找和获得。Map 类中存储的数据没有索引值,系统会以一定的形式
索引存储的名称,从而提高读取数据时的速度。
该系列中常见的类有:
1HashMap
Hash(哈希表)为基础实现的 Map 类。
2LinkedHashMap
以链表和 Hash(哈希表)为基础实现的 Map 类。
3TreeMap
以树为基础实现的 Map 类。
和上面的结构类似,以不同的数据结构实现的 Map 类,拥有不同数据
结构的特点,在实际的项目中使用时,根据需要选择合适的即可。
该系列的类中常见的方法如下:
aget 方法
Object get(Object key)
该方法的作用是获得当前容器中名称为 key 的结构对应的值。
bkeySet 方法
Set keySet()
该方法的作用是返回当前容器中所有的名称,将所有的名称以 Set 的形式返回。
使用这个方法可以实现对于 Map 中所有元素的遍历。
cput 方法
Object put(Object key, Object value)
该方法的作用是将值 value 以名称 key 的形式存储到容器中。
dputAll 方法
void putAll(Map t)
该方法的作用是将 Map 对象 t 中的所有数据按照原来的格式存储到当前容器类
中,相当于合并两个 Map 容器对象。
eremove 方法
Object remove(Object key)
该方法的作用是删除容器中名称为 key 的值。
fsize 方法
int size()
该方法的作用是返回当前日期中存储的名称:值数据的组数。
gvalues 方法
Collection values()
该方法的作用是返回当前容器所有的值组成的集合,以 Collection 对象的形式
返回。
下面是一个简单的示例,在该示例中演示 Map 系列类的基本使用,代
码如下:

import java.util.*;
/**
* 以 HashMap 为基础演示 Map 系列中类的使用
*/
public class HashMapUse {
public static void main(String[] args) {
//容器对象的初始化
Map map = new HashMap();
//存储数据
map.put("苹果", "2.5");
map.put("桔子", "2.5");
map.put("香蕉", "3");
map.put("菠萝", "2");
//删除元素
map.remove("桔子");
//修改元素的值
map.put("菠萝", "5");
//获得元素个数
int size = map.size();
System.out.println("个数是:" + size);
//遍历 Map
Set set = map.keySet();
Iterator iterator = set.iterator();
while(iterator.hasNext()){
//获得名称
String name = (String)iterator.next();
//获得数值
String value = (String)map.get(name);
//显示到控制台
System.out.println(name + ":" + value);
}
}
}


该程序的运行结果为:
个数是:3
香蕉:3
菠萝:5
苹果:2.5
使用示例
如前所述,集合框架中的类只是提供了一种数据存储的方式,在实际
使用时,可以根据逻辑的需要选择合适的集合类进行使用。
下面以一个字符串计算的示例演示集合类的实际使用。
该程序的功能为计算一个数字字符串,例如”1+2*31-5”、”12
*30/34-450”等,的计算结果,在该示例中支持四则运算,但是不支持括号。本
示例中计算的字符串要求合法。
该程序实现的原理是:首先按照运算符作为间隔,将字符串差分为数
字字符串和运算符字符串的序列,由于分拆出的字符串数量不固定,所以存储到
List 系列的 Vector 容器中,然后按照运算符的优先级进行计算。
该程序的代码如下:

import java.util.*;
/**
* 计算字符串的值
*/
public class CalcStr {
public static void main(String[] args) {
String s = "1+20*3/5";
double d = calc(s);
System.out.println(d);
}
/**
* 计算字符串的值
* @param s 需要计算的字符串
* @return 计算结果
*/
public static double calc(String s){
//拆分字符串
Vector v = split(s);
//print(v); //测试代码
//计算字符串
double d = calcVector(v);
return d;
}
/**
* 将字符串拆分为数字和运算符。
* 例如:"1+23*4"则拆分为:"1"、"+"、"23"、"*"和"4"
* @param s 需要拆分的字符串
* @return 拆分以后的结果
*/
private static Vector split(String s){
Vector v = new Vector();
String content = "";
int len = s.length(); //字符串长度
char c;
for(int i = 0;i < len;i++){
c = s.charAt(i);
//判断是否为运算符
if(c == '+' ||
c == '-' ||
c == '*' ||
c == '/'){
//存储数字
v.add(content);
//存储运算符
v.add("" + c);
//清除已有字符串
content = "";
}else{
content += c; //连接字符串
}
}
v.add(content); //添加最后一个数字
return v;
}
/**
* 测试代码,输出拆分以后的结果
* @param v 需要打印的 Vector 对象
*/
private static void print(Vector v){
int size = v.size();
for(int i = 0;i < size;i++){
System.out.println((String)v.get(i));
}
}
/**
* 计算 Vector 中的数据
* @param v 存储拆分后字符串的 Vector
* @return 计算结果
*/
private static double calcVector(Vector v){
int index1;
int index2;
//计算乘除
while(true){
index1 = v.indexOf("*"); //乘号索引值
index2 = v.indexOf("/"); //除号索引值
//无乘除符号
if(index1 == - 1 && index2 == -1){
break; //结束循环
}
//如果有乘号
if(index1 != -1){
//没有除号或乘号在前
if(index2 == -1 || index1 < index2){
String s1 =
(String)v.get(index1 - 1); //第一个数字
String opr =
(String)v.get(index1); //运算符
String s2 =
(String)v.get(index1 + 1); //第二个数字
//计算
String answer =
calc(s1,s2,opr);
//计算以后的处理
handle(answer,index1 -
1,v);
}
}
//有除号
if(index2 != -1){
//没有乘号或除号在前
if(index1 == -1 || index2 <
index1){
String s1 =
(String)v.get(index2 - 1); //第一个数字
String opr =
(String)v.get(index2); //运算符
String s2 =
(String)v.get(index2 + 1); //第二个数字
//计算
String answer =
calc(s1,s2,opr);
//计算以后的处理
handle(answer,index2 -
1,v);
}
}
}
//计算加
int index3 = v.indexOf("+");
while(index3 != -1){ //有加号
String s1 = (String)v.get(index3 - 1); //
第一个数字
String opr = (String)v.get(index3); //运
算符
String s2 = (String)v.get(index3 + 1); //
第二个数字
//计算
String answer = calc(s1,s2,opr);
//计算以后的处理
handle(answer,index3 - 1,v);
//获得下一个加号的位置
index3 = v.indexOf("+");
}
//计算减
index3 = v.indexOf("-");
while(index3 != -1){ //有加号
String s1 = (String)v.get(index3 - 1); //
第一个数字
String opr = (String)v.get(index3); //运算
符
String s2 = (String)v.get(index3 + 1); //
第二个数字
//计算
String answer = calc(s1,s2,opr);
//计算以后的处理
handle(answer,index3 - 1,v);
//获得下一个减号的位置
index3 = v.indexOf("-");
}
//反馈结果
String data = (String)v.get(0);
return Double.parseDouble(data);
}
/**
* 计算两个字符串类型的值运算结果
* @param number1 数字 1
* @param number2 数字 2
* @param opr 运算符
* @return 运算结果
*/
private static String calc(String number1,String
number2,String opr){
//将字符串转换为数字
double d1 = Double.parseDouble(number1);
double d2 = Double.parseDouble(number2);
//判断运算符
if(opr.equals("+")){
return "" + (d1 + d2);
}
if(opr.equals("-")){
return "" + (d1 - d2);
}
if(opr.equals("*")){
return "" + (d1 * d2);
}
if(opr.equals("/")){
return "" + (d1 / d2);
}
return "0"; //运算符错误时返回 0
}
/**
* 计算以后的处理
* @param answer 计算结果
* @param index 参与计算的三个字符串中第一个字符串的起始位置
* @param v 存储字符串的容器
*/
private static void handle(String answer,int index,Vector v){
//删除计算过的字符串
for(int i = 0;i < 3;i++){
v.remove(index);
}
//将计算结果插入到 index 位置
v.insertElementAt(answer, index);
}
}


该程序的运行结果为:
13.0

原文地址:https://www.cnblogs.com/bocai2010000/p/6832747.html