Java:集合
程序员文章站
2022-07-10 20:58:41
本文内容: 什么是集合 Collection Iterator List set Map Collections工具类 首发日期:2018-05-17 什么是集合: 集合是一种新容器,集合可以存储数量不固定的元素(数组的空间是固定的,你申请多少空间以后都不能改变),而集合可以动态的增加空间(有些是空... ......
本文内容:
- 什么是集合
- Collection
- Iterator
- List
- set
- Map
- Collections工具类
首发日期:2018-05-17
什么是集合:
- 集合是一种新容器,集合可以存储数量不固定的元素(数组的空间是固定的,你申请多少空间以后都不能改变),而集合可以动态的增加空间(有些是空间不够时新建一个足够大的数组再把原来的元素移到新的数组中)。
-
集合的出现解决的几个问题:
- 存储数量不等的元素。
- 定义了数据结构,所以集合的元素可以依据数据结构来读取,比如LinkList(可以理解成链表结构的数组),HashSet(哈希表结构)
- 可以存储具有映射关系的元素(Map)
PS:
- jdk1.5和jdk1.8新增的内容有点多,现在有点新特性没添上,以后有空再加上去吧。
- Queue主要为了实现队列功能,这里不讲述,有兴趣自行查找。
Collection:
介绍:
- collection是一个抽象接口,是List、Set和Queue接口的父接口
方法(父接口定义的方法,实现类中都会有)【具体使用看下面的具体实现类】:
-
添加元素:
- 添加一个元素X:add(X)
- 添加集合X中全部元素到集合中:addAll(X)
- clear():移除此 collection 中的所有元素
- remove(x):移除指定元素x
- removeAll(x):移除集合中另一个集合x的元素
- size():检测集合的元素个数
- isEmpty():检测集合是否为空,空返回true
- contains(x):是否包含某元素x
- containsAll(x):是否包含另一个集合x中的所有元素。
- toArray():将集合转成数组
- iterator():返回可以在此集合上进行元素迭代的迭代器
- equals(x):比较集合是否与x一致。
集合的获取依赖于迭代器Iterator。
补充:
- 下面的各种具体实现类的构造方法都支持传入一个比较器,用于执行非自然排序(比如String的比较是字符,而我们可以定义成按字符长度排序。)【例子在TreeSet中。】
Iterator:
介绍:
- Iterator是一个接口,它可以对Collection进行元素迭代(如果Collection返回了一个迭代器的话)
- 基本每一个具体实现类中都实现了Iterator(内部实现),从而使得Iterator可以迭代所有的Collection的具体实现类的元素。
迭代方法:
- hasNext():如果仍有元素可以迭代,则返回 true。
- next():迭代出下一个元素
- remove():删除迭代器刚越过的元素(就是刚刚next到的元素)
示例:
package 集合; import java.util.ArrayList; import java.util.Iterator; public class IteratorDemo { public static void main(String[] args) { ArrayList q=new ArrayList(); //增 q.add("a"); q.add("b"); q.add("c"); q.add("d"); //使用迭代器迭代 for(Iterator it=q.iterator();it.hasNext();) { Object obj=it.next(); System.out.println(obj);//a b c d if(obj=="a") it.remove(); } //删除后查看一下 System.out.println(q); } }
补充:
- 对于List,有一个特别的迭代器接口:ListIterator,这个迭代器专用于List,它比普通的接口多出了增加元素、修改元素、正反向迭代功能。
- Iterator经常与foreach语句来搭配使用。
List:
介绍:
- List是一个接口,定义的是存储的元素是有序的集合,
- 实现List的集合可以使用下标来取出
- 实现List的集合中元素可以是重复的。
特有方法(除了Collection中有的方法):
- add(index,x):在集合的指定位置index插入指定元素x
-
addAll(index,x):从指定的位置开始,将集合x中的所有元素插入到此列表中。
- remove(index):移除集合中指定位置index上的元素。
- get(index):返回列表中指定位置的元素。 【因为List是有下标的,所以支持使用get来获取元素】
-
set(index, x)
用指定元素x替换列表中指定位置index的元素 。 - indexOf(X):返回集合中元素x的下标 。
-
subList(fromIndex,toIndex):根据下标,从集合中取出元素,返回的是一个List
。 listIterator():返回此列表中的元素的列表迭代器。
常用实现类:
ArrayList:
- 是一种数组结构的集合,便于查找,增删麻烦
- 也有一些新增的方法,但貌似不太重要,有兴趣的查文档吧。
import java.util.ArrayList; import java.util.Iterator; public class ListDemo { public static void main(String[] args) { ArrayList q=new ArrayList(); //增 q.add("a"); q.add("b"); ArrayList a=new ArrayList(); a.addAll(q); a.add("c"); a.add("d"); System.out.println(a);//[a, b, c, d],实现了toString,所以可以直接打印出来。 //删 // a.remove("a"); a.remove(0); //查 System.out.println(a.size());//3 System.out.println(a.contains("b"));//true System.out.println(a.isEmpty());//false System.out.println(a);//[b, c, d] //改 a.set(0, "bag"); System.out.println(a); //使用迭代器迭代 for(Iterator it=a.iterator();it.hasNext();) { System.out.println(it.next());//c d } } }
LinkedList:
- 是一种链表结构的集合,便于增删,查找不快。
- 它的元素插入法是头插法,所以后面的元素会排在前面。
- LinkedList还实现了Deque接口,可以用LinkedList来实现堆栈、队列、双端队列。
-
因为使用了头插法,所以有几个方法需要注意一下:
- addFirst(x):将指定元素插入此列表的开头
- addLast(x):将指定元素添加到此列表的结尾。
- getFirst():返回此列表的第一个元素。
- getLast():返回此列表的最后一个元素。
- removeFirst():移除并返回此列表的第一个元素。
- removeLast():移除并返回此列表的最后一个元素。
descendingIterator():返回逆序的迭代器
补充:
- 以前还能见到Vector和Stack,但Vector太过古老,被ArrayList取代,所以这里不讲;而Stack已经被ArrayDeque取代。
- 这里不讲述线程同步中集合的处理。
- 对于想在迭代器迭代过程中针对集合进行增删改的,可以通过返回ListIterator来操作。
set
介绍:
- Set是一个接口,定义的是存储的元素是无序的集合,
- 实现Set的集合中元素不可以重复。
- 获取Set集合中的元素只能依靠迭代器。
新增方法:无新增方法,基本都是Collection中声明的方法。
常用实现类:
HashSet:
- 哈希表结构的集合
- 利用哈希表结果构成的集合查找速度会很快。
TreeSet:
- 二叉树结构的集合
- 二叉树插入元素是有顺序的,TreeSet的元素是有序的。
- 由于二叉树需要对结点排序(插入的结点位置),默认情况下没有排序方法,所以元素需要继承Comparator并重写compareTo方法来实现元素之间比较大小的功能。
- 对于TreeSet,compareTo方法来保证元素的唯一性。【这时候可以不重写equals】
LinkHashSet:
- 是HashSet的子类,是链表跟哈希表的数据结构的结合,上一个元素会存储下一个元素的位置,所以可以按顺序来取出。
解决集合的元素的重复:
- Set集合是不允许重复元素的,但是集合是不知道我们对象的重复的判断依据的,默认情况下判断依据是判断两者是否为同一元素(euqals方法,依据是元素==元素?),如果要依据我们自己的判断来判断元素是否重复,需要重写元素的equals方法(元素比较相等时调用)【在hastSet中还需要多一步:hashCode方法(元素生成hash码的规则,生成的哈希码如果相同则会影响存储规则--》首先判断哈希码是否相同,再判断元素是否相同,如果元素相同则不存储,如果不相同则依据哈希规则向后取一个位置存储(数据结构的知识,这里不讲述))】
- hashCode()的返回值是元素的哈希码,如果两个元素的哈希码相同,那么需要进行equals判断。【所以可以自定义返回值作为哈希码】
- equals()返回true代表两元素相同,返回false代表不同。
import java.util.HashSet; import java.util.Set; class Student{ String name; int age; Student(String name,int age){ this.name=name; this.age=age; } public String toString() {//重写方法,以便sysout能输出 return "Student [name=" + name + ", age=" + age + "]"; } public int hashCode() {//这里使用的是自动生成的代码,也可以使用自己的规则 final int prime = 31; int result = 1; result = prime * result + age; result = prime * result + ((name == null) ? 0 : name.hashCode()); return result; } public boolean equals(Object obj) {//这里使用的是自动生成的代码,也可以使用自己的规则 if (this == obj)//如果两个地址相同,返回true return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Student other = (Student) obj; if (age != other.age) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name))//这里根据姓名和年龄来判断元素是否相同 return false; return true; } } public class HashSetDemo { public static void main(String[] args) { Set s=new HashSet(); // s.add("abc"); // s.add("abc"); // System.out.println(s);//这里因为可以使用自带的判断方法,所以不会发生重复 // s.add(new Student("lilei",18)); // s.add(new Student("lilei",18)); // System.out.println(s);//这里因为判断两个地址是不同的,所以会重复。 // 在重写equals之后: s.add(new Student("lilei",18)); s.add(new Student("lilei",18)); System.out.println(s);//不发生重复。 } }
解决TreeSet的排序问题:
- 二叉树需要结点排序,所以元素之间比较能够比较,所以对于自定义元素对象,需要继承Comparator并重写的compareTo方法。
- 两个元素相等时,compareTo返回0;左大于右时,返回正整数(一般返回1);小于时返回负整数(一般返回-1)
- 在TreeSet中,compareTo负责检测元素重复,所以要对compareTo的重写留心。
import java.util.TreeSet; class Student2 implements Comparable{ String name; int age; Student2(String name,int age){ this.name=name; this.age=age; } public int compareTo(Object o) { Student2 stu=(Student2)o; return this.name.equals(stu.name)?this.age-stu.age:this.name.compareTo(stu.name); //默认按姓名排序,如果有重复的姓名,按年龄排序。认为同名同年龄为同一元素 } @Override public String toString() { return "Student2 [name=" + name + ", age=" + age + "]"; } } public class TreeSetDemo { public static void main(String[] args) { TreeSet t=new TreeSet(); // t.add("a"); // t.add("c"); // t.add("d"); // t.add("b"); // System.out.println(t);//对于非自定义对象,可以排序[a, b, c, d] t.add(new Student2("lilei",18)); t.add(new Student2("lilei",17)); t.add(new Student2("hanmeimei",18)); t.add(new Student2("john",17)); t.add(new Student2("mike",27)); t.add(new Student2("alice",21)); System.out.println(t); } }
- 还支持创建集合时传入一个比较器Comparator来进行排序,这时候重写的是compare方法:
import java.util.Comparator; import java.util.TreeSet; class CompareByLength implements Comparator{ public int compare(Object o1, Object o2) { Student3 stu1=(Student3)o1; Student3 stu2=(Student3)o2; return stu1.name.length()-stu2.name.length(); // 注意,这里也与compareTo类似,定义的规则必须要考虑到重复性,不然会导致属性值相同的元素 // 认为是同一元素 } } class Student3 { String name; int age; Student3(String name,int age){ this.name=name; this.age=age; } public String toString() { return "Student2 [name=" + name + ", age=" + age + "]"; } } public class TreeSetDemo2 { public static void main(String[] args) { TreeSet t=new TreeSet(new CompareByLength()); t.add(new Student3("aaa",18)); t.add(new Student3("a",18)); // t.add(new Student3("d",18));//这里是元素重复性的检测,原因在compare t.add(new Student3("aa",17)); t.add(new Student3("cccccccccc",17)); System.out.println(t); } }
Map:
介绍:
- Map主要用于存储带有映射关系的数据(比如学号与学生信息的映射关系)
- Map的存储形式是键值对,一个键对应一个值。
- 键是不可重复的,值是可以重复的。
常见方法:
-
获取:
- keySet():获取所有键,返回一个Set集合
-
get(x):返回指定键x所映射的值;如果此映射不包含该键的映射关系,则返回
null
。 - size():返回键值对的数量。
- values():获取所有值,返回一个Set集合 。
entrySet():返回一个集合,集合中的对象都是包含键值对关系的
entry类对象。
- put(key,value):将指定的值与此映射中的指定键关联【已有则覆盖旧值】
- putAll(X):从指定映射X中将所有映射关系复制到此映射中。
- clear():删除所有键值对 。
- remove(key):如果存在一个键key的映射关系,则将其从此映射中移除
- containsKey(x):检测是否存储指定键x
- containsValue(x):检测是否存储指定值x
- isEmpty():检测是否为空,空则返回 true
重要实现类:
HashMap:
- 哈希表结构的。
- HashMap的方法基本都是Map中声明的方法
TreeMap:
- 二叉树结构的。
- 有序的,可以根据键值来排序,需要实现可以进行比较的方法(compareTo或compare)
Properties:
- 一种经常用来存储配置的集合,很适合存储一些比如"backgroundColor=red"的数据。
- 常用方法:
getProperty(String key):用指定的键在此属性列表中搜索属性。
-
load(InputStream inStream):从输入流中读取属性列表(键和元素对)。
list(PrintStream out):将属性列表输出到指定的输出流。
嵌套类:
Map.Entry<K,V>
- 与Map.entrySet 方法配合,Map.entrySet返回的结果是一个集合,集合中的每一个元素都是这个类的对象。
- 存在意义是返回结果包含了键和值,使得能够同时操作键和值。
- 此类对象的常用方法:
- getKey():返回与此项对应的键。
getValue():返回与此项对应的值。
-
setValue(value):用指定的值替换与此项对应的值
public class MapDemo { public static void main(String[] args) { Map m=new HashMap(); m.put("hanmeimei", "lilei"); m.put("wodeta", "wo"); m.put("apple", "google"); Set s=m.entrySet(); for(Iterator it=s.iterator();it.hasNext();) { Map.Entry me=(Entry) it.next(); System.out.println(me.getKey()+"...."+me.getValue()); } } }
Collections工具类:
介绍:
- Collections是jdk提供的一个专门用来操作集合的类
- 此类完全由在 collection 上进行操作或返回 collection 的静态方法组成。
常用方法:
- 排序:
- sort(L):根据元素的自然顺序 对指定列表按升序进行排序。
- sort(L,C):根据指定比较器C产生的顺序对指定列表进行排序。
- 查找:
- max(L):根据元素的自然顺序,返回给定 collection 的最大元素
- max(L,C):根据指定比较器C产生的顺序,返回给定 collection 的最大元素
- min(L):根据元素的自然顺序,返回给定 collection 的最小元素
- min(L,C):根据指定比较器C产生的顺序,返回给定 collection 的最小元素
- 修改:
- fill(L,x):使用指定元素替换指定列表中的所有元素。
- swap(L,indexX,indexY):将指定集合中indexX与indexY的元素交换
- reverse(L):反转指定列表中元素的顺序。
reverseOrder():返回一个比较器,它强行逆转实现了 Comparable 接口的对象 collection 的自然顺序。
import java.util.ArrayList; import java.util.Collections; public class ListDemo2 { public static void main(String[] args) { ArrayList q=new ArrayList(); q.add("a"); q.add("z"); q.add("b"); q.add("c"); System.out.println(Collections.max(q)); System.out.println(q); Collections.sort(q); System.out.println(q); } }
想了解更多,可以自行查看jdk文档。