容器类
----通常,程序总是根据运行时才知道的某些条件去创建新的对象。在此之前,不会知道所需对象的数量、确切的类型。当然不能依靠创建命名的引用来持有每个对象。Java有多种方式保存对象(对象的引用),如较为简单直接有效方式数组,但是数组的尺寸大小固定,当时当你写的程序连你都不知道有多少个对象需要你来承接的时候,Java类库中的容器类(自动调节自身尺寸)就能大显身手了!
基本容器类有List、Set、Map。当然也有称其为集合类,Java的类库中使用了Collection这个名词来指代该类的一个特殊子集。当然他们各自有各自的特性。例如,Set对于每个值都只保存一个对象(去重),Map是允许你将对象和对象关联起来存储。在强调容器类会根据对象的数量自动调节自身大小 ------妈妈再也不用担心下标越界了!!
1 基本概念
注意:Java 容器类用途就是保存对象(对象引用)。
- Collection。独立元素的序列,此元素须满足一至多条规则,如List须满足按照插入顺序保存元素,而Set不会有重复元素。Queue按照排队规则来确定对象产生顺序(插入顺序)
- Map。一组key-value对象,使用key来查找value.也即为用键对象查找值对象。对象与对象形成的键-值也称为“关联数组”,就如同字典的单词查找一般。
首先创建个类
public class Gerbil {
private int gerbilNumber;
public void setGerbilNumer(int gerbilNumber) {
this.gerbilNumber=gerbilNumber;
}
public int getGerbilNumber() {
return gerbilNumber;
}
public String hop() {
return "沙鼠步数"+gerbilNumber;
}
}
你可以创建一个List:
当然最好List<Gerbil> gerbilList = new ArrayList<Gerbil>(); 注意这里的ArrayList已经上转型为List。使用接口的目的在于如果你决定去修改你的实现,你只需要在创建处修改即可。
如List<Gerbil> gerbilList = new LinkedList<Gerbil>();
因此,应该创建一个具体类对象,将其转型为对应接口,然后在其余代码中使用该接口。
如代码,foreach选择List中的每一个元素,Collection.addAll()可以接受一个Collection对象实现添加一组元素的效果。
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/*
* @author jack
* 2019/4/11
*/
public class AddingGroups {
/*
* 添加List容器对象(对象的引用)
*/
public List<Gerbil> setGerbilList() {
List<Gerbil> gerbilList = new ArrayList<Gerbil>();
for (int i = 0;i < 5;i ++) {
Gerbil gerbil =new Gerbil();
gerbil.setGerbilNumer(i);
gerbilList.add(gerbil);
}
return gerbilList;
}
public static void main(String[] args) {
AddingGroups addingGroups = new AddingGroups();
ArrayList<Gerbil> gerbilLists = (ArrayList<Gerbil>) addingGroups.setGerbilList();
List<Gerbil> lists = new ArrayList<Gerbil>();
lists.addAll(gerbilLists);
for (Gerbil gerbil : gerbilLists) {
System.out.println("ArrayList"+gerbil.hop());
}
for (Gerbil gerbil : lists) {
System.out.println("List"+gerbil.hop());
}
Iterator<Gerbil> gIterator = lists.iterator();
while (gIterator.hasNext()) {
Gerbil gerbil = (Gerbil) gIterator.next();
System.out.println("Iterator"+":"+gerbil.hop());
}
}
}
输出:
ArrayList沙鼠步数2
ArrayList沙鼠步数3
ArrayList沙鼠步数4
List沙鼠步数0
List沙鼠步数1
List沙鼠步数2
List沙鼠步数3
List沙鼠步数4
2 List
List承诺可以将元素维护在特定的序列中。List在Collection的基础上添加了大量的方法,使其可以在List中插入和移除元素
两类List:
- 基本的ArrayList,擅长随机访问元素,但是在List中间插入、删除比较慢
- LinkList,擅长中间插入、删除。但是随机访问比较慢,但是LinkList的特性集比ArrayList大(https://www.cnblogs.com/lintong/p/4374292.html)作为参考了解
简单解释:如getFirst()、element()完全一样,都是返回list的第一个元素(返回而非移除),如果List为空则抛出NoSouchElementException。peek()与上两方法稍有差异,当List为空则返回NULL。removeFirst()、remove()和poll()与上诉方法差异一致。
3 Set
Set不保存重复的元素。Set具有Collection完全一样的接口,故没有什么额外的功能,不像前面的List(当然这也是继承和多态的典型应用:表现不同的行为)
4 Map
将对象映射到其他对象的能力是解决编程问题的利剑。
- Map提供了一种映射关系,其中的元素是以键值对(key-value)的形式存储的,能够实现根据key快速查找value;
- Map中的键值对以Entry类型的对象实例形式存在;
- 键(key值)不可重复,value值可以重复,一个value值可以和很多key值形成对应关系,每个建最多只能映射到一个值。
- Map支持泛型,形式如:Map<K,V>
- Map中使用put(K key,V value)方法添加
如下代码测试random类的随机性
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
public class MapStatistic {
public static void main(String[] args) {
Random random = new Random(49);
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
for (int i = 0 ; i < 100; i++) {
int r = random.nextInt(20);
Integer freq = map.get(r);
map.put(r, freq == null ? 1 : freq + 1);
}
System.out.println(map);
}
}
如果Key 值不在容器中get()将返回NULL,get()返回对应的Value(Integer引用)最终得到一下结果:
{0=6, 1=5, 2=4, 3=5, 4=7, 5=3, 6=6, 7=4, 8=7, 9=6, 10=7, 11=7, 12=3, 13=4, 14=3, 15=4, 16=3, 17=8, 18=6, 19=2}
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import practise.Gerbil;
/*
* @author jack
* 学习验证对象类特性 */
public class ListPractise {
/*
* 添加List容器对象(对象的引用)
*/
public List<Gerbil> setGerbilList() {
List<Gerbil> gerbilList = new ArrayList<Gerbil>();
for (int i = 0;i < 5;i ++) {
Gerbil gerbil =new Gerbil();
gerbil.setGerbilNumer(i);
gerbilList.add(gerbil);
}
return gerbilList;
}
/*
* 添加set容器对象
*/
public Set<Gerbil> setGerbilSet() {
Set<Gerbil> gerbilSet = new HashSet<Gerbil>();
for (int i = 0; i < 5 ; i ++) {
Gerbil gerbil = new Gerbil();
gerbil.setGerbilNumer(i);
gerbilSet.add(gerbil);
}
return gerbilSet;
}
/*
* 添加Map容器对象
*/
public Map<String, Gerbil> setGerbilMap(){
Map<String, Gerbil> gerbilMap = new HashMap<String, Gerbil>();
for(int i = 0; i < 5 ; i ++) {
Gerbil gerbil = new Gerbil();
gerbil.setGerbilNumer(i);
gerbilMap.put("第"+i, gerbil);
}
return gerbilMap;
}
public static void main(String[] args) {
ListPractise lPractise = new ListPractise();
ArrayList<Gerbil> gerbilLists = (ArrayList<Gerbil>) lPractise.setGerbilList();
Set<Gerbil> gerbilSet = lPractise.setGerbilSet();
Iterator<Gerbil> gIterator = gerbilLists.iterator();
while (gIterator.hasNext()) {
Gerbil gerbil = (Gerbil) gIterator.next();
System.out.println("Iterator"+":"+gerbil.hop());
}
for (Gerbil gerbil : gerbilLists) {
System.out.println("List"+gerbil.hop());
}
for (Gerbil gerbil : gerbilSet) {
System.out.println("Set"+gerbil.hop());
}
}
}
总结:
- 数组将数字与对象联系起来。保存类型明确的对象,查询对象是不需要对对象结果做类型转换。当然可以保存基本类型的数据。数组是一旦生成容量不可改变!
- Coullection 保存单一元素,而Map保存键值对。在Java泛型的基础上可以指定存放得数据类型,如此也避免了错误类型对象放入容器中。且在获取对象时不必做类型转换。容器则不能持有基本的数据类型,优势则是在再添加更多元素的时候自动调节元素尺寸。
- List 可以像素组一样建立数字索引与对象的关联,故数组和List都是排好顺序的容器
- 如果大量随机访问则使用ArrayList,若是常从中间插入或删除元素则用LinkedList。
- LinkedList可以实现Queue以及栈的行为。
- Set不接受重复的元素。HashSet提供较快的查询速度,TreeSet保持元素的排序状态,LinkedHashSet已插入顺序保持元素。
- Map 是将对象和对象进行关联的设计。HashMap设计用来快速访问;而TreeMap保持Key始终排序状态,所以没有HashMap快,LinkedHashMap保持元素插入的顺序,且通过散列提供了快速访问的能力。
- 新程序不易使用Vector、HashTable、Stack