Java集合框架
集合
- 概念:对象的容器,定义了对多个对象进行操作的常用方法。可实现数组的功能。
- 集合与数组的区别:
- 数组长度固定,集合长度不固定。
- 数组可以存储基本类型和引用类型,集合只能存储引用类型。
- 位置:java.util.*
集合框架
java集合框架为我们提供了一套性能优良、使用方便的接口和类,它们都位于java.util包中。集合框架是一种为表示和操作而规定的一种统一的彼岸准体系结构。
早在 Java 2 中之前,Java 就提供了特设类。比如:Dictionary, Vector, Stack, 和 Properties 这些类用来存储和操作对象组。
虽然这些类都非常有用,但是它们缺少一个核心的,统一的主题。由于这个原因,使用 Vector 类的方式和使用 Properties 类的方式有着很大不同。
集合框架设计要满足的目标:
- 该框架必须是高性能的。基本集合(动态数组,链表,树,哈希表)的实现也必须是高效率的。
- 该框架允许不同类型的集合,以类似的方式工作,具有高度的互操作性。
- 对一个集合的扩展和适应必须是简单的。
集合框架包含的主要内容及彼此之间的关系如图所示:
Java集合类主要由两个根接口Collection和Map派生出来的。
Collection
Collection派生出了三个子接口:
- [Collection](Collection (Java Platform SE 8 ) (matools.com))(父)接口,代表一组任意类型的对象,无序、无下标、不能重复。
- 方法:
- boolean add(Object obj) //添加一个对象。
- boolean addAll(Collection c)//将一个集合中的所有对象添加到此集合中。
- void clear()//清空此集合中的所有对象。
- boolean contains(Object o)//检查此集合中是否包含o对象。
- boolean equals(Object o)//比较此集合是否与指定对象相等。
- boolean isEmpty()//判断此集合是否为空。
- boolean remove(Object o)//在此集合中移除o对象。
- int size()//返回此集合中的元素个数。
- Object[] toArray()//将此集合转换成数组。
- 方法:
代码示例1:(Collection的基本使用)
package com.collection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
/**
* Collection接口的使用
* 1、添加元素
* 2、删除元素
* 3、遍历元素
* 4、判断
* @author ywj
*/
public class CollectionDemo1 {
public static void main(String[] args) {
//创建集合
Collection collection = new ArrayList();
//1、添加元素
((ArrayList) collection).add("西瓜");
((ArrayList) collection).add("甜瓜");
((ArrayList) collection).add("哈密瓜");
System.out.println("元素个数:"+collection.size());
System.out.println(collection);
//2、删除元素
// collection.remove("哈密瓜");
// collection.clear();
// System.out.println("删除之后:"+collection.size());
//3、遍历元素[重点]
//3.1增强for
System.out.println("==========3.1使用增强for==========");
for (Object object:collection){
System.out.println(object);
}
//3.2使用迭代器(迭代器专门用来遍历集合的一种方式)
//hasNext();有没有下一个元素
//next();获取下一个元素
//remove();删除当前元素
System.out.println("==========3.2使用迭代器==========");
Iterator it = collection.iterator();
while (it.hasNext()){
String object=(String)it.next();
System.out.println(object);
//不能使用collection删除方法
//collection.remove(object); //报错:ava.util.ConcurrentModificationException
//it.remove();
}
System.out.println("元素个数:"+collection.size());
//4、判断
System.out.println(collection.contains("西瓜"));
System.out.println(collection.isEmpty());
}
}
运行结果:
元素个数:3
[西瓜, 甜瓜, 哈密瓜]
==========3.1使用增强for==========
西瓜
甜瓜
哈密瓜
==========3.2使用迭代器==========
西瓜
甜瓜
哈密瓜
元素个数:3
true
false
Process finished with exit code 0
代码示例2:
package com.collection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
/**
* Collection的使用:保存学生信息
* @author ywj
*/
public class CollectionDemo02 {
public static void main(String[] args) {
//新建一个Collection对象
Collection collection = new ArrayList();
Student s1 = new Student("张三", 18);
Student s2 = new Student("疑问句", 20);
Student s3 = new Student("挽姬", 21);
//1、添加数据
((ArrayList) collection).add(s1);
((ArrayList) collection).add(s2);
((ArrayList) collection).add(s3);
System.out.println("元素个数:"+collection.size());
System.out.println(collection.toString());
//2、删除
// collection.remove(s1);
// collection.clear();//将三个对象从集合移除
// System.out.println("删除之后:"+collection.size());
//3、遍历
//3.1增强for
for (Object object:collection){
Student s = (Student) object;
System.out.println(s.toString());
}
//3.2迭代器:hsaNext() next(); remove迭代过程中不能使用collection删除方法
Iterator it = collection.iterator();
while (it.hasNext()){
Student s = (Student) it.next();
System.out.println(s.toString());
}
//4、判断
System.out.println(collection.contains(s1));
System.out.println(collection.isEmpty());
}
}
运行结果:
元素个数:3
[Student [name=张三,age=18], Student [name=疑问句,age=20], Student [name=挽姬,age=21]]
Student [name=张三,age=18]
Student [name=疑问句,age=20]
Student [name=挽姬,age=21]
Student [name=张三,age=18]
Student [name=疑问句,age=20]
Student [name=挽姬,age=21]
true
false
Process finished with exit code 0
-
Set接口继承Collection接口,存储一组唯一(不允许重复),无序的对象。
- 方法:全部继承自collection中的方法。
来自API中的解释:
public interface Set<E> extends Collection<E>
不包含重复元素的集合。 更正式地,集合不包含一对元素
e1
和e2
,使得e1.equals(e2)
,并且最多一个空元素。 正如其名称所暗示的那样,这个接口模拟了数学集抽象。Set
接口除了继承自Collection
接口的所有构造函数的合同
以及add,equals
和hashCode
方法的合同外
,还
增加
了其他规定。 其他继承方法的声明也包括在这里以方便。 (伴随这些声明的规范已经量身定做Set
接口,但它们不包含任何附加的规定。)构造函数的额外规定并不奇怪,所有构造函数都必须创建一个不包含重复元素的集合(如上所定义)。
注意:如果可变对象用作设置元素,则必须非常小心。 如果对象的值以影响
equals
比较的方式更改,而对象是集合中的元素,则不
指定集合的行为。 这种禁止的一个特殊情况是,一个集合不允许将其本身作为一个元素。一些集合实现对它们可能包含的元素有限制。 例如,一些实现禁止空元素,有些实现对元素的类型有限制。 尝试添加不合格元素会引发未经检查的异常,通常为
NullPointerException
或ClassCastException
。 尝试查询不合格元素的存在可能会引发异常,或者可能只是返回false; 一些实现将展现出前者的行为,一些实现将展现出后者。 更一般来说,尝试对不符合条件的元素的操作,其完成不会导致不合格元素插入到集合中,可能会导致异常,或者可能会成功执行该选项。 此异常在此接口的规范中标记为“可选”。此接口是成员Java Collections Framework 。
代码示例(Set的基本使用):
package com.collection; import java.util.HashSet; import java.util.Iterator; import java.util.Set; /** * 测试set接口的使用 * @author ywj */ public class SetDemo01 { public static void main(String[] args) { //创建集合 Set<String> set = new HashSet<>(); //1、添加数据 set.add("小米"); set.add("华为"); set.add("魅族"); System.out.println("数据个数:"+set.size()); System.out.println(set.toString()); //2、删除 // set.remove("魅族"); // System.out.println(set.toString()); //3、遍历 //3.1增强for System.out.println("--------增强for---------"); for (String string:set){ System.out.println(string); } //3.2使用迭代器 System.out.println("---------迭代器----------"); Iterator<String> it = set.iterator(); while (it.hasNext()){ System.out.println(it.next()); } //4.判断 System.out.println(set.contains("华为")); System.out.println(set.isEmpty()); } } 运行结果: 数据个数:3 [华为, 魅族, 小米] --------增强for--------- 华为 魅族 小米 ---------迭代器---------- 华为 魅族 小米 true false Process finished with exit code 0
-
Set实现类
- HashSet(重点):
- 基于HashCode实现元素不重复,计算元素存放的位置。
- 当存入元素的哈希码相同时,会调用equals进行确认,如结果为true,则拒绝后者存入。
代码示例(HashSet使用方法):
package com.collection; import java.util.HashSet; import java.util.Iterator; /** * HashSet集合使用 * 存储结构:哈希表(数组+链表+红黑树) * * @author ywj */ public class HashSetDemo01 { public static void main(String[] args) { //新建集合 HashSet<String> hashSet = new HashSet<>(); //1、添加元素 hashSet.add("疑问句"); hashSet.add("饭饭饭"); hashSet.add("唐蛇皮"); hashSet.add("挽姬"); System.out.println("元素个数:"+hashSet.size()); System.out.println(hashSet.toString()); //2、删除数据 // hashSet.remove("饭饭饭"); // System.out.println("删除之后:"+hashSet.size()); //3、遍历 //3.1使用增强for System.out.println("-----------使用增强for---------"); for (String string:hashSet){ System.out.println(string); } //3.2使用迭代器 System.out.println("-----------使用迭代器-----------"); Iterator<String> it = hashSet.iterator(); while (it.hasNext()){ System.out.println(it.next()); } //4.判断 System.out.println(hashSet.contains("饭饭饭")); System.out.println(hashSet.isEmpty()); } } 运行结果: 元素个数:4 [疑问句, 挽姬, 唐蛇皮, 饭饭饭] -----------使用增强for--------- 疑问句 挽姬 唐蛇皮 饭饭饭 -----------使用迭代器----------- 疑问句 挽姬 唐蛇皮 饭饭饭 true false Process finished with exit code 0
代码示例(HashSet)2:
package com.collection; import java.util.HashSet; import java.util.Iterator; /** * HashSet的使用 * 存储结构:哈希表(数组+链表+红黑树) * 存储过程: * 1、根据hashcode计算保存的位置,如果此位置为空,则直接保存,如果不为空则执行第二步。 * 2、再执行equals方法,如果equals方法为true,则认为是重复,否则,形成链表。 * @author ywj */ public class HashSetDemo02 { public static void main(String[] args) { //创建集合 HashSet<Person> persons = new HashSet<>(); //1、添加数据 Person p1 = new Person("疑问句", 20); Person p2 = new Person("挽姬", 21); Person p3 = new Person("唐蛇皮", 19); persons.add(p1); persons.add(p2); persons.add(p3); // persons.add(p3);//重复 persons.add(new Person("唐蛇皮",19)); System.out.println("元素个数:"+persons.size()); System.out.println(persons.toString()); //2、删除操作 // persons.remove("p1"); // System.out.println("删除之后:"+persons.size()); //3、遍历 //3.1使用增强for System.out.println("-----------使用增强for---------"); for (Person person:persons){ System.out.println(person); } //3.2迭代器 System.out.println("-----------使用迭代器-----------"); Iterator<Person> it = persons.iterator(); while (it.hasNext()){ System.out.println(it.next()); } //4、判断 System.out.println(persons.contains("唐蛇皮")); System.out.println(persons.isEmpty()); } } Person类: package com.collection; /** * 人类 * @author ywj */ public class Person { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Person [name="+name+",age="+age+"]"; } @Override public int hashCode() { int n1=this.name.hashCode(); int n2=this.age; return n1+n2; } @Override public boolean equals(Object obj) { if (this==obj){ return true; } if (obj==null){ return false; } if (obj instanceof Person){ Person p=(Person)obj; if (this.name.equals(p.getName())&&this.age==getAge()){ return true; } } return super.equals(obj); } }
- TreeSet:
- 基于排列顺序实现元素不重复。
- 实现了SortedSet接口,对集合元素自动排序。
- 元素对象的类型必须实现Comparable接口,指定排序规则。
- 通过CompareTo方法确定是否为重复元素。
- HashSet(重点):
代码示例:
package com.collection;
import java.util.Iterator;
import java.util.TreeSet;
/**
* 使用TreeSet保存数据
* 存储结构:红黑树
* 要求:元素必须要实现Comparable接口,compareTo()方法返回值为0,认为是重复元素。
* @author ywj
*/
public class TreeSetDemo02 {
public static void main(String[] args) {
//创建集合
TreeSet<Person> persons = new TreeSet<>();
//1、添加元素
Person p1 = new Person("疑问句", 20);
Person p2 = new Person("挽姬", 21);
Person p3 = new Person("唐蛇皮", 19);
persons.add(p1);
persons.add(p2);
persons.add(p3);
System.out.println("元素个数:"+persons.size());
System.out.println(persons.toString());
//2、删除
// persons.remove(p1);
// System.out.println(persons.size());
//3、遍历
//3.1增强for
System.out.println("---------增强for------------");
for (Person person : persons){
System.out.println(person);
}
//3.2使用迭代器
System.out.println("----------使用迭代器----------");
Iterator<Person> it = persons.iterator();
while (it.hasNext()){
System.out.println(it.next());
}
//4、判断
System.out.println(persons.contains("唐蛇皮"));
}
}
Person类:
package com.collection;
/**
* 人类
* @author ywj
*/
public class Person implements Comparable<Person>{
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person [name="+name+",age="+age+"]";
}
@Override
public int hashCode() {
int n1=this.name.hashCode();
int n2=this.age;
return n1+n2;
}
@Override
public boolean equals(Object obj) {
if (this==obj){
return true;
}
if (obj==null){
return false;
}
if (obj instanceof Person){
Person p=(Person)obj;
if (this.name.equals(p.getName())&&this.age==getAge()){
return true;
}
}
return super.equals(obj);
}
//先按姓名比,然后再按年龄比
@Override
public int compareTo(Person o) {
int n1=this.getName().compareTo(o.getName());
int n2=this.age-o.getAge();
return n1==0?n2:n1;
}
}
代码示例:(补充Comparator接口)
package com.collection;
import java.util.Comparator;
import java.util.TreeSet;
/**
* TreeSet集合的使用
* Comparator :实现定制比较(比较器)
* Comparable:可比较的
* @author ywj
*/
public class TreeSetDemo03 {
public static void main(String[] args) {
//创建集合,并指定比较规则
TreeSet<Person> persons = new TreeSet<>(new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
int n1=o1.getAge()-o2.getAge();
int n2=o1.getName().compareTo(o2.getName());
return n1==0?n2:n1;
}
});
Person p1 = new Person("疑问句", 20);
Person p2 = new Person("挽姬", 21);
Person p3 = new Person("唐蛇皮", 19);
persons.add(p1);
persons.add(p2);
persons.add(p3);
System.out.println(persons.toString());
}
}
代码案例:
package com.collection;
import java.util.Comparator;
import java.util.TreeSet;
/**
* 要求:使用TreeSet集合实现字符串按照长度进行排序
* lufei shanzhi shuolong namei qiaoba fulanqi
* Comparator接口实现比较定制
* @author ywj
*/
public class TreeSetDemo04 {
public static void main(String[] args) {
//创建集合,并指定比较规则
TreeSet<String> treeSet = new TreeSet<>(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
int n1=o1.length()-o2.length();
int n2=o1.compareTo(o2);
return n1==0?n2:n1;
}
});
//添加数据
treeSet.add("lufei");
treeSet.add("shanzhi");
treeSet.add("shuolong");
treeSet.add("namei");
treeSet.add("qiaoba");
treeSet.add("fulanqi");
System.out.println(treeSet.toString());
}
}
运行结果
[lufei, namei, qiaoba, fulanqi, shanzhi, shuolong]
Process finished with exit code 0
- [List](List (Java Platform SE 8 ) (matools.com))接口继承Collection接口,存储一组不唯一(允许重复),有序(以元素插入次序来放置元素,不会重新排列)的对象。
- 方法:
- void add(int index, Object o)//在index位置插入对象o.
- boolean addAll(int index, Collection c)//将一个集合中的元素添加到此集合中的index位置。
- Object get(int index)//返回集合中指定位置的元素。
- List subList(int fromIndex, int toIndex) //返回fromIndex和toIndex之间的集合元素。
- 方法:
代码示例(List的基本使用):
package com.collection;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
/**
* List子接口的使用
* 特点:1、有序 有下标 2、可以重复
* @author ywj
*/
public class ListDemo01 {
public static void main(String[] args) {
//先创建集合对象
List list = new ArrayList<>();
//1、添加元素
list.add("小米");
list.add("华为");
list.add(0,"魅族");
System.out.println("元素个数:"+list.size());
System.out.println(list.toString());
//2、删除元素
//list.remove("苹果");
// list.remove(0);
// System.out.println("删除之后:"+list.size());
// System.out.println(list.toString());
//3、遍历
//3.1使用for遍历
System.out.println("==============3.1使用for遍历============");
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
//3.2使用增强for遍历
System.out.println("==============3.2使用增强for遍历============");
for (Object object:list){
System.out.println(object);
}
//3.3使用迭代器
Iterator it = list.iterator();
System.out.println("==============3.3使用迭代器============");
while (it.hasNext()){
System.out.println(it.next());
}
//3.4使用列表迭代器,和Iterator的区别,ListIterator可以向前或向后遍历,添加、删除、修改元素。
System.out.println("==============3.4使用列表迭代器从前往后============");
ListIterator lit = list.listIterator();
while (lit.hasNext()){
System.out.println(lit.nextIndex()+":"+lit.next());
}
System.out.println("==============3.4使用列表迭代器从后往前============");
while (lit.hasPrevious()){
System.out.println(lit.previousIndex()+":"+lit.previous());
}
//4、判断
System.out.println(list.contains("魅族"));
System.out.println(list.isEmpty());
//5、获取
System.out.println(list.indexOf("华为"));
}
}
运行结果:
元素个数:3
[魅族, 小米, 华为]
==============3.1使用for遍历============
魅族
小米
华为
==============3.2使用增强for遍历============
魅族
小米
华为
==============3.3使用迭代器============
魅族
小米
华为
==============3.4使用列表迭代器从前往后============
0:魅族
1:小米
2:华为
==============3.4使用列表迭代器从后往前============
2:华为
1:小米
0:魅族
true
false
2
Process finished with exit code 0
代码示例:
package com.collection;
import java.util.ArrayList;
import java.util.List;
/**
* List的使用
* @author ywj
*/
public class ListDemo02 {
public static void main(String[] args) {
//创建集合
List list = new ArrayList<>();
//1、添加数字数据(自动装箱)
list.add(10);
list.add(20);
list.add(30);
list.add(40);
list.add(50);
System.out.println("元素个数:"+list.size());
System.out.println(list.toString());
//2、删除操作
//list.remove(10);//报错 IndexOutOfBoundsException: Index: 10, Size: 5
//list.remove((Object) 20);
// list.remove((new Integer(10)));
// System.out.println("删除元素:"+list.size());
// System.out.println(list.toString());
//3、补充方法subList,返回了集合,含头不含尾
List subList = list.subList(1, 3);
System.out.println(subList.toString());
}
}
运行结果:
元素个数:5
[10, 20, 30, 40, 50]
[20, 30]
Process finished with exit code 0
List实现类:
-
[ArrayList](ArrayList (Java Platform SE 8 ) (matools.com))
- 数组结构实现,查询快、增删慢;
- JDK1.2版本,运行效率快、线程不安全。
注释:ArrayList是一个动态数组,也是我们最常用的集合,是List类的典型实现。
它允许任何符合规则的元素插入甚至包括null,每一个ArrayList都有一个初始容量(10),该容量代表了数组的大小。
随着容器中的元素不断增加,容器的大小也会随着增加,在每次向容器中增加元素的同时都会进行容量检查,当快溢出时,就会进行扩容操作。
所以如果我们明确所插入元素的多少,最好指定一个初始容量值,避免过多的进行扩容操作而浪费时间、效率。
ArrayList擅长于随机访问,同时ArrayList是非同步的。
代码示例:
package com.collection;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.ListIterator;
/**
* ArrayList的使用
* 存储结构:数组,查找遍历速度快,增删慢
* @author ywj
*/
public class ArrayListDemo01 {
public static void main(String[] args) {
//创建集合
ArrayList arrayList = new ArrayList<>();
//1、添加元素
Student s1 = new Student("疑问句",20);
Student s2 = new Student("挽姬",21);
Student s3 = new Student("唐蛇皮",19);
arrayList.add(s1);
arrayList.add(s2);
arrayList.add(s3);
System.out.println("元素个数:"+arrayList.size());
System.out.println(arrayList.toString());
//2、删除元素
//arrayList.remove(s1);
// arrayList.remove(new Student("唐蛇皮",19));//equals(this==obj)
// System.out.println("删除之后:"+arrayList.size());
//3、遍历元素(重点)
//3.1使用迭代器
System.out.println("-------------3.1使用迭代器-----------");
Iterator it = arrayList.iterator();
while (it.hasNext()){
Student s = (Student) it.next();
System.out.println(s.toString());
}
//3.2列表迭代器
ListIterator lit = arrayList.listIterator();
System.out.println("-------------3.2使用列表迭代器-----------");
while (lit.hasNext()){
Student s = (Student) lit.next();
System.out.println(s.toString());
}
//3.3使用列表迭代器倒序
System.out.println("-------------3.3使用列表迭代器倒序-----------");
while (lit.hasPrevious()){
Student s = (Student) lit.previous();
System.out.println(s.toString());
}
//4、判断
System.out.println(arrayList.contains(new Student("唐蛇皮",19)));
System.out.println(arrayList.isEmpty());
//5、查找
System.out.println(arrayList.indexOf(new Student("唐蛇皮",19)));
}
}
Student类:
@Override
public String toString() {
return "Student [name="+name+",age="+age+"]";
}
@Override
public boolean equals(Object obj) {
//1、判断是不是同一对象
if (this==obj){
return true;
}
//2、判断是否为空
if (obj==null){
return false;
}
//3、判断是否是Student类型
if (obj instanceof Student){
Student s = (Student) obj;
//4、比较属性
if (this.name.equals(s.getName())&&this.age==s.getAge()){
return true;
}
}
//5、不满足条件返回false
return false;
}
}
运行结果:
元素个数:3
[Student [name=疑问句,age=20], Student [name=挽姬,age=21], Student [name=唐蛇皮,age=19]]
-------------3.1使用迭代器-----------
Student [name=疑问句,age=20]
Student [name=挽姬,age=21]
Student [name=唐蛇皮,age=19]
-------------3.2使用列表迭代器-----------
Student [name=疑问句,age=20]
Student [name=挽姬,age=21]
Student [name=唐蛇皮,age=19]
-------------3.3使用列表迭代器倒序-----------
Student [name=唐蛇皮,age=19]
Student [name=挽姬,age=21]
Student [name=疑问句,age=20]
true
false
2
Process finished with exit code 0
-
[Vector](Vector (Java Platform SE 8 ) (matools.com)):
- 数组结构实现,查询快、增删慢;
- JDK1.0版本,运行效率慢、线程安全。
注意:与ArrayList相似,但是Vector是同步的,它的操作与ArrayList几乎一样。
代码示例:
package com.collection;
import java.util.Enumeration;
import java.util.Vector;
/**
* Vector集合的使用
* 存储结构:数组
* @author ywj
*/
public class VectorDmo01 {
public static void main(String[] args) {
//创建集合
Vector vector = new Vector<>();
//1、添加元素
vector.add("香蕉");
vector.add("榴莲");
vector.add("葡萄");
System.out.println("元素个数:"+vector.size());;
//2、删除
// vector.remove(0);
// vector.remove("香蕉");
// vector.clear();
//3、遍历
//3.1使用枚举器
Enumeration en = vector.elements();
while (en.hasMoreElements()){
String o = (String) en.nextElement();
System.out.println(o);
}
//4、判断
System.out.println(vector.contains("香蕉"));
System.out.println(vector.isEmpty());
//5、vector其他方法
//firstElement、lastElement、elementAt()
}
}
运行结果:
元素个数:3
香蕉
榴莲
葡萄
true
false
Process finished with exit code 0
-
[LinkedList](LinkedList (Java Platform SE 8 ) (matools.com))
- 链表结构实现,增删快,查询慢。
注意:LinkedList是采用双向循环链表实现,LinkedList是List接口的另一个实现,除了可以根据索引访问集合元素外,LinkedList还实现了Deque接口,可以当作双端队列来使用,也就是说,既可以当作“栈”使用,又可以当作队列使用。
代码示例:
package com.collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.ListIterator;
/**
* LinkedList的使用
* 存储结构:双向链表
* @author ywj
*/
public class LinkedListDemo01 {
public static void main(String[] args) {
//创建集合
LinkedList<Object> linkedList = new LinkedList<>();
//1、添加元素
Student s1 = new Student("疑问句",20);
Student s2 = new Student("挽姬",21);
Student s3 = new Student("唐蛇皮",19);
linkedList.add(s1);
linkedList.add(s2);
linkedList.add(s3);
System.out.println("元素个数:"+linkedList.size());
System.out.println(linkedList.toString());
//2、删除
// linkedList.remove(new Student("唐蛇皮",19));
// System.out.println("删除之后:"+linkedList.size());
// linkedList.clear();
//遍历
//3.1使用for遍历
System.out.println("----------3.1使用for遍历------------");
for (int i = 0; i < linkedList.size(); i++) {
System.out.println(linkedList.get(i));
}
//3.2使用增强for遍历
System.out.println("----------3.2使用增强for遍历------------");
for (Object object:linkedList){
Student s =(Student) object;
System.out.println(s.toString());
}
//3.3使用迭代器
System.out.println("----------3.3使用迭代器遍历------------");
Iterator<Object> it = linkedList.iterator();
while (it.hasNext()){
Student s = (Student) it.next();
System.out.println(s.toString());
}
//3.4使用listIterator迭代器
System.out.println("----------3.4使用列表迭代器遍历------------");
ListIterator<Object> lit = linkedList.listIterator();
while (lit.hasNext()){
Student s = (Student) lit.next();
System.out.println(s.toString());
}
//4、判断
System.out.println(linkedList.contains(s1));
System.out.println(linkedList.isEmpty());
//5、获取
System.out.println(linkedList.indexOf(s1));
}
}
运行结果:
元素个数:3
[Student [name=疑问句,age=20], Student [name=挽姬,age=21], Student [name=唐蛇皮,age=19]]
----------3.1使用for遍历------------
Student [name=疑问句,age=20]
Student [name=挽姬,age=21]
Student [name=唐蛇皮,age=19]
----------3.2使用增强for遍历------------
Student [name=疑问句,age=20]
Student [name=挽姬,age=21]
Student [name=唐蛇皮,age=19]
----------3.3使用迭代器遍历------------
Student [name=疑问句,age=20]
Student [name=挽姬,age=21]
Student [name=唐蛇皮,age=19]
----------3.4使用列表迭代器遍历------------
Student [name=疑问句,age=20]
Student [name=挽姬,age=21]
Student [name=唐蛇皮,age=19]
true
false
0
Process finished with exit code 0
-
Queue是队列集合
方法:PriorityQueue
PriorityQueue保存队列元素的顺序并不是按照加入的顺序,而是按照队列元素的大小进行排序的。
PriorityQueue不允许插入null元素。Deque:
Deque接口是Queue接口的子接口,它代表一个双端队列,当程序中需要使用“栈”这种数据结构时,推荐使用ArrayDeque。
Map接口派生:
Map代表的是存储key-value对的集合,可根据元素的key来访问value。
因此Java集合大致也可分成List、Set、Queue、Map四种接口体系。
-
Map接口存储一组成对的键-值对象,提供key(键)到values(值)的映射,Map中的Key不要求有序,不允许重复。values同样不要求有序,但是允许重复。
-
Map接口的特点:
- 用于存储任意键值对(Key-Value)
- 键:无序、无下标、不允许重复(唯一)
- 值:无序、无下标、允许重复
-
方法:
- V put(K key, V value) //将对象存入到集合中,关联键值。key重复则覆盖原值。
- Object get(Object key) // 根据键获取对应的值。
- Set //返回所有Key。
- Collection values() //返回包含所有值的Collection集合。
- Set<Map.Entry<K,V>>//键值匹配的Set集合。
-
API中对Map的描述
public interface Map<K,V>
将键映射到值的对象。 地图不能包含重复的键; 每个键可以映射到最多一个值。
这个接口取代了
Dictionary
类,它是一个完全抽象的类而不是接口。Map
界面提供了三个集合视图 ,允许将映射内容视为一组键,值集合或键值映射集合。 地图的顺序被定义为其中在地图上的集合视图迭代返回元素的顺序。 一些地图实现,如TreeMap
课程,对他们的订单做出了具体的保证; 其他人,像HashMap
班,不要。注意:如果使用可变对象作为地图键,必须非常小心。 如果对象的值以影响
equals
比较的方式更改,而对象是地图中的键,则不会指定地图的行为。 这个禁令的一个特殊情况是,地图不允许将自己包含在内。 虽然地图可以将其本身作为一个值,但建议您非常小心:equals
和hashCode
方法在这样的地图上已经不太明确。所有通用映射实现类应提供两个“标准”构造函数:一个创建空映射的void(无参数)构造函数,以及一个具有类型为
Map
的单个参数的构造函数
,它创建一个具有相同键值的新映射映射作为参数。 实际上,后一个构造函数允许用户复制任何地图,产生所需类的等效地图。 没有办法强制执行此建议(因为接口不能包含构造函数),而JDK中的所有通用映射实现都符合要求。包含在该界面中的“破坏性”的方法,即,修改其操作地图的方法,被指定抛出
UnsupportedOperationException
如果此映射不支持该操作。 如果是这种情况,如果调用对地图没有影响,这些方法可能会但不是必须抛出UnsupportedOperationException
。 例如,如果映射映射为“叠加”的地图为空,则可以在不可修改的映射上调用putAll(Map)
方法,但不是必须抛出异常。一些地图实现对它们可能包含的键和值有限制。 例如,一些实现禁止空键和值,有些对键的类型有限制。 尝试插入不合格的键或值会抛出未经检查的异常,通常为
NullPointerException
或ClassCastException
。 尝试查询不合格键或值的存在可能会引发异常,或者可能只是返回false; 一些实现将展现出前者的行为,一些实现将展现出后者。 更一般来说,尝试对不符合条件的密钥或值的操作,其完成不会导致将不合格元素插入到地图中可能会导致异常或可能成功执行该选项。 此异常在此接口的规范中标记为“可选”。Collections Framework接口中的许多方法都是按照
equals
方法定义的。 例如,对于在本说明书containsKey(Object key)
方法表示:“返回true
当且仅当此映射包含一个键k
使得(key==null ? k==null : key.equals(k))
的映射。” 该规范不应该被解释为意味着具有非空参数调用key
Map.containsKey
会导致key.equals(k)
被调用的任意键k。
实现可以实现优化,从而避免equals的
调用,例如,首先比较两个密钥的哈希码。 (Object.hashCode()
规范保证具有不等的哈希码的两个对象不能相等。)更一般地,各种Collections Framework接口的实现可以随意使用底层Object
方法的指定行为,无论执行者认为适当。执行递归遍历地图的一些地图操作可能会失败,并且地图直接或间接包含自身的自引用实例有异常。 这包括
clone()
,equals()
,hashCode()
和toString()
方法。 实现可以可选地处理自引用场景,然而大多数当前实现不这样做。此接口是成员Java Collections Framework 。
-
Map接口的使用
代码示例:
package com.collection; import java.util.HashMap; import java.util.Map; import java.util.Set; /** * Map接口的使用 * 特点: * 1、存储键值对 * 2、键不能重复,值可以重复 * 3、无序 * @author ywj */ public class MapDemo01 { public static void main(String[] args) { //创建Map集合 Map<String,String> map=new HashMap<>(); //1、添加元素 map.put("cn","中国"); map.put("uk","英国"); map.put("usa","美国"); System.out.println("元素个数:"+map.size()); System.out.println(map.toString()); //2、删除 // map.remove("usa"); // System.out.println("删除之后:"+map.size()); //3、遍历 //3.1使用keySet(); System.out.println("-------------keySet()------------"); // Set<String> keySet = map.keySet(); for (String key: map.keySet()){ System.out.println(key+"------"+map.get(key)); } //3.2使用entrySet()方法 System.out.println("-------------entrySet()------------"); //Set<Map.Entry<String, String>> entries = map.entrySet(); for (Map.Entry<String,String> entry: map.entrySet()) { System.out.println(entry.getKey()+"----------"+entry.getValue()); } //4、判断 System.out.println(map.containsKey("cn")); System.out.println(map.containsValue("韩国")); } } 运行结果: 元素个数:3 {usa=美国, uk=英国, cn=中国} -------------keySet()------------ usa------美国 uk------英国 cn------中国 -------------entrySet()------------ usa----------美国 uk----------英国 cn----------中国 true false Process finished with exit code 0
-
Map集合的实现类
-
HashMap(重点)
-
JDK1.2版本,线程不安全,运行效率快;允许用null作为key或是value。
-
API描述HashMap
public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable
基于哈希表的实现的
Map
接口。 此实现提供了所有可选的地图操作,并允许null的
值和null
键。 (HashMap
类大致相当于Hashtable
,除了它是不同步的,并允许null)。这个类不能保证地图的顺序; 特别是,它不能保证订单在一段时间内保持不变。假设哈希函数在这些存储桶之间正确分散元素,这个实现为基本操作(
get
和put
)提供了恒定的时间性能。 收集视图的迭代需要与HashMap
实例(桶数)加上其大小(键值映射数)的“容量”成正比
。 因此,如果迭代性能很重要,不要将初始容量设置得太高(或负载因子太低)是非常重要的。HashMap的
一个实例有两个影响其性能的参数: 初始容量和负载因子 。 容量是哈希表中的桶数,初始容量只是创建哈希表时的容量。 负载因子是在容量自动增加之前允许哈希表得到满足的度量。 当在散列表中的条目的数量超过了负载因数和电流容量的乘积,哈希表被重新散列 (即,内部数据结构被重建),使得哈希表具有桶的大约两倍。作为一般规则,默认负载因子(.75)提供了时间和空间成本之间的良好折中。 更高的值会降低空间开销,但会增加查找成本(反映在
HashMap
类的大部分操作中,包括get
和put
)。 在设置其初始容量时,应考虑地图中预期的条目数及其负载因子,以便最小化重新组播操作的数量。 如果初始容量大于最大条目数除以负载因子,则不会发生重新排列操作。如果许多映射要存储在
HashMap
实例中,则以足够大的容量创建映射将允许映射的存储效率高于使其根据需要执行自动重新排序以增长表。 请注意,使用同一个hashCode()
多个密钥是降低任何哈希表的hashCode()
的一种方法。 为了改善影响,当按键是Comparable
时,这个类可以使用键之间的比较顺序来帮助打破关系。请注意,此实现不同步。 如果多个线程同时访问哈希映射,并且至少有一个线程在结构上修改了映射,那么它必须在外部进行同步。 (结构修改是添加或删除一个或多个映射的任何操作;仅改变与实例已经包含的密钥相关联的值不是结构修改。)这通常通过对自然地封装映射的一些对象进行同步来实现。 如果没有这样的对象存在,地图应该使用
Collections.synchronizedMap
方法“包装”。 这最好在创建时完成,以防止意外的不同步访问地图:Map m = Collections.synchronizedMap(new HashMap(...));
所有这个类的“集合视图方法”返回的迭代器都是故障快速的 :如果映射在迭代器创建之后的任何时间被结构地修改,除了通过迭代器自己的
remove
方法之外,迭代器将抛出一个ConcurrentModificationException
。 因此,面对并发修改,迭代器将快速而干净地失败,而不是在未来未确定的时间冒着任意的非确定性行为。请注意,迭代器的故障快速行为无法保证,因为一般来说,在不同步并发修改的情况下,无法做出任何硬性保证。 失败快速迭代器尽力扔掉
ConcurrentModificationException
。 因此,编写依赖于此异常的程序的正确性将是错误的:迭代器的故障快速行为应仅用于检测错误。
-
-
代码示例:
package com.collection; import java.util.HashMap; import java.util.Map; /** * HashMap集合使用 * 存储结构:哈希表(数组+链表+红黑树) * 使用key可hashcode和equals作为重复 * @author ywj */ public class HashMapDemo01 { public static void main(String[] args) { //创建集合 HashMap<Car, String> cars = new HashMap<>(); //添加元素 Car c1 = new Car("奥迪", "银色"); Car c2 = new Car("大众", "金色"); Car c3 = new Car("比亚迪", "红色"); cars.put(c1,"武汉"); cars.put(c2,"上海"); cars.put(c3,"广州"); cars.put(new Car("比亚迪","红色"),"广州"); System.out.println("元素个数:"+cars.size()); System.out.println(cars.toString()); //2、删除 // cars.remove(c1); System.out.println("删除之后:"+cars.size()); //3、遍历 //3.1使用keySet(); System.out.println("-----------使用keySet()-------------"); for (Car key : cars.keySet()){ System.out.println(key.toString()+" "+cars.get(key)); } //3.2使用entrySet(); System.out.println("-----------使用entrySet();---------------"); for (Map.Entry<Car,String> entry : cars.entrySet()){ System.out.println(entry.getKey()+" "+entry.getValue()); } //4、判断 System.out.println(cars.containsKey(c1)); System.out.println(cars.containsValue("广州")); } } Car类: package com.collection; import java.util.Objects; /** * 汽车类 * @author ywj */ public class Car { private String carName; private String color; public Car() { } public Car(String carName, String color) { this.carName = carName; this.color = color; } public String getCarName() { return carName; } public void setCarName(String carName) { this.carName = carName; } public String getColor() { return color; } public void setColor(String color) { this.color = color; } @Override public String toString() { return "Car [carName="+carName+",color="+color+"]"; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Car car = (Car) o; return Objects.equals(carName, car.carName) && Objects.equals(color, car.color); } @Override public int hashCode() { return Objects.hash(carName, color); } } 运行结果: 元素个数:3 {Car [carName=比亚迪,color=红色]=广州, Car [carName=大众,color=金色]=上海, Car [carName=奥迪,color=银色]=武汉} -----------使用keySet()------------- Car [carName=比亚迪,color=红色] 广州 Car [carName=大众,color=金色] 上海 Car [carName=奥迪,color=银色] 武汉 -----------使用entrySet();--------------- Car [carName=比亚迪,color=红色] 广州 Car [carName=大众,color=金色] 上海 Car [carName=奥迪,color=银色] 武汉 true true Process finished with exit code 0
-
HashMap总结
- HashMap刚创建时,table是null,为了节省空间,当添加第一个元素时,table容量调整为16.
- 当元素个数大于阈值(16*0.75=12)时,会进行扩容,扩容后大小为原来的2倍。目的是减少调整元素的个数。
- JDK1.8 当每个链表长度大于8,并且元素个数大于等于64时,会调整为红黑树,目的提高执行效率。
- JDK1.8当链表长度小于6时,调整成链表。
- JDK1.8以前,链表时头插入,JDK1.8以后时是尾插入。
-
-
Hashtable:
- JDK1.0版本,线程安全,运行效率慢;不允许null作为key或是value。
-
Properties:
- Hashtable的子类,要求key和value都是String。通常用于配置文件的读取。
-
TreeMap
- 实现了SortedMap接口(是Map的子接口),可以对key自动排序。
代码示例:(TreeMap)
package com.collection; import java.util.Map; import java.util.TreeMap; /** * TreeMap的使用 * 存储结构:红黑树 * @author ywj */ public class TreeMapDemo01 { public static void main(String[] args) { //新建集合(定制比较) TreeMap<Car, String> treeMap = new TreeMap<Car,String>(); //1、添加元素 Car c1 = new Car("奥迪", "银色"); Car c2 = new Car("大众", "金色"); Car c3 = new Car("比亚迪", "红色"); treeMap.put(c1,"武汉"); treeMap.put(c2,"上海"); treeMap.put(c3,"广州"); System.out.println("元素个数:"+treeMap.size()); System.out.println(treeMap.toString()); //2、删除 // treeMap.remove(c1); // System.out.println("删除后:"+treeMap.size()); //3、遍历 //3.1使用keySet System.out.println("----------使用keySet----------"); for (Car key: treeMap.keySet()){ System.out.println(key+" "+treeMap.get(key)); } //3.2使用entrySet System.out.println("-----------使用entrySet--------"); for (Map.Entry<Car,String> entry : treeMap.entrySet()){ System.out.println(entry.getKey()+" "+entry.getValue()); } //4、判断 System.out.println(treeMap.containsKey(c1)); } } Car类: package com.collection; import java.util.Objects; /** * 汽车类 * @author ywj */ public class Car implements Comparable<Car>{ private String carName; private String color; public Car() { } public Car(String carName, String color) { this.carName = carName; this.color = color; } public String getCarName() { return carName; } public void setCarName(String carName) { this.carName = carName; } public String getColor() { return color; } public void setColor(String color) { this.color = color; } @Override public String toString() { return "Car [carName="+carName+",color="+color+"]"; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Car car = (Car) o; return Objects.equals(carName, car.carName) && Objects.equals(color, car.color); } @Override public int hashCode() { return Objects.hash(carName, color); } @Override public int compareTo(Car o) { int n1=this.carName.compareTo(o.getCarName()); int n2=this.color.compareTo(o.getColor()); return n2; } }
-
泛型
-
Java泛型是JDK1.5中引入的一个新特性,其本质是参数化类型,把类型作为参数传递。
-
常见形式有泛型类、泛型接口、泛型方法。
-
语法:
<T,...> //T称为类型占位符,表示一种引用类型。
-
好处:
- 提高代码的重要性。
- 防止类型转换异常,提高代码的安全性。
-
泛型集合
- 概念:参数化类型、类型安全的集合,强制集合元素的类型必须一致。
- 特点:
- 编译时即可检查,而非运行时抛出异常。
- 访问时,不必类型转换(拆箱)。
- 不同泛型之间引用不能相互赋值,泛型不存在多态。
泛型类:
代码示例:
package com.collection;
/**
* 泛型类
* 语法:类名<T,E>
* T是类型占位符,表示一种引用类型,如果编写多个使用逗号隔开
* @author ywj
*
*/
public class MyGenericDemo01<T> {
//使用泛型T
//1、创建一个变量
T t;
//2、作为方法的参数:
public void show(T t){
//不能实例化
System.out.println(t);
}
//3、泛型作为方法的返回值
public T getT(){
return t;
}
}
package com.collection;
public class TestGeneric {
public static void main(String[] args) {
//使用泛型类创建对象
//注意:1、泛型是引用类型 2、不同的泛型类型对象之间不能相互赋值
MyGenericDemo01<String> myGeneric = new MyGenericDemo01<String>();
myGeneric.t="hihi";
myGeneric.show("hh");
String string = myGeneric.getT();
MyGenericDemo01<Integer> myGeneri2 = new MyGenericDemo01<>();
myGeneri2.t=100;
myGeneri2.show(200);
Integer integer = myGeneri2.getT();
}
}
泛型接口:
代码示例:
package com.collection;
/**
* 泛型接口
* 语法:接口名<T>
* 注意:不能泛型静态常量
* @author ywj
*/
public interface MyInterface<T> {
String name="张三";
T server(T t);
}
package com.collection;
public class MyInterfaceImpl implements MyInterface<String>{
@Override
public String server(String t) {
System.out.println(t);
return null;
}
}
泛型方法:
代码示例:
package com.collection;
/**
* 泛型方法
* 语法:<T>返回值类型
* @author ywj
*/
public class MyGenericMethod {
//泛型方法
public <T> T show(T t){
System.out.println("泛型方法"+t);
return t;
}
//泛型方法的调用
MyGenericMethod myGenericMethod = new MyGenericMethod();
myGenericMethod.show("艾尼");
myGenericMethod.show(200);
myGenericMethod.show(3.14);
}
Collections工具类
- 概念:集合工具类,定义了除了存取以外的集合常用方法。
- 方法:
- public static void reverse(List<?> list) // 反转集合中元素的顺序
- public static void shuffle<List<?> list)//随机重置集合元素的顺序
- public static void short(List list)//升序排列(元素类型必须实现Comparable接口)
代码示例:
package com.collection;
import java.util.*;
/**
* 演示Collections工具类的使用
* @author ywj
*/
public class CollectionDemo03 {
public static void main(String[] args) {
//创建一个集合
List<Integer> list = new ArrayList<>();
list.add(30);
list.add(3);
list.add(51);
list.add(20);
list.add(8);
//sort排序
System.out.println("排序前:"+list.toString());//排序前:[30, 3, 51, 20, 8]
Collections.sort(list);
System.out.println("排序后:"+list.toString());//排序后:[3, 8, 20, 30, 51]
//binarySearch二分查找
int i = Collections.binarySearch(list, 8);//1
System.out.println(i);
//copy复制
List<Integer> dest = new ArrayList<>();
for (int j = 0; j < list.size(); j++) {
dest.add(0);
}
Collections.copy(dest,list);
System.out.println(dest.toString());//[3, 8, 20, 30, 51]
//reverse反转
Collections.reverse(list);
System.out.println("反转之后:"+list);//反转之后:[51, 30, 20, 8, 3]
//shuffle打乱
Collections.shuffle(list);
System.out.println("打乱之后:"+list);//打乱之后:[3, 30, 51, 20, 8]
//补充:list转成数组
Integer[] array = list.toArray(new Integer[0]);
System.out.println(array.length);
System.out.println(Arrays.toString(array));//5 [51, 20, 30, 8, 3]
//数组转换成集合
String[] names = {"张三","李四","王五"};
//这个集合是一个受限集合,不能添加和删除
List<String> list1 = Arrays.asList(names);
System.out.println(list1);//[张三, 李四, 王五]
}
}