今天开始学java的集合相关知识。
- 集合概念
- 集合 API
- Collection接口
- List 接口及实现类
- List接口集合迭代
- Set 接口
- Set 接口集合迭代
- Map 接口
- Collections类
集合的概念
在我们之前所学的知识中,可以存储一组元素的工具有数组,但数组一旦定义了长度就不能更改,优点是数据查找周期短,但我们经常会存储一些会变长的数据,这时我们就需要可以动态增长长度的容器,那就可以使用集合(容器)。
集合 API
Java中集合是由很多接口、抽象类和实现类组成的。
Collection接口
Collection接口定义了一些存储一组对象的方法,他的子接口Set和List分别定义了存储方式。
import java.util.ArrayList;
import java.util.Collection;
public class Demo1 {
/*
集合
数组一旦定义了长度就不能更改,有点是数据查找周期短
集合是一个可以动态增长长度的容器,一个集合应该只存放一种类型数据(只能存放引用类型数据)
*/
public static void main(String[] args) {
Collection<String> a1=new ArrayList<>();
a1.add("a");
a1.add("b");
a1.add("c");
a1.add("d");
Collection<String> a2=new ArrayList<>();
a2.add("d");
a2.add("e");
a2.add("f");
a2.add("b");
a1.addAll(a2);//将a2元素加入a1
a1.remove("c");//移除指定元素
a1.removeAll(a2);//移除a1中与a2中相同的元素
System.out.println(a1.size());//输出长度
System.out.println(a1.isEmpty());//判断是否为空
System.out.println(a1.equals(a2));//比较内容是否相同
System.out.println(a1.contains("a"));//判断是否包含指定元素
System.out.println(a1);
System.out.println(a2);
String[] s=a2.toArray(a1.toArray(new String[a2.size()]));//将集合转换为String数组
Object []o=a2.toArray();//将集合转换为Object数组
}
}
List 接口及实现类
List接口继承了Collection接口,有三个实现类,分别是:ArrayList类,LinkedList类,Vector类。是单列集合,可以存放重复的元素。
这三个实现类分别的作用和特点是:
ArrayList:底层创建是一个Object数组,会先创建一个长度为10的数组,需要连续的内存空间,内存使用效率低。当插入元素超过数组长度时,会新创建一个长度为原数组长度1.5倍的数组(使用底层grow()方法)。特点是数据插入,删除周期长,但查询速度快
LinkedList:底层是一个链表,内存使用效率高。特点是插入,删除周期短,但查询周期长。
Vector: 底层是数组,相较于ArrayList和LinkedList有线程安全的特点。
下面分别是这三个实现类的示例代码:
import java.util.ArrayList;
import java.util.List;
public class Demo2 {
/*
ArrayList
底层创建是一个Object数组,会先创建一个长度为10的数组,需要连续的内存空间,内存使用效率低
当插入元素超过数组长度时,会新创建一个长度为原数组长度1.5倍的数组(使用底层grow()方法)
特点是数据插入,删除周期长,但查询速度快
*/
public static void main(String[] args) {
//List<String> a=new ArrayList<>();
ArrayList<String> a=new ArrayList<>();
a.add("a");
a.add("b");
a.add("c");
a.add("d");
a.add("e");
a.add("f");
a.add("X");
a.add("X");
a.add("X");
a.add("X");
a.add("X");
a.add("X");
System.out.println( a.isEmpty());//判断是否为空
a.remove(2);//移除指定位置的元素
System.out.println(a.size());//数组长度
System.out.println(a.get(4));//返回指定位置元素
a.set(1,"A");//替换
System.out.println(a);
}
}
import java.util.LinkedList;
public class Demo4 {
/*
LinkedList
底层是一个链表,内存使用效率高
特点是插入,删除周期短,但查询周期长
*/
public static void main(String[] args) {
LinkedList<String> a=new LinkedList<>();
a.add("a");
a.add("b");
a.add("c");
a.add("d");
a.add("a");
a.remove(2);//删除指定元素并返回该元素
System.out.println(a.get(3));//输出指定元素
a.set(1,"X");//替换指定元素
System.out.println(a);
}
}
import java.util.Vector;
public class Demo3 {
/*
Vector
底层是数组,相较于ArrayList和LinkedList有线程安全的特点
*/
public static void main(String[] args) {
Vector<String> a=new Vector<>();
a.add("a");
a.add("b");
a.add("c");
a.add("d");
a.add("e");
a.add("a");
a.add("a");
System.out.println(a.get(0));
}
}
List接口集合迭代
List接口集合迭代有四种方式:for循环,增强for循环,Iterator迭代器,ListIterator迭代器(只支持对List接口下的实现类)。
下面是使用方法:
import java.util.ArrayList;
import java.util.Iterator;
public class Demo5 {
/*
Iterator
迭代器迭代,返回一个ArrayList中的内部类对象,实现Iterator接口
次内部类专门对集合进行遍历时的控制
为集合设计的遍历工具
*/
public static void main(String[] args) {
ArrayList<String> a=new ArrayList<>();
a.add("a");
a.add("b");
a.add("c");
a.add("d");
a.add("e");
a.add("f");
a.add("X");
a.add("X");
a.add("X");
a.add("X");
a.add("X");
a.add("X");
Iterator<String> iterator=a.iterator();
while (iterator.hasNext()){//hasNext()用来判断Iterator是否还有后续
String b=iterator.next();
if (b.equals("X")){
iterator.remove();
}
}
System.out.println(a);
}
}
import java.util.ArrayList;
import java.util.Iterator;
import java.util.ListIterator;
public class Demo10 {
/*
ListIterator
为List接口下的集合设计的迭代器
*/
public static void main(String[] args) {
ArrayList<String> a=new ArrayList<>();
a.add("a");
a.add("b");
a.add("c");
a.add("d");
a.add("e");
a.add("f");
a.add("X");
a.add("X");
a.add("X");
a.add("X");
a.add("X");
a.add("X");
ListIterator<String> listiterator=a.listIterator(2) ;//可以从指定的位置开始遍历
while (listiterator.hasNext()){//hasNext()用来判断Iterator是否还有后续
String b=listiterator.next();
System.out.println(b);
}
System.out.println();
while (listiterator.hasPrevious()){//hasNext()用来判断Iterator是否还有后续
String b=listiterator.previous();//从后向前遍历
System.out.println(b);
}
System.out.println(a);
}
}
Set接口
Set接口继承Collection接口,也是单列集合,但不能存放相同元素,是无序的,并且Set中的元素是没有索引的。set有两个实现类:HashSet和TreeSet。
HashSet:不能存放重复元素,用equals()方法来比较存放,是无序的。底层数据是依赖哈希表和链表。
TreeSet:不能存放重复元素。底层数据是二叉树,有序的(存储的对象必须实现Comparable接口)。
如何排序:HashCode()和equals()
Hashcode():先用HashCode进行比较,将元素转换成一个int值进行比较,如果值相同,再使用equals()进行比较。
equals():比较元素的内容,最安全。
import java.util.HashSet;
public class Demo6 {
/*
HashSet
无序的,存放不同的元素,
使用equals方法比较,都返回false
底层数据结构是哈希表和链表
哈希表依赖于哈希值存储
*/
public static void main(String[] args) {
HashSet<String> hashSet=new HashSet<>();
hashSet.add("a");
hashSet.add("b");
hashSet.add("c");
hashSet.add("d");
hashSet.add("e");
hashSet.add("e");
hashSet.add("e");
System.out.println(hashSet);
}
}
import java.util.TreeSet;
public class Demo7 {
/*
TreeSet
底层数据是二叉树
存放不同元素,有序的(存储的对象必须实现Comparable接口)
*/
public static void main(String[] args) {
TreeSet<String> treeSet=new TreeSet<>();
treeSet.add("x");
treeSet.add("a");
treeSet.add("e");
treeSet.add("f");
treeSet.add("c");
treeSet.add("a");
System.out.println(treeSet);
Car car1=new Car(1,"奥迪");
Car car2=new Car(2,"宝马");
Car car3=new Car(3,"雷克萨斯");
Car car4=new Car(4,"兰博基尼");
TreeSet<Car> treeSet1=new TreeSet<>();
treeSet1.add(car2);
treeSet1.add(car4);
treeSet1.add(car1);
treeSet1.add(car3);
System.out.println(treeSet1);
}
}
Set 接口集合迭代
Set 接口集合迭代的方式有两种:增强for循环,迭代器迭代。
HashSet的迭代:
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class Demo17 {
/*
Set 接口集合迭代
Set 接口集合迭代的方式有两种:增强for循环,迭代器迭代。
*/
public static void main(String[] args) {
Set<String> set=new HashSet<>();
set.add("a");
set.add("b");
set.add("c");
set.add("d");
set.add("a");
Iterator<String> iterator=set.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
TreeSet的迭代:
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;
public class Demo18 {
public static void main(String[] args) {
Set<String> set=new TreeSet<>();
set.add("a");
set.add("b");
set.add("c");
set.add("d");
set.add("a");
Iterator<String> iterator=set.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
Map 接口
双列集合,一个键指向一个值,键不能重复,但是值可以重复。
Map接口的三个实现类是HashMap、HashTable、TreeMap。
HashMap:底层结构是java8,有三种数据结构:1.数组、2.链表、3.红黑树;存放键是无序的,可以存放一个null键。遍历方式有两种:一是通过键找值,通过遍历键来遍历值;二是根据键值对对象找键和值,通过遍历所有键值对对象的集合,获取每一个键值对对象,找到对象的键和值。
HashMap添加键的过程:添加一个元素时,会通过Hash计算得一个hash值,封装到一个Node对象中,将对象存储到对应位置。但有新元素存入时,没有相同地址的元素存入新地址,相同元素的地址存入存入之前元素的后一位,当链表的长度达到8,且哈希数组的长度达到64时,链表会转为红黑树。哈希数组的默认长度为16,负载因子为0.75,如果哈希数组发生扩容,每次扩容为原来的两倍。
Hashtable:相较HashMap,实现了线程安全、同步。不能存储null值。
TreeTable:存放的键有序。存储的对象必须实现Comparable接口。
import java.util.HashMap;
import java.util.TreeMap;
public class Demo9 {
/*
HashMap
双列集合,键不能重复,值可以重复,不能存放重复元素,
HashMap是如何排序的
HashCode()和equals();
Hashcode():先用HashCode进行比较,将元素转换成一个int值进行比较,如果值相同,再使用equals()进行比较
equals():比较元素的内容,最安全
*/
public static void main(String[] args) {
TreeMap<Integer,String> map=new TreeMap<>();
map.put(2,"金毛");
map.put(1,"柯基");
map.put(4,"哈士奇");
map.put(2,"金毛");
System.out.println(map);
Dog dog1=new Dog(2,"金毛");
Dog dog2=new Dog(1,"柯基");
Dog dog3=new Dog(4,"哈士奇");
Dog dog4=new Dog(2,"金毛");
TreeMap<Dog,String> map2 = new TreeMap<>();
map2.put(dog2,"123");
map2.put(dog3,"223");
map2.put(dog1,"323");
map2.put(dog4,"423");
System.out.println(map2);
}
}
import java.util.Objects;
public class Dog implements Comparable<Dog>{
int age;
String name;
public Dog(int age, String name) {
this.age = age;
this.name = name;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Dog dog = (Dog) o;
return age == dog.age &&
Objects.equals(name, dog.name);
}
@Override
public int hashCode() {
return Objects.hash(age, name);
}
@Override
public int compareTo(Dog o) {
return this.age-o.age;
}
}
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class Demo11 {
/*
HashMap的遍历
1.通过键找值
2.通过键值对对象找键和值(推荐,尤其在容量大时)
*/
public static void main(String[] args) {
HashMap<Integer,String> hashMap=new HashMap<>();
hashMap.put(2,"奥迪");
hashMap.put(1,"宝马");
hashMap.put(3,"雷克萨斯");
System.out.println(hashMap);
for (int s:hashMap.keySet()) {
String a= hashMap.get(s);
System.out.println(s+"="+a);
}
Set<Map.Entry<Integer,String>> set=hashMap.entrySet();
for (Map.Entry<Integer,String>mappentry:set){
System.out.println(mappentry.getKey()+"="+mappentry.getValue());
}
}
}
Collections类
Collections为集合提供的一个工具类,类似于Arrays数组。
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
public class Demo12 {
/*
Collections
为集合提供的一个工具类,类似于Arrays数组
int...a
可变长度参数
要写在参数列表的最后,一个参数列表只能有一个可变长度参数
*/
public static void main(String[] args) {
//HashMap<Integer,String> hashMap=new HashMap<>();
ArrayList<Integer> arrayList=new ArrayList<>();
arrayList.add(1);
arrayList.add(2);
arrayList.add(3);
arrayList.add(4);
ArrayList<Integer> arrayList2=new ArrayList<>();
arrayList2.add(0);
arrayList2.add(0);
arrayList2.add(0);
arrayList2.add(0);
arrayList2.add(0);
Collections.addAll(arrayList,3);//将指定元素添加到指定集合
Collections.binarySearch(arrayList,2);//使用二分查找查找指定元素
Collections.sort(arrayList);//排序
Collections.swap(arrayList,3,1);//将数组内元素位置替换
Collections.copy(arrayList2,arrayList);//将数组2的元素复制到数组1中,注意:数组1的size要比数组二大
Collections.emptyList();//返回一个空数组,不能添加数据,常用来进行逻辑比较
Collections.fill(arrayList,6);//用指定元素替换指定集合中所有元素
System.out.println(Collections.max(arrayList2));//输出集合中最大元素
System.out.println(Collections.min(arrayList2));//输出集合中最小元素
Collections.reverse(arrayList2);//反转指定集合的元素顺序
Collections.shuffle(arrayList2);//对指定集合随机排序
System.out.println(arrayList);
System.out.println(arrayList2);
test(10,1,2,3,4,5,6);
}
public static void test(int a,int...b){
System.out.println(a);
System.out.println(b);
}
}