Java基础复习(七):集合
集合
Collection接口是所有单列集合的最顶层接口,List接口和Set接口分别实现了Collection接口;而我们常用的ArrayList集合、LinkedList集合等集合实现了List接口;常用的HashSet集合,LinkedHashSet集合等集合实现了Set接口。
1、Collection接口及常用方法:
Collection接口是所有单列集合的最顶层接口,定义所有单列集合(即图片中最下层的所有集合)共性的方法:
public boolean add(E e):把给定的对象添加到当前的集合中
public void clear():清空集合所有的元素
public boolean remove(E e):把给定的对象从当前集合中删除
public boolean contains(E e):判断当前的集合中是否包含给定的对象
public boolean isEmpty():判断集合是否为空
public int size():返回集合中元素的个数
public Object[] toArray():把集合中的元素存放到数组中
2、List接口及常用方法:
List接口的特点:
集合中的元素有序、且可重复;
集合中的每个元素都有其对应的顺序索引,容器中的元素都对应一个整数型的序号记载其在容器中的位置,可以根据序号存取容器中的元素,并包含了一些带索引的方法。
public void add(int index, Object ele):将指定的元素添加在指定的索引位置(index)上
public boolean addAll(int index, Collection eles):在指定索引位置,加上一个集合
public Object get(int index):获取指定位置上的元素
public Object remove(int index):删除指定索引位置上的元素
public Object set(int index, Object ele):设置指定的索引位置(index)的位置的元素为ele
public int indexOf(Object obj):返回指定对象obj在集合中首次出现的位置,没有则返回-1;
public int lastIndexOf(Object obj):返回指定对象obj在集合最后一次出现的位置,没有则返回-1;
public List subList(int fromIndex, int toIndex):返回从fromIndex到toIndex结束的子list,左闭右开的区间;
(1)ArrayList:
ArrayList是List接口的实现类,可以简单看作可变长度的数组。
ArrayList的特点:1、ArrayList集合长度可变;2、线程不安全;3、查询效率高,增删效率低。
参考上述方法即可;4、底层为Object数组;
(2)LinkedList:
LinkedList也是List接口的实现类。
LinkedList的特点:LinkedList底层是一个双向链表,查询慢,增删快;
新增方法:
public void addFirst(E e):在列表的开头新增一个指定元素e
public void addLast(E e):在列表的最后位置新增一个指定元素e
public void push(E e):等效addFirst,将指定元素放入首位
public E getFirst():获取第一个元素
public E getLast():获取最后一个元素
public E removeFirst():删除第一个元素
public E removeLast():删除最后一个元素
public E pop():弹出列表最后一个元素
public boolean isEmpty():判断是否为空,如果为空,返回true
import java.util.LinkedList;
public class Test_LinkedList {
public static void main(String[] args) {
LinkedList<Integer> list = new LinkedList<>();
list.add(1);
list.add(2);
list.add(3);
System.out.println("初始集合:");
System.out.println(list);
System.out.println("集合前放入0");
list.addFirst(0);
System.out.println(list);
System.out.println("集合前放入-1");
list.push(-1);
System.out.println(list);
System.out.println("取出第一个值:");
System.out.println(list.pop());
System.out.println("利用pop()弹出所有元素");
while(list.isEmpty()!=true){
System.out.println(list.pop());
}
System.out.println("最后的集合:"+list);
}
}
结果:
初始集合:
[1, 2, 3]
集合前放入0
[0, 1, 2, 3]
集合前放入-1
[-1, 0, 1, 2, 3]
取出第一个值:
-1
利用pop()弹出所有元素
0
1
2
3
最后的集合:[]
(3)Vector:
Vector也是List接口的一个实现类。
Vector的特点:1、vector底层是一个数组;2、增加同步检查,所以线程安全,但效率低;
3、Set接口及常用方法:
Set接口的特点:1、不允许存储重复的元素(因为重写了equals方法和hashCode方法);
(1)HashSet:
HashSet的特点:1、不允许存储重复元素;2、是一个无序的集合,存储元素和取出元素的顺序可能不一致;3、底层是哈希表存储结构;4、允许使用null元素,但要保证元素的唯一性;
哈希表结构:
本质底层依赖两个方法:
int hashCode()
boolean equals(Object obj)
为什么重写equals的同时也要重写hashcode:
因为在不重写equals时比较的是两个地址值;当重写了equals时,假设两个对象,重写了其equals方法,其相等条件是属性相等,就返回true。如果不重写hashcode方法,其返回的依然是两个对象的内存地址值,必然不相等。这就出现了equals方法相等,但是hashcode不相等的情况。这不符合hashcode的规则。重写equals()方法就必须重写hashCode()方法主要是针对HashSet和Map集合类型。集合框架只能存入对象(对象的引用(基本类型数据:自动装箱))。
在向HashSet集合中存入一个元素时,HashSet会调用该对象(存入对象)的hashCode()方法来得到该对象的hashCode()值,然后根据该hashCode值决定该对象在HashSet中存储的位置。简单的说:HashSet集合判断两个元素相等的标准是:两个对象通过equals()方法比较相等,并且两个对象的HashCode()方法返回值也相等。如果两个元素通过equals()方法比较返回true,但是它们的hashCode()方法返回值不同,HashSet会把它们存储在不同的位置,依然可以添加成功。
(2)LinkedHashSet:底层由哈希表+链表构成,由链表保证元素有序,由哈希表保证元素唯一。
4、Collections类的常用方法:
排序方法:
void reverse(List list)//反转
void shuffle(List list)//随机排序
void sort(List list)//按自然排序的升序排序
void sort(List list, Comparator c)//定制排序,由Comparator控制排序逻辑
void swap(List list, int i , int j)//交换两个索引位置的元素
void rotate(List list, int distance)//旋转。当distance为正数时,将list后distance个元素整体移到前面。当distance为负数时,将 list的前distance个元素整体移到后面。
替换查找方法:
int binarySearch(List list, Object key)//对List进行二分查找,返回索引,注意List必须是有序的
int max(Collection coll)//根据元素的自然顺序,返回最大的元素。 类比int min(Collection coll)
int max(Collection coll, Comparator c)//根据定制排序,返回最大元素,排序规则由Comparatator类控制。类比int min(Collection coll, Comparator c)
void fill(List list, Object obj)//用指定的元素代替指定list中的所有元素。
int frequency(Collection c, Object o)//统计元素出现次数
int indexOfSubList(List list, List target)//统计target在list中第一次出现的索引,找不到则返回-1,类比int lastIndexOfSubList(List source, list target).
boolean replaceAll(List list, Object oldVal, Object newVal)// 用新元素替换旧元素
需要注意的是::
1、binarySearch()
方法:默认的是集合是有序的,如果集合不是顺序排列,则有可能会找不到。
import java.util.ArrayList;
import java.util.Collections;
public class Test2_Collections {
public static void main(String[] args) {
ArrayList<Integer> arrayList = new ArrayList<Integer>();
arrayList.add(-1);
arrayList.add(3);
arrayList.add(3);
arrayList.add(-5);
arrayList.add(7);
arrayList.add(4);
arrayList.add(-9);
arrayList.add(-7);
ArrayList<Integer> arrayList2 = new ArrayList<Integer>();
arrayList2.add(-3);
arrayList2.add(-5);
arrayList2.add(7);
System.out.println("原始数组:");
System.out.println(arrayList);
System.out.println("Collections.binarySearch(arrayList, 7):没排列的结果");
System.out.println(Collections.binarySearch(arrayList, 7));
System.out.println("Collections.binarySearch(arrayList, 7):升序排列后的结果");
// 对List进行二分查找,返回索引,List必须是有序的
Collections.sort(arrayList);//升序
System.out.println(arrayList);
System.out.println(Collections.binarySearch(arrayList, 7));
}
}
结果:
原始数组:
[-1, 3, 3, -5, 7, 4, -9, -7]
Collections.binarySearch(arrayList, 7):没排列的结果
-9
Collections.binarySearch(arrayList, 7):升序排列后的结果
[-9, -7, -5, -1, 3, 3, 4, 7]
7
2、sort()
方法:使用前提是,插入里面的元素必须实现Compareable,重写接口中的compareTo方法来自定义排序;一般常用的引用类型数据如:String类,自身含有CompareTo方法,所以直接引用就好;而其他的自定义类型就需要重写方法来实现。
(1)String 本身含有compareTo方法,所以可以直接调用sort方法,按自然顺序排序,即升序排序;
(2)调用sort(List list, Comparator c)
方法,可以先实现Comparable接口新建一个比较类(例如:MyCompare类),将其传入sort方法中,按新类中的比较规则排序;
(3)用匿名内部类来实现MyCompare类的作用;
(4)传入对象已经实现了Comparable接口,有了compareTo方法;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class Test_ComepareTo {
public static void main(String[] args) {
List<String> listS = new ArrayList<String>();
List<Person1> list1 = new ArrayList<Person1>();
List<Person2> list2 = new ArrayList<Person2>();
List<Person3> list3 = new ArrayList<Person3>();
//一.将String类型的变量插入到listS中并排序
//listS中的对象String 本身含有compareTo方法,所以可以直接调用sort方法,按自然顺序排序,即升序排序
listS.add("5");
listS.add("2");
listS.add("9");
Collections.sort(listS);
//二.将Person1类的对象插入到list1中并排序
//将已创建的实现了Comparator接口的比较类MyCompare传入Collections的sort方法中即可实现依照MyCompare类中的比较规则。
Person1 a1 = new Person1();
Person1 b1 = new Person1();
Person1 c1 = new Person1();
a1.setName("a1"); a1.setAge(44);
b1.setName("b1"); b1.setAge(55);
c1.setName("b1"); c1.setAge(33);
list1.add(a1);
list1.add(b1);
list1.add(c1);//Collections类的sort方法要求传入的第二个参数是一个已实现Comparator接口的比较器
Collections.sort(list1, new MyCompare());
//三.将Person2类的对象插入到list2中并排序
//其实原理和上面的二类似,只是没有单独创建MyCompare类,而是用匿名内部类来实现Comparator接口里面的具体比较。
Person2 a2 = new Person2();
Person2 b2 = new Person2();
Person2 c2 = new Person2();
a2.setName("a2"); a2.setAge(66);
b2.setName("b2"); b2.setAge(33);
c2.setName("b2"); c2.setAge(22);
list2.add(a2);
list2.add(b2);
list2.add(c2); //Collections类的sort方法要求传入的第二个参数是一个已实现Comparator接口的比较器
Collections.sort(list2,new Comparator<Person2>(){
@Override
public int compare(Person2 a2, Person2 b2) {
//a2.getOrder().compareTo(b2.getOrder()是升序排列的
return a2.getOrder().compareTo(b2.getOrder());
}
});
//四.将Person3类的对象插入到list3中并排序
//被排序的类Person3实现了Comparable接口,在类Person3中通过重载compareTo方法来实现具体的比较,所以可以直接调用sort(List list)方法。
Person3 a3 = new Person3();
Person3 b3 = new Person3();
Person3 c3 = new Person3();
a3.setName("a3"); a3.setAge(77);
b3.setName("b3"); b3.setAge(55);
c3.setName("b3"); c3.setAge(99);
list3.add(a3);
list3.add(b3);
list3.add(c3);
Collections.sort(list3);//Collections类的sort方法要求传入的List中的对象是已实现Comparable接口的对象
System.out.println(listS);
System.out.println(list1);
System.out.println(list3);
System.out.println(list2);
}
}
class Person1{
private String name;
private Integer age;
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override//重载了Object类里的toString方法,使之可以按照我们要求的格式打印
public String toString() {
return "name is "+name+" age is "+ age;
}
}
class MyCompare implements Comparator<Person1> {
@Override//重载了Comparator接口里面的compare方法实现具体的比较
public int compare(Person1 o1, Person1 o2) {
//一般o2-o1是降序,o1-o2是升序
// return o2.getAge()-o1.getAge();//[name is b1 age is 55, name is a1 age is 44, name is b1 age is 33]
return o1.getAge()-o2.getAge();//[name is b1 age is 33, name is a1 age is 44, name is b1 age is 55]
}
}
class Person2{
private String name;
private Integer age;
public void setName(String name) {
this.name = name;
}
public Integer getOrder() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override//重载了Object类里的toString方法,使之可以按照我们要求的格式打印
public String toString() {
return "name is "+name+" age is "+age;
}
}
class Person3 implements Comparable<Person3>{
private String name;
private Integer age;
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override//重载了Object类里的toString方法,使之可以按照我们要求的格式打印
public String toString() {
return "name is "+name+" age is "+age;
}
@Override//重载了Comparable接口里的compareTo方法来实现具体的比较
public int compareTo(Person3 a) {
return this.age.compareTo(a.getAge());
}
}
结果:
[2, 5, 9]
[name is b1 age is 33, name is a1 age is 44, name is b1 age is 55]
[name is b3 age is 55, name is a3 age is 77, name is b3 age is 99]
[name is b2 age is 22, name is b2 age is 33, name is a2 age is 66]
而对于所有的排序方法,其实最后都要重写compareTo()
方法。
其他方法:
emptyXxx(): 返回一个空的、不可变的集合对象,此处的集合既可以是List,也可以是Set,还可以是Map。
singletonXxx(): 返回一个只包含指定对象(只有一个或一个元素)的不可变的集合对象,此处的集合可以是:List,Set,Map。
unmodifiableXxx(): 返回指定集合对象的不可变视图,此处的集合可以是:List,Set,Map。
import java.util.*;
public class Test3_Collections {
public static void main(String[] args) {
ArrayList<Integer> arrayList = new ArrayList<Integer>();
arrayList.add(-1);
arrayList.add(3);
arrayList.add(3);
arrayList.add(-5);
arrayList.add(7);
arrayList.add(4);
arrayList.add(-9);
arrayList.add(-7);
HashSet<Integer> integers1 = new HashSet<>();
integers1.add(1);
integers1.add(3);
integers1.add(2);
Map scores = new HashMap();
scores.put("语文" , 80);
scores.put("Java" , 82);
//Collections.emptyXXX();创建一个空的、不可改变的XXX对象
List<Object> list = Collections.emptyList();
System.out.println(list);//[]
Set<Object> objects = Collections.emptySet();
System.out.println(objects);//[]
Map<Object, Object> objectObjectMap = Collections.emptyMap();
System.out.println(objectObjectMap);//{}
//Collections.singletonXXX();
List<ArrayList<Integer>> arrayLists = Collections.singletonList(arrayList);
System.out.println(arrayLists);//[[-1, 3, 3, -5, 7, 4, -9, -7]]
//创建一个只有一个元素,且不可改变的Set对象
Set<ArrayList<Integer>> singleton = Collections.singleton(arrayList);
System.out.println(singleton);//[[-1, 3, 3, -5, 7, 4, -9, -7]]
Map<String, String> nihao = Collections.singletonMap("1", "nihao");
System.out.println(nihao);//{1=nihao}
//unmodifiableXXX();创建普通XXX对象对应的不可变版本
List<Integer> integers = Collections.unmodifiableList(arrayList);
System.out.println(integers);//[-1, 3, 3, -5, 7, 4, -9, -7]
Set<Integer> integers2 = Collections.unmodifiableSet(integers1);
System.out.println(integers2);//[1, 2, 3]
Map<Object, Object> objectObjectMap2 = Collections.unmodifiableMap(scores);
System.out.println(objectObjectMap2);//{Java=82, 语文=80}
}
}
结果:
[]
[]
{}
[[-1, 3, 3, -5, 7, 4, -9, -7]]
[[-1, 3, 3, -5, 7, 4, -9, -7]]
{1=nihao}
[-1, 3, 3, -5, 7, 4, -9, -7]
[1, 2, 3]
{Java=82, 语文=80}
引用文章:Collections类常用方法总结
5、Arrays类的常用方法:
排序 : sort()
sort(int[] a)//方法按照数字顺序排列指定的数组。
sort(int[] a,int fromIndex,int toIndex)//按升序排列数组的指定范围
parallelSort(int[] a)//按照数字顺序排列指定的数组(并行的)。同sort方法一样也有按范围的排序
查找 : binarySearch()
比较: equals()
填充 : fill()
转列表: asList()
转字符串 : toString()
复制: copyOf()
对字符串排序,依次比较每个字符:
String[] strs = { "abcdehg", "abcdefg", "abcdeag" };
Arrays.sort(strs);
System.out.println(Arrays.toString(strs));//[abcdeag, abcdefg, abcdehg]
6、Map<k,v>集合
Map集合特点:(1)是一个双列集合,每一个元素包含两个值(键和值);(2)key和value的数据类型可以相同,可以不同;(3)key不允许重复,value可以重复;(4)key与value是一一对应的;
常用方法:
(1)HashMap:
特点:(1)底层是一个哈希表,查询效率高;JDK1.8之前:数组+单向链表;JDK1.8之后:数组+单向链表/红黑树(链表长度超过8时)(2)是一个无序集合,存储和取出的顺序有可能不同;(3)key-value可以为null,但最多只能为一个null;(4)不支持线程同步,即可以有多个线程同时写HashMap,可能导致数据不一致,如果需要同步可以使用Collection的synchronizedMap方法使其同步。
(2)LinkedHashMap:
特点:(1)底层是哈希表+链表;(2)是一个有序集合,存取顺序相同;
(3)遍历方法:
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class Test_Map {
public static void main(String[] args) {
Map<Integer, String> map = new HashMap<Integer, String>();
map.put(1, "a");
map.put(2, "b");
map.put(3, "ab");
map.put(4, "ab");
map.put(4, "ab");
System.out.println(map.size());
/*
1、调用keySet()方法,获取所有元素的key值,存入set集合
2、遍历set集合,获取每一个key值
3、通过get(key)获取value值
*/
System.out.println("第一种:通过Map.keySet遍历key和value:");
for (Integer in : map.keySet()) {
//map.keySet()返回的是所有key值,并存放到一个set集合中,返回值为一个set集合
String str = map.get(in);//得到每个key对应的value值
System.out.println(in + " " + str);
}
/*
1、通过iterator()方法获取迭代器
2、调用hasNext()判断有没有下一个元素,作为循环条件
3、调用next()获取Map集合中的所有元素
4、通过getKey()和getValue()分别取值
*/
System.out.println("第二种:通过Map.entrySet使用iterator遍历key和value:");
Iterator<Map.Entry<Integer, String>> it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<Integer, String> entry = it.next();
System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
}
/*
1、调用entrySet()方法,获取到集合内多个entry对象存入set集合
2、调用遍历set集合获取每个entry对象
3、通过getKey()和getValue()分别取值
*/
System.out.println("第三种:键值对,通过Map.entrySet遍历key和value");
for (Map.Entry<Integer, String> entry : map.entrySet()) {
//Map.entry<Integer,String> 映射项(键-值对) 有几个方法:用上面的名字entry
//entry.getKey() ;entry.getValue(); entry.setValue();
//map.entrySet() 返回此映射中包含的映射关系的 Set视图。
System.out.println("key= " + entry.getKey() + " and value= "
+ entry.getValue());
}
/*
通过values()方法,但只能获取到value值,无法获取key值
*/
System.out.println("第四种:通过Map.values()遍历所有的value,但不能遍历key");
for (String v : map.values()) {
System.out.println("value= " + v);
}
}
}
结果:
4
第一种:通过Map.keySet遍历key和value:
1 a
2 b
3 ab
4 ab
第二种:通过Map.entrySet使用iterator遍历key和value:
key= 1 and value= a
key= 2 and value= b
key= 3 and value= ab
key= 4 and value= ab
第三种:键值对,通过Map.entrySet遍历key和value
key= 1 and value= a
key= 2 and value= b
key= 3 and value= ab
key= 4 and value= ab
第四种:通过Map.values()遍历所有的value,但不能遍历key
value= a
value= b
value= ab
value= ab