触类旁通,我懂得Java数据集合类型是在学习Python的组合数据类型的时候突然顿悟,有时候你想了很长时间的问题,目前所有的条件给不了你答案,但是只要你砥砺前行,总会在某地某事某一刻恍然大悟,说出“哦,原来是这个样子,自己太愚钝了^-^”,下面是我个人的对Java的集合的一个总结,前提声明我只用了集合中一部分的方法,还有很多方法大家可以通过JavaIPA找一下。
开始卷吧:我们知道数组可以保存一定长度的数据,但是这个长度是不可变得,例如:int[20],定义一个长度为20的数组,这个数组给了20个位置让我们存放数字;但是有时如果我们想存储的是一些数目不确定的对象,怕太浪费资源,又怕存放的空间不够,在你左右为难的时候,JDK 中提供了一系列的特殊的类,这些类可以存储任意类型的对象,并且长度可以变,在Java中这些类统称为:集合。(在学习这一节的时候一定要先掌握数据《数据结构》中的存储结构的一些概念)
Java的集合类都位于java.util包中,在使用的时候一定要注意导包的问题,否则可能会报错。
集合按存储结构分为两大类:单列集合Collection,双列集合Map
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?1.1 Colletction
1.2 Map
(单列集合)Collection
List接口
ArrayList集合
ArrayList集合内部封装了一个长度可变得数组对象,当存入的元素超过数组长度的时候,ArrayList会在内存中分配一个更大的数组来存储这些元素,因此可以把ArrayList 看做是一个长度可变得数组。
package collectionmethod;
import java.util.*;
public class ArrayListmethod {
public static void main(String[] args) {
ArrayList arraylist = new ArrayList();
arraylist.add("stu1");
arraylist.add("stu2");
arraylist.add("stu3");
System.out.println("集合的长度:"+arraylist.size());
System.out.println("第二个元素是多少:"+arraylist.get(1));
}
}
注意:上诉代码中我只在集合中添加(add)了三个元素,当你要获取(get)集合中元素的时候,索引的取值只能从0开始,最后一个索引是size-1,也就是说只能get(0),get(1),get(2),当出现get(3)的时候,索引超出此范围,抛出角标异常IndexOutOfBoundsException。(这个时候可以抛出异常)
package collectionmethod;
import java.util.*;
public class ArrayListmethod {
public static void main(String[] args) {
ArrayList arraylist = new ArrayList();
arraylist.add("stu1");
arraylist.add("stu2");
arraylist.add("stu3");
System.out.println("集合的长度:"+arraylist.size());
System.out.println("第二个元素是多少:"+arraylist.get(6)); //索引下标为7的数
}
}
?报错:
集合的长度:3
Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 6, Size: 3
at java.util.ArrayList.rangeCheck(Unknown Source)
at java.util.ArrayList.get(Unknown Source)
at collectionmethod.ArrayListmethod.main(ArrayListmethod.java:11)
抛出异常:
package collectionmethod;
import java.util.*;
public class ArrayListmethod {
public static void main(String[] args) {
/**
* 抛出异常
*/
try {
ArrayList arraylist = new ArrayList();
arraylist.add("stu1");
arraylist.add("stu2");
arraylist.add("stu3");
System.out.println("集合的长度:"+arraylist.size());
System.out.println("第二个元素是多少:"+arraylist.get(6));
}
catch(Exception e)
{
System.out.println("捕获信息异常:"+e.getMessage());
}
}
}
异常处理:
集合的长度:3
捕获信息异常:Index: 5, Size: 3
LinkedList集合
我们知道ArrayList在查询的时候很快,但是在增删的时候效率就很低了,在这个前提下List的另一个实现类LinkedList诞生了。LinkedList内部维护着一个双向循环链表(《数据结构》),这个概念大家自己去看,自己动手,丰衣足食。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? LinkedList中定义的方法
方法声明 | 功能描述 | void add(int index,E element) | 在此列表中指定的位置插入指定的元素 | void addFirst(Object o) | 将指定元素插入此列表的开头 | void addLast(Object o) | 将指定元素添加到此列表的尾部 | void getFirst() | 返回此列表的第一个元素 | void getLast() | 返回此列表的最后一个元素 | Object removeFirst() | 移除并返回此列表的第一个元素 | Object removeLast() | 移除并返回此列表的最后一个元素 |
LinkedList linkedlist = new LinkedList();
linkedlist.add("stu1");
linkedlist.add("stu2");
linkedlist.add("stu3");
linkedlist.add("stu4");
System.out.println(linkedlist.toString());//<>.toString,取出并打印集合的元素
linkedlist.add(3,"wailaiBug");
linkedlist.addFirst("FirstBug");
linkedlist.addLast("LastBug");
System.out.println(linkedlist);
System.out.println(linkedlist.getFirst());
System.out.println(linkedlist.getLast());
linkedlist.remove(3);
linkedlist.removeFirst();
System.out.print(linkedlist);
Console:
[stu1, stu2, stu3, stu4]
[FirstBug, stu1, stu2, stu3, wailaiBug, stu4, LastBug]
FirstBug
LastBug
[stu1, stu2, wailaiBug, stu4, LastBug]
那么简单的List学习以后呢,我们先不说Set,先为大家普及一下在使用集合时一些实用的接口和方法Iterator和JDK5.0的foreach循环,那么下面的单列集合Collection的Set 和双列集合Map都会用到哟。(稳住气别心急,加油!)(像极了节目中突然插得两条广告^-^)
Iterator接口(迭代器)
迭代器,迭代器,通俗易懂的来讲就是用来遍历集合中的所有元素的工具。Iterator接口也是Java集合中的一员(想象它的作用就像煲汤时候用的汤勺,把锅里的食材都搅合一遍),和Collection,Map的元素存储功能不同,Iterator接口主要用于迭代访问(遍历)Collection中的元素。
package collectionmethod;
import java.util.*;
public class ArrayListmethod {
public static void main(String[] args) {
ArrayList arraylist = new ArrayList();
arraylist.add("stu1");
arraylist.add("stu2");
arraylist.add("stu3");
System.out.println("集合的长度:"+arraylist.size());
Iterator iterator = arraylist.iterator(); //获取Iterator的对象
while(iterator.hasNext())//判断ArrayList中是否存在下一个元素
{
Object obj = iterator.next();//取出ArrayList集合中的元素
System.out.println(obj);
}
}
}
Console:
集合的长度:3
stu1
stu2
stu3
那么我们与直接输出arraylist作比较
//比较直接输出arraylist
System.out.println(arraylist);
Console:
[stu1, stu2, stu3]
比较后发现迭代器是一个一个输出的,而直接输出的是一列表。
在迭代器中存在连个方法,第一个是<>.hasNext()方法:判断集合中是否存在下一个元素,如果存在那么用<>.next()方法将元素取出来;否则说明已到达集合末尾,停止遍历。Iterator迭代器在遍历集合时,内部采用指针的方式来跟踪集合中的元素。
特别说明:当通过迭代器获取ArrayList集合中的元素时,都会将这些元素当作Object类型看待,如果想到得到特殊的元素类型,这需要进行强制类型转换。
注意one:<>.next()方法获取元素必须确保获取的元素存在,否则抛出NoSuchElementException异常
1.3 Iterator迭代过程
?注意two:Itetator迭代器中单独使用<>.remove()方法会导致迭代器预期的迭代次数发生变化,导致迭代器的结果不准确,代码如下:
package collectionmethod;
import java.util.*;
public class ArrayListmethod {
public static void main(String[] args) {
ArrayList arraylist = new ArrayList();
arraylist.add("stu1");
arraylist.add("stu2");
arraylist.add("wailaiBug");
System.out.println("集合的长度:"+arraylist.size());
Iterator iterator = arraylist.iterator(); //获取Iterator的对象
/**
* Iterator
*/
while(iterator.hasNext())//判断ArrayList中是否存在下一个元素
{
Object obj = iterator.next();//取出ArrayList集合中的元素
if("wailaiBug".equals(obj))
{
arraylist.remove(obj);
}
}
System.out.println(arraylist);
}
}
?Console:迭代器抛出异常ConcurrentModificationException
集合的长度:3
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
at java.util.ArrayList$Itr.next(Unknown Source)
at collectionmethod.ArrayListmethod.main(ArrayListmethod.java:98)
?那么问题来了,我就是想用,你到底给不给>_<(嘤嘤嘤),其实吧,也不是不可能,只不过需要<>.remove配合一些操作,以下代码是两种骚操作。
?第一种代码:在删除下面加个break;
if("wailaiBug".equals(obj))
{
arraylist.remove(obj);
break; //加个break
}
Console:?
集合的长度:3
[stu1, stu2]
?
第二种代码: 使用迭代器本身的删除方法
if("wailaiBug".equals(obj))
{
iterator.remove();//迭代器本身自带的
}
Console:
集合的长度:3
[stu1, stu2]
?嘤嘤嘤,解决了!!!
?foreach循环(JDK5.0的新特性)
foreach循环诞生是觉得Iterator迭代器遍历集合太繁琐(人们总是想着怎么简单怎么来),foreach循环呢,说白了,就是一个加强版的for循环,而且相比于for更加简洁,它用来遍历数组或集合中的元素。具体的语法格式如下:
for(容器中元素的类型 ?临时变量 : 容器变量) { ?? ? ? ? ? ? ? ? ? ? 执行语句; ?}
package collectionmethod;
import java.util.*;
public class ArrayListmethod {
public static void main(String[] args) {
ArrayList arraylist = new ArrayList();
arraylist.add("stu1");
arraylist.add("stu2");
arraylist.add("stu3");
System.out.println("集合的长度:"+arraylist.size());
for(Object obj : arraylist)//foreach循环
{
System.out.println(obj);
}
}
}
Console:
集合的长度:3
stu1
stu2
stu3
与for相比,foreach循环不需要获得容器的长度,,也不需要根据索引访问容器中的元素,但它会自动遍历容器中的每一个元素。
注意:当使用foreach循环遍历集合和数组时,只能访问集合总的元素,不能对其中的元素进行修改,如下代码,我是通过String数组为例写的
package collectionmethod;
import java.util.*;
public class ArrayListmethod {
static String[] strs = {"aaa","bbb","ccc"};
public static void main(String[] args) {
for(String str : strs)
{
str = "wailaiBug";
}
System.out.println("foreach循环修改后的数组:" + strs[0] +","+ strs[1] +","+ strs[2] );
//for
for(int i = 0; i < strs.length ; i++)
{
strs[i] = "wailaiBug";
}
System.out.println("for循环修改后的数组:" + strs[0] +","+ strs[1] +","+ strs[2] );
}
}
Console:
foreach循环修改后的数组:aaa,bbb,ccc
for循环修改后的数组:wailaiBug,wailaiBug,wailaiBug
Set接口
Set接口和Collection接口的方法基本上一致,没有对Collection接口的功能进行扩充,只是比Collection接口更加严格。Set接口区别于List接口的是,Set接口中元素无序,并且都会以某种规则保证存入的元素不出现重复。
Set接口有两个实现类一个是HashSet,另一个是TreeSet
HashSet集合
HashSet是Set接口的实现类, HashSet根据对象的哈希值来确定元素在集合中的存储位置,因此具有良好的存取和查找性能。
当向HashSet集合中添加一个对象时,首先会调用该对象的hashCode()方法来计算对象的哈希值,来确定对象的存储位置,如果此时哈希值相同,在调用对象的equals()方法来确保该位置没有重复元素。
package collectionmethod;
import java.util.HashSet;
import java.util.Iterator;
public class SetMethod {
public static void main(String[] args) {
HashSet hashset = new HashSet();
hashset.add("wailaiBug");
hashset.add("gebidashu");
hashset.add("xiaoxuzi");
hashset.add("wailaiBug");
Iterator it = hashset.iterator();
while(it.hasNext())
{
Object obj = it.next();
System.out.println(obj);
}
}
}
Console:
gebidashu
wailaiBug
xiaoxuzi
可以看出,去除的元素顺序与添加元素的顺序不一致,并且重复存入的元素(wailaiBug)被去除了,只添加了一个。
我们来看一下HashSet的整个存储流程图:
1.4 HashSet的存储过程
?当向集合存入元素时,为了保证HashSet正常工作,要求在存入对象时,重写HashCode()和equals()方法,那么问题来了,为什么String类不需要重写呢,这是因为在我们之前学String类的时候人家内部已经重写过了,所以不需要咱们重写。
package collectionmethod;
import java.util.HashSet;
import java.util.Iterator;
class Student{
private String id;
private String name;
public Student(String id,String name) {
this.id = id;
this.name = name;
}
/**
* 重写toString方法
*/
public String toString() {
return id+":"+name;
}
/**
* 重写hashCode
*/
public int hashCode() {
return id.hashCode();//返回id属性的哈希值
}
/**
* 重写equals()方法
*/
public boolean equals(Object obj) {
if(this == obj)//判断是否是同一个对象
{
return true;//如果是的话,返回一个true
}
if(!(obj instanceof Student))//判断对象是否为Student类型
{
return false;//如果对象不是Student类型,返回fasle
}
Student stu = (Student) obj;
boolean b = this.id.equals(stu.id);//判断id是否相同
return b;//返回判断结果
}
}
public class SetMethod {
public static void main(String[] args) {
HashSet hashset = new HashSet();
Student stu1 =new Student("1","mihoutao");
Student stu2 =new Student("2","wailaiBug");
Student stu3 =new Student("2","wailaiBug");
hashset.add(stu1);
hashset.add(stu2);
hashset.add(stu3);
System.out.println(hashset);
}
}
?Console:
[1:mihoutao, 2:wailaiBug]
(双列集合)Map
?研究一对一的关系(扩展:《数据库》研究一对一,一对多,多对多关系)
Map接口是一种双列集合,它的每个元素都包含一个键对象Key,值对象Value。键值对之间存在的一种对应关系,叫做映射。从Map集合中访问元素时,只要指定了Key,就能找到对应的Value。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Map集合的常见方法表
方法声明 | 功能描述 | void put(Object key,Object value ) | 将指定的值与此映射中的指定键关联(可选操作) | Object get(Object key) | 返回指定键所映射的值;如果此映射不包括改建的映射干洗,则返回null | boolean containsKey(Object value) | 如果此映射包含指定键的映射关系,则返回true | boolean containsValue(Object value) | 如果此映射将一个或多个键映射到指定值,则返回true | Set keySet() | 返回此映射中的见的Set视图 | Collection<V>values() | 返回此映射中包含的值Collection视图 | Set<Map.Entry<K,V>>entrySet() | 返回映射中包含的映射关系的Set视图 |
HashMap集合
HashMap是Map接口的一个实现类,它用于存储键值映射关系, 但必须不保证出现重复的键
package map;
import java.util.HashMap;
import java.util.Map;
public class HashMapMethod {
public static void main(String[] args) {
Map map = new HashMap();
map.put("1","wailaiBug");
map.put("2","wai");
map.put("3","laiBug");
System.out.println("1:" + map.get("1"));
System.out.println("2:" + map.get("2"));
System.out.println("3:" + map.get("3"));
}
}
Console:
1:wailaiBug
2:wai
3:laiBug
?学会了如何简单的存储和获取值,那么我们开始遍历(卷起来!!!)
第一种:?
package map;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class HashMapMethod {
public static void main(String[] args) {
Map map = new HashMap();
map.put("1","wailaiBug");
map.put("2","wai");
map.put("3","laiBug");
Set keyset = map.keySet();
Iterator it = keyset.iterator();
while(it.hasNext())
{
Object key = it.next();
Object value = map.get(key);
System.out.println(key + ":" + value);
}
}
}
?Console :
1:wailaiBug
2:wai
3:laiBug
第二种:?
package map;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class HashMapMethod {
public static void main(String[] args) {
Map map = new HashMap();
map.put("1","wailaiBug");
map.put("2","wai");
map.put("3","laiBug");
Set entrySet = map.entrySet();
Iterator it = entrySet.iterator();
while(it.hasNext())
{
Map.Entry entry = (Map.Entry)(it.next());
Object key = entry.getKey();
Object value = entry.getValue();
System.out.println(key + ":" + value);
}
}
}
Console:
1:wailaiBug
2:wai
3:laiBug
在Map中还提供了一个values()方法,通过这个方法获取Map中所有值得Collection集合。
package map;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class HashMapMethod {
public static void main(String[] args) {
Map map = new HashMap();
map.put("1","wailaiBug");
map.put("2","wai");
map.put("3","laiBug");
Collection values = map.values();
Iterator it = values.iterator();
while(it.hasNext())
{
Object value = it.next();
System.out.println(value);
}
}
}
Console:
wailaiBug
wai
laiBug
?HashMap集合迭代出来的元素顺序和存入的顺序是不一致的。如果想让这两个顺序一致,可以使用Java中提供的LinkedHashMap类,它是HashMap的子类与LinkedList一样,它是使用双向链表来维护内部元素的关系,是Map元素迭代的顺序与存入的顺序一致。
package map;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class HashMapMethod {
public static void main(String[] args) {
Map map = new HashMap();
map.put("1","wailaiBug");
map.put("2","wai");
map.put("3","laiBug");
Set keySet = map.keySet();
Iterator it = keySet.iterator();
while(it.hasNext())
{
Object key = it.next();
Object value = map.get(key);
System.out.println(key + ":" + value);
}
}
}
Console:
1:wailaiBug
2:wai
3:laiBug
?
Properties集合(Hashtable实现类)
Properties主要用来存储字符串类型的键和值,在实际开发中经常使用Properties集合来存取响应的配置器。
|