目录
1.集合的概念
所有的集合类和集合接口都在java.util包下。
在内存中申请一块空间用来存储数据,在Java中集合就是替换掉定长的数组的一种引用数据类型
集合和数组的区别:
2.List接口及其实现类:
1)ArrayList:底层数据结构是数组,查询快,增删慢,线程不安全,效率高,可以存储重复元素
2)LinkedList 底层数据结构是链表,查询慢,增删快,线程不安全,效率高,可以存储重复元素
3)Vector:底层数据结构是数组,查询快,增删慢,线程安全,效率低,可以存储重复元素
ArrayList:
ArrayList 可以存储重复元素,底层是数组实现,添加元素的类型可以 是任意类型。 所有java中的集合类都支持自定义类型(泛型,把类型当做参数传递) ArrayList<String> 定义时,为集合中可以存储的数据设定一个类型,必须是 类类型。
好处:一个集合只能存储一种相同的数据类型。
package list;
import java.util.ArrayList;
public class ArrayListDemo {
public static void main(String[] args){
/* ArrayList 可以存储重复元素,底层是数组实现,添加元素的类型可以
是任意类型。
所有java中的集合类都支持自定义类型(泛型,把类型当做参数传递)
ArrayList<String> 定义时,为集合中可以存储的数据设定一个类型,必须是
类类型。
好处:一个集合只能存储一种相同的数据类型。*/
ArrayList<String> arrayList=new ArrayList<>();
arrayList.add("a");//在末尾添加元素
arrayList.add("b");
arrayList.add("c");
arrayList.add("d");
arrayList.add("e");
arrayList.add("f");
arrayList.add("a");
arrayList.add("b");
arrayList.add("a");
arrayList.remove("b");//删除集合中第一个遇到的指定元素
System.out.println(arrayList);//[a, c, d, e, f, a, b, a]
String s=arrayList.remove(1);//移除指定位置的元素并返回。
System.out.println(s);//c
System.out.println(arrayList);//[a, d, e, f, a, b, a]
arrayList.add(1, "c");//在指定位置添加元素,注意不能超过集合的size.
System.out.println(arrayList);//[a, c, d, e, f, a, b, a]
System.out.println(arrayList.contains("a"));//true 检测集合是否含有指定的元素
System.out.println(arrayList.get(1));//c 获取指定位置的元素
System.out.println(arrayList.isEmpty());//false 检测集合是否为空
}
}
ArrayList的常用方法
add(E element) 添加元素 注意:是在末尾添加元素。
add(int index, E element) 在指定的位置添加元素 注意:不能超过集合的size
get(int index) 获得指定位置的元素
indexOf(Object o) 返回指定元素在集合中第一次出现的索引。
lastIndexOf(Object o)
remove(int index) 删除并返回指定位置元素
package list;
import java.util.ArrayList;
import java.util.ListIterator;
public class ArrayListDemo1 {
public static void main(String[] args){
ArrayList<String> arrayList=new ArrayList<>();
arrayList.add("a");
arrayList.add("b");
arrayList.add("a");
arrayList.add("c");
arrayList.add("a");
arrayList.add("d");
arrayList.add("e");
arrayList.add("a");
/* //for循环来指定的元素
for(int i=0;i<arrayList.size();i++){
if(arrayList.get(i).equals("a")){
arrayList.remove(i);
i--;
}
}
System.out.println(arrayList);*/
/* //通过增强for循环来删除指定的元素
for(String s:arrayList){
if(s.equals("a")){
arrayList.remove("a");
}
}*/
/*//通过迭代器来删除指定的元素
ListIterator<String> it=arrayList.listIterator();
while(it.hasNext()){
String s=it.next();
if(s.equals("a")){
it.remove();
}
}
System.out.println(arrayList);*/
/*//迭代器2
ListIterator<String> it=arrayList.listIterator(5);
while(it.hasPrevious()){
String s=it.previous();
if(s.equals("a")){
it.remove();
}
}
System.out.println(arrayList);*/
}
}
上述代码是Lsit接口集合迭代的三种方法:
for循环法
增强for循环法
迭代器遍历
LinkedList:
LinkedList和ArrayList方法一样,只是底层实现不一样。ArrayList底层为数组存储,LinkedList是以双向链表存储。LinkedList集合没有初始化容量。最初这个链表中没有任何元素。first和last引用都是null。
链表的优点:
由于链表上的元素在空间存储上内存地址不连续。
所以随机增删元素的时候不会有大量元素位移,因此随机增删效率较高。
在以后的开发中,如果遇到随机增删集合中元素的业务比较多时,建议
使用LinkedList。
链表的缺点:
不能通过数学表达式计算被查找元素的内存地址,每一次查找都是从头
节点开始遍历,直到找到为止。所以LinkedList集合检索/查找的效率
较低。
ArrayList:把检索发挥到极致。(末尾添加元素效率还是很高的。)
LinkedList:把随机增删发挥到极致。
加元素都是往末尾添加,所以ArrayList用的比LinkedList多。
Vector:
1、底层也是一个数组。
2、初始化容量:10
3、怎么扩容的?
扩容之后是原容量的2倍。
10--> 20 --> 40 --> 80
4、Vector中所有的方法都是线程同步的,都带有synchronized关键字,
是线程安全的。效率比较低,使用较少了。
5、怎么将一个线程不安全的ArrayList集合转换成线程安全的呢?
使用集合工具类:
java.util.Collections;
java.util.Collection 是集合接口。
java.util.Collections 是集合工具类。
Collections.synchronizedList();//将及格转换为线程安全的。
3.Set接口:
3.1概述:
-
Set集合也是一个接口,继承自Collection,与List类似,都需要通过实现类来进行操作。
-
特点
-
不允许包含重复的值
-
没有索引(就不能使用普通的for循环进行遍历。
-
package set; import java.util.HashSet; public class HashDemo1 { public static void main(String[] args){ HashSet<String> hashSet=new HashSet<>(); hashSet.add("x"); hashSet.add("a"); hashSet.add("g"); hashSet.add("a"); hashSet.add("x"); hashSet.add("c"); hashSet.add("k"); System.out.println(hashSet);//HashSet可以去除重复的元素 //因为HashSet是无序的所以没有索引 hashSet.remove("x"); System.out.println(hashSet); System.out.println(hashSet.isEmpty()); } }
-
3.2哈希值
set集合的去重原理使用的是哈希值
哈希值就是JDK根据对象地址 或者 字符串 或者数值 通过自己内部的计算出来的一个整数类型数据
public int hashCode()
- 用来获取哈希值,来自于Object顶层类
-
对象的哈希值特点
-
同一个对象多次调用
hashCode()
方法,得到的结果是相同的。 -
默认情况下,不同的对象的哈希值也是不同的(特殊情况除外)。
-
package set;
import java.util.HashSet;
public class HashSetDemo2 {
public static void main(String[] args){
/* 添加元素时 调用equals();但是效率低。
底层用到hasdCode()和equals()方法
用输入的内容计算hash值(整数),用hash值比较速度快,但是hash是不安全,
有可能内容不能计算的hash值相同。
解决方法:当hash相同时,调用equals方法判断内容是否相等。
这样既效率高又安全。*/
HashSet<String> hashSet=new HashSet<>();
hashSet.add("x");
hashSet.add("a");
hashSet.add("x");
hashSet.add("l");
hashSet.add("k");
System.out.println(hashSet);
}
}
3.3TreeSet
1、TreeSet集合底层实际上是一个TreeMap
2、TreeMap集合底层是一个二叉树。
3、放到TreeSet集合中的元素,等同于放到TreeMap集合key部分了。
4、TreeSet集合中的元素:无序不可重复,但是可以按照元素的大小顺序自动排序。
package set;
import java.util.TreeSet;
public class TreeSetDemo1 {
public static void main(String[] args){
TreeSet<Integer> set=new TreeSet<>();
/* 不能存储重复元素
底层是树形结构 有一个根节点,每一个节点有两个子节点,大的元素
向右放,小的元素向左放。
添加进来的元素可以排序(有序的 不是添加的顺序 ,是元素的自然顺序)
remove() 删除指定内容的元素
polllast() 删除并返回最后一个元素
first() 删除并返回第一个元素*/
set.add(0);
set.add(5);
set.add(4);
set.add(2);
set.add(3);
System.out.println(set);
}
}
3.4Set集合遍历迭代
因为set集合是无序的没有索引,所以其遍历迭代不能使用for循环来进行遍历迭代,只能使用增强for循环法和迭代器遍历。
package set;
import java.util.Iterator;
import java.util.TreeSet;
public class TreeSetDemo2 {
public static <SetIterator> void main(String[] args){
TreeSet<Studen1> set=new TreeSet<>();
set.add(new Studen1("张三", 101));
set.add(new Studen1("李四", 102));
set.add(new Studen1("王五", 103));
set.add(new Studen1("张三", 101));
System.out.println(set.toString());
Iterator<Studen1> it=set.iterator();
//iterator迭代器循环
while(it.hasNext()){
Studen1 s=it.next();
System.out.println(s);
}
//增强for循环
for(Studen1 s:set){
System.out.println(s);
}
}
}
4.Map接口:
4.1Map集合的概述:
双列集合:用来存储键值对的集合。
interface Map<K,V>
: K(key)键 ,V(value)值
将键映射到值的对象,不能出现重复的键,每个键最多可以映射到一个值
1、Map和Collection没有继承关系。
2、Map集合以key和value的方式存储数据:键值对 key和value都是引用数据类型。 key和value都是存储对象的内存地址。 key起到主导的地位,value是key的一个附属品。
4.2Map集合的基本方法:
V put(K key,V value) 设置键值对
V remove(Object key) 删除元素
void clear() 清空集合
boolean containsKey(Object key) 判断键是否存在,存在则返回true
boolean containsValue(Object value) 判断值是否存在,存在则返回true
boolean isEmpty() 判断集合是否为空
int size() 获取集合元素个数
package map;
import java.util.HashMap;
import java.util.HashSet;
public class HashMapDemo1 {
public static void main(String[] args){
HashMap<String,String> map=new HashMap<>();
map.put("aa", "AA");
map.put("bb","BB" );
map.put("cc","CC" );
map.put("dd","DD" );
map.put("cc","GG" );
System.out.println(map);
System.out.println(map.remove("cc"));//删除键值映射,并返回对应的值
System.out.println(map.values());
System.out.println(map.keySet());
map.clear();
System.out.println(map);//清除
}
}
package map;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class HashMapDemo2 {
public static void main(String[] args){
Map<String,String> map=new HashMap<>();
map.put("AA","aa");
map.put("BB","bb");
map.put("CC","cc");
map.put("DD","dd");
map.put("EE","ee");
//Map集合的遍历
//方法一:通过keyset()获取所有的键遍历键的集合
Set<String> keys = map.keySet();
// 遍历键, 根据键获取值
for (String key: keys) {
String value = map.get(key);
System.out.println(key + ":" +value);
}
System.out.println("------------------");
//方式二:通过entrySet() 获取到一个Enyry类型的集合,Entry中放有键值。
Set<Map.Entry<String,String>> entries=map.entrySet();
for(Map.Entry entry:entries){
System.out.println(entry.getKey()+":"+entry.getValue());
}
}
}
4.3Map集合的特点:
、无序,不可重复。
为什么无序? 因为不一定挂到哪个单向链表上。
不可重复是怎么保证的? equals方法来保证HashMap集合的key不可重复。
如果key重复了,value会覆盖。
2、放在HashMap集合key部分的元素其实就是放到HashSet集合中了。
所以HashSet集合中的元素也需要同时重写hashCode()+equals()方法。
3、HashMap集合的默认初始化容量是16。