- 集合是Java API自己提供的一系列的类,可以作用于动态存放多个对象(集合只能存对象)
- 集合与数组的不同:
- 集合
- 集合是大小可变的序列
- 元素类型可以不受限定
- 只要是引用类型
- 集合不能存放基本数据类型,但可以放基本数据类型的包装类
- 数组:
- 数组长度固定
- 数组可以存储基本数据类型和引用类型
- 集合类全部支持泛型,是一种数据安全的用法
Java的集合框架从整体上可以分为两大家族
- Collection(接口)家族,该接口下的所有子孙均存储的是单一对象。Add(s)
- Map(接口)家族,该接口下的所有子孙均存储的是key-value(键值对)形式的数据。 Put(key,value)
另外还有三个分支,均是为上面两个大家族服务的
- Iterator(迭代器)家族。只要用于遍历Collection接口及其子类而设计
- Comparator(比较器),在集合中存储对象的时候,用于对象之间的比较
- Collections是工具类。注意:该类名带了个s,一般就表示工具类。里面提供了N多静态方法,来对Collection集合进行比较
List:有序(跟录入的顺序一致)可以重复 有下标
Set:无序(跟录入的顺序不一致,并不是随机的,而是由hash值+散列算法来决定的),不可以重复 没有下标
常用方法:
- int size();返回此Collection中的元素
- boolean isEmpty();判断此collection是否包含元素
- boolean contains(Object obj);判断此collection是否包含指定的元素。
- boolean contains(Collection c);判断此collection是否包含指定collection中的所有元素
- boolean add(Object element);向此collection中添加元素
- boolean addAll(Collection c);将指定collection中的所有元素添加到此collection中
- boolean remove(Object element);从此colletion中移除指定的元素
- boolean removeAll(Collection c);移除此collection中那些也包含在指定colletion中的所有元素
- void clear();移除collection中所有的元素
- boolean retainAll(Collection c);仅保留此collection中那些也包含在指定collection的元素
- Iterator iterator();返回在此collection的元素上进行迭代的迭代器
- Object[] toArray();把此collection转成数组
使用场景:
ArrayList[重点]: 数组结构实现,查询快、增删慢、必须连续开辟空间;JDK1.2版本,运行效率快、线程不安全
LinkedList: 链表结构实现,增删快、查询慢、无需连续开辟空间;JDK1.2版本,运行效率慢,队列模式、栈模式,线程不安全
Vector: 数组结构实现,查询快、增删满;JDK1.0版本,运行效率慢、线程安全的,弃用,1.2版本加入list接口
Stack: 弃用,线程安全的
特点:有序且可重复(因为List接口中添加了许多针对下标操作的方法)
遍历方法有四种:
- for循环
- foreach循环
- Iterator迭代器循环
- ListIterator迭代器循环
迭代器循环使用步骤:
- 获取迭代器对象—》while循环中用迭代器对象中的hashNext()方法来判断是否有可以迭代的对象—》输出迭代器返回的下一个元素(迭代器对象.next())
list接口中独有的迭代器:ListIterator迭代器
//遍历-------ListIterator迭代器 ListIterator<String> listIterator=list.listIterator();//获取ListIterator迭代器对象 while(listIterator.hashNext()){ //判断是否有可以迭代的对象 String e=listIterator.next();//返回下一个元素 System.out.println(e); }
新增的几个实用方法:
- public Object get(int index) //根据下标,返回列表中的元素
- public Object add(int index,Object element) //在列表的指定位置插入指定的元素,将当前处于该位置的元素(如果有的话)和所有后续元素向右移动
- public Object set(int index,Object element)// 用指定元素替换指定位置的元素
- public Object remove(int index) //移除表中指定位置的元素
- 注意:list集合中的元素被索引与数组中的元素一样,均是从0开始
public class Test{ public static void main(Strin[] args){ ArrayList list=new ArrayList(); //添加元素 list.add("字符串"); list.add(100);//Integer.valueOf(100); list.add(123.123);//Double.valuOf(123.123); } }
LinkedList的独有特点:
队列模式:先进先出
public class Test{ public static void main(String [] args){ LinkedList<String> list=new LinkedList<>(); list.add("aaa"); list.add("bbb"); list.add("ccc"); while(!list.isEmpty){ //删除第一个元素,并返回 String element=list.removeFirst(); System.out.println(element); } System.out.println("集合中元素的个数"+list.size()); } }
.removeFirst()方法表示:队列模式先进先出
栈模式:先进后出
同理:栈模式的先进后出是将 .removeFirst方法修改为.removeLast()方法
知识点:使用LinkedList方法+泛型
泛型:数据安全的做法,规定集合应该储存什么样的数据类型
public class Test01{
public static void main(String [] args){
/**
知识点:使用Linkedlist方法+泛型
泛型:数据安全的作法,规定集合应该储存什么样的数据类型
*/
LinkedList<String> list=new LinkedList<>();
//添加元素
list.add("荣十一");
list.add("沝");
list.add("沝心");
//获取元素的个数
int size=list.size();
System.out.println("获取元素的个数:"+size);
//设置指定下标上的元素
list.set(0,"小郑");
//获取指定下标上的元素
String element=list.get(0);
System.out.println("获取指定下标的元素:"+element);
//在指定下标上插入元素
list.add(1,"小张");
LinkedList<String> newlist1=new LinkedList<>();
Collections.addAll(newlist,"aaa","bbb","ccc");//利用集合工具进行批量添加
list.addAll(newlist1);//将新集合中所有的元素添加到指定的集合的末尾
LinkedList<String> newList2=new LinkedList<>();
Collections.addAll(newList2,"ddd","eee","fff");//利用集合工具类批量添加
list.addAll(3,newList2);//将新集合中所有的元素添加到指定集合上指定的下标
//清楚集合中所有的元素 list.clear();
System.out.println("判断集合中是否包含某个元素"+list.contains("小张"));
LinkedList<String> newList3=new LinkedList<>();
Collections.addAll(newList3,"eee","fff","ddd");//利用集合工具类进行批量添加
System.out.println("判断集合中是否包含某个集合中所有的元素:"+list.containsAll(newList3));
int index=list.indexOf("沝");
System.out.println("获取元素在集合中的下标"+index);
boolean empty =list.isEmpty();//有元素则---false 无元素则---ture
System.out.prinntln("判断集合中是否没有该元素:"+empty);//false
//删除
list.remove(3);//依据下标删除元素
list.remove("eee");//依据元素删除元素
//删除---交集
LinkedList<String> newList4=new linkedList<>();
Collections.addAll(newList4,"fff","aaa","bbb");//利用集合的工具类进行批量添加
list.addAll(newList4);
//保留集合
LinkedList<String> newList5=new LinkedList<>();
Collections.addAll(newList,"榮十一","小雅","小惠");
list.retainAll(newList5);
//替换指定下标上的元素
list.set(4,"桜儿");
//获取开始下标到结束下标(不包含)的元素,并返回新的集合
List<String> subList=list.subList(1,5);
//将集合转换为数组
Object[] array=subList.toArray();
System.out.println(Arrays.toString(array));
System.out.println("-----------");
//遍历----for
for(int i=0;i<list.size();i++){
System.out.println(list.get(i));
}
System.out.println("-----------");
//遍历---foreach
for(String e:list){
System.out.println(e);
}
System.out.println("--------------");
//遍历-----Iterator迭代器
Iterator<String> it=list.iterator();//获取Iterator迭代器对象
while(it.hashNext()){
//判断是否有可以迭代的元素
String e=it.next();//返回下一个元素
System.out.println(e);
}
System.out.println("-------------");
//遍历-------ListIterator迭代器
ListIterator<String> listIterator=list.listIterator();//获取ListIterator迭代器对象
while(listIterator.hashNext()){
//判断是否有可以迭代的对象
String e=listIterator.next();//返回下一个元素
System.out.println(e);
}
}
}
了解:Vector是元老级别的集合类,从JDK1.0版本开始使用,JDK1.2开始才推出集合框架的概念,考虑到当时很多程序员习惯性使用Vector,就让Vector也实现了List接口,这样才将其保留了下来
public class Test{ public static void main(String [] args){ Verctor<String> v=new Verctor<>(); //添加元素 v.add(); //删除元素 v.removeElement();//可以通过下标来删除元素,也可以通过元素来删除元素 //遍历 Elemeration<String> element=v.elements(); while(elements.hasMoreElements()){ String nextElement =element.nextElement(); System.out.println(nextElement); } } }
特点:有更老的一套遍历方法
同样:Vector也有list接口的所有方法和遍历的方法,因为都是继承父类List的方法
特点:栈模式-----先进后出
public class Test{ public static void main(String[] args){ Stack<String> stack=new Stack<>(); //添加元素,将元素压入栈顶 stack.push("榮1"); stack.push("榮2"); stack.push("榮3"); stack.push("榮4"); System.out.println("距离栈顶的位置(从1开始):"+stack.search("榮2")); while(!stack.empty()){ //获取栈顶第一个元素,并返回 //String element=stack.peek(); //删除栈顶第一个元素,并返回 String element=stack.pop(); System.out.println(element); } System.out.println(stack.size()); } }
同样,stack也继承于父类List接口,所以也可以实现list的所有方法
特点:无序且不可重复
使用场景:
HashSet[重点]: 基于HashCode实现不重复,当存入元素的哈希码相同时,
会调用==或equls确认,结果为true拒绝存入
去重+有序,线程不安全
LinkedHashSet: 链表实现的HashSet,按照链表进行存储,即可保留元素的插入顺序,
使用的是头部插序,要避免哈希回环问题。
去重+有序,线程不安全
TreeSet: 1.基于排序顺序实现元素不重复 2.实现了SortedSet接口对集合元素自动排序
3.元素对象的类型必须实现Comparable接口,指定排序规则
4.通过CompareTo方法确定是否为重复元素
5.去重+无序,线程不安全
特点:去重+无序
注意:HashSet中,无序不代表随机,利用的是hash值+散列算法进行的顺序
public class Test01{ public static void main(String[] args){ /** 知识点:使用HashSet方法 特点:去重+无序 */ HashSet<String> set=new HashSet<>(); //添加 set.add("榮1"); set.add("榮2"); set.add("榮3"); set.add("榮5"); //获取元素的个数 int size=set.size(); System.out.println("获取的元素个数:"+size); HashSet<String> newSet1=new HashSet<>(); Collections.addAll(newSet1,"沝","沝心"); set.addAll(newSet1);//将新集合中所有元素添加到指定集合的末尾 //清空集合中的所有元素 //set.clear(); System.out.println("判断集合中是否包含某个元素"+set.contains("榮2")); HashSet<String> newSet2=new HashSet<>(); Collections.addAll(newSet2,"榮沝","榮沝心"); System.out.println("判断集合中是否包含某个元素:"+set.containsAll(newSet2)); boolean empty=set.isEmpty();//有元素--false 没有元素--true System.out.println("判断集合中是否没有元素:"+empty); //删除 set.remove("榮2"); //删除-交集 HashSet<String> newSet3=new HashSet<>(); Collections.addAll(newSet3,"榮5","沝心","榮沝心"); set.removeAll(newSet3); //保留交集 HashSet<String> newSet4=new HashSet<>(); Collections.addAll(newSet4,"榮1","榮沝","沝"); set.retainAll(newSet4); //将集合转换为数组 Object [] array=set.toArray(); System.out.println(Arrays.toString(array)); System.out.println("---------------"); //遍历----foreach for(String element:set){ System.out.println(element); } System.out.println("--------------"); //遍历----Iterator迭代器 Iterator<String> it=set.iterator();//获取Iterator迭代器对象 while(it.hasNext()){ //判断是否有可以迭代的元素 String e=it.next();//返回下一个元素 System.out.println(e); } } }
与HashSet方法相同,不同处在于LinkedHashSet构造了一个新的哈希链,使用节点找到地址进行单向链表。底层原理就是调用的HashMap。
同样:LinkedHashSet也是继承的set方法,可以和上面HashSet一样使用set的方法
同理:TreeSet也可以使用set的所有方法
特点:TreeSet可以进行排序
- 存整数包装数据类型:数字排序
- 存字符串类型:字典排序
public class Test{ public static void main(String[] args){ /** 知识点:TreeSet排序 需求:创建两个TreeSet对象,分别存Integer、String,感受排序 TreeSet存Integer:数字排序 TreeSET存String: 字典排序 */ TreeSet<Integer> set1=new TreeSet<>(); //添加元素 set1.add(5);//Integer.valueOf(5); set1.add(1);//Integer.valueOf(1); set1.add(3);//Integer.valueOf(3); set1.add(4);//Integer.valueOf(4); set1.add(2);//Integer.valueOf(2); //遍历-----foreach for(Integer integer:set1){ System.out.println(integer); } TreeSet<String> set2=new TreeSet<>(); set2.add("c"); set2.add("d"); set2.add("a"); set2.add("b"); for(String string:set2){ System.out.println(string); } } }
内置比较器:实现comparable重写compareTo方法进行比较有两种方式
- return this.需要的属性 减去o.需要比较的属性 前减后顺序。 后减前 倒序
- return 类型.compare(this.需要的属性,o.需要比较的属性) 顺序。需要倒序则交换位置
外置比较器:在新建的TreeSet括号中新建 Comparator方法,进行重写compare,比较方式与内置器比较方式相同。作用范围为:当内置比较器无法满足需求时,但又不能改变内置比较器的规则时使用。。在底层源码中是优先使用外置比较器,如果没有外置比较器的时候才调用内置比较器。所以外置比较器优先级高于内置比较器。源代码验证:
Comparator<? super K> cpr = comparator; if (cpr != null) { //如果外置比较器没有使用,为空就不进入外置比较器中是二选一的方式,进入了外置比较器,就不进入内置比较器,所以外置比较器优先于内置比较器 do { parent = t; cmp = cpr.compare(key, t.key); if (cmp < 0) t = t.left; else if (cmp > 0) t = t.right; else return t.setValue(value); } while (t != null); } else { if (key == null) throw new NullPointerException(); @SuppressWarnings("unchecked") Comparable<? super K> k = (Comparable<? super K>) key; do { parent = t; cmp = k.compareTo(t.key); if (cmp < 0) t = t.left; else if (cmp > 0) t = t.right; else return t.setValue(value); } while (t != null); }
List接口:拥有下标,存放的元素有序且允许有重复的集合接口,拥有特有的listIterator迭代器
Set接口:没有下标存放的元素无需不包含重复的集合接口
HashMap[重点]:JDK1.2版本,线程不安全的,运行效率快;允许null作为key或者是value
Hashtable: JDK1.0版本,线程安全的,运行效率慢,不允许null作为key或者是value。
Properties: Hashtable的子类,要求key和value都是String。通常用于配置文件的读取。
TreeMap: 实现了SortedMap接口(Map的子接口),可以对key自动排序,
- key需要实现comparable接口,也就是实现内置比较器,通过重写compareTO方法进行比较,
- key需要实现的功能不能被内置比较器满足时,内置比较器又不能去修改,因为内置比较器满足他人使用,所以就需要使用到外置比较器来进行满足条件,即comparator接口来进行重写compare方法,进行key排序
map类实现的方法
.put()方法:作用于添加元素使用
.clear()方法:作用于清空集合
.containsKey()方法:判断此集合中是否有某个key
.containsValue()方法:判断此集合中是否有某个Value
通过key来获取对应的value
- .get()方法:通过key来获取对应的value值
- .getOrDefault()方法:通过key来获取对应的value值,若集合中没有该集合则添加默认的Value值
- .isEmpty():判断集合中是否没有该元素
.putAll()方法:将新集合中所有的元素添加到map集合中去
.putIfAbsent(key,value)方法:添加元素,若有该key值就不添加,返回集合value,如果没有该集合就添加key-value
删除方法.remove():
- 可以使用key值来删除映射关系。
- 也可以使用key-value键值对来及逆行删除映射关系
修改/替换方法:
- .replace():通过key来替换value
- .replace(key,value,替换的value):通过键值对来替换value
- .put(key,value):添加元素时,若有相同的key就替换value值
集合种映射关系的个数:.size():获取集合中的个数
获取集合中所有的value:.values():写在打印语句中,输出集合中全部value
遍历:------keySet() : .keySet()生成 Set keySet=map.keySet();
for(String key:keySet){
Integer value=map.get(key);//通过key来获取对应的value
输出内写入key+value输出}
特点:HashMap key是唯一的,value可以重复。储存键值对、无序的
注意:无序不代表随机,根据存入顺序来进行的
允许出现null键,线程不安全的
特点:ConcurrentHashMap key是唯一的,value可以重复
存储键值对,有序,允许存null键,线程不安全
//遍历1--keySet()
//遍历思路:把LinkedHashMap中所有的key抽取出存放在Set集合中,遍历Set集合依次取出key,就能获取对应的Value
Set<String> keySet = map.keySet();
for (String key:keySet){
Integer value=map.get(key);//通过key获取对应的value
System.out.println(key+"------"+value);
}
System.out.println("-----------------");
//遍历2---entrySet()
//遍历思路:把LinkedHashMap中的key和value
Set<Map.Entry<String, Integer>> entrySet = map.entrySet();
for (Map.Entry<String,Integer>entry:entrySet){
String key=entry.getKey();
Integer value = entry.getValue();
System.out.println(key+"-----"+value);
}
存储键值对,无序,不允许存null键,线程安全(局部加锁,效率高)
ConcurrentHashMap<Object, Object> map = new ConcurrentHashMap<>(); map.put(null, "xx"); Set<Entry<Object,Object>> entrySet = map.entrySet(); for (Entry<Object, Object> entry : entrySet) { System.out.println(entry.getKey() + " -- " + entry.getValue()); }
特点:TreeMap针对于Key排序
HashSet底层由HasMap实现,HashSet存入的元素是存储在HashMap KEY的位置因为HashMap key不允许重复
TreeSet底层由HasMap实现,TreeSet存入的元素是存储在TreeMap KEY的位置因为TreeMap key才排序
内置比较器与外置比较器的使用,上面在Treeset方法中也说了,效果是一样的。看需求使用,key值排序
特点:存储键值对,无序,不允许存null键,线程安全(直接在方法中上锁,效率低),已弃用
Hashtable key 是唯一的,value可以重复
//遍历1 - keySet() //遍历思路:把Hashtable中所有的key抽取出存放在Set集合中,遍历Set集合依次取出Key,就能获取对应的Value Set
keySet = map.keySet(); for (String key : keySet) { Integer value = map.get(key);//通过key获取对应的value System.out.println(key + " -- " + value); } System.out.println("--------------"); //遍历2 - entrySet() //遍历思路:把Hashtable中所有的映射关系(Entry)抽取出存放在Set集合中,遍历Set集合依次取出映射关系(Entry),就能获取映射关系中的key和value Set > entrySet = map.entrySet(); for (Entry entry : entrySet) { String key = entry.getKey(); Integer value = entry.getValue(); System.out.println(key + " -- " + value); }
一般用于开发连接数据库的,创建一个.Properties文件,输入数据库的用户和密码还有连接数据库那一个数据库,然后在类中创建文件对象,进行配置文件的加载,获取配置文件的数据
//创建配置文件的对象 Properties p=new Properties(); //将配置文件加载到对象中 p.load(Test01.class.getClassLoader().getResourceAsStream("DBConfig.properties")); //获取配置文件中的数据 String username=p.getProperty("username"); String password=p.getProperty("password"); System.out.println(username+"-------"+password);
Collection :使用add为增加方法,有迭代器进行遍历,也可以进行for循环和foreach遍历
Map:使用put为增加方法,没有迭代器进行遍历,使用的是 .entrySet()方法进行foreach的遍历。用于存储任意键值对(key–value),key无下标、不可以重复有唯一性。value无下标、可以重复
ConcurrentHashMap<Object, Object> map = new ConcurrentHashMap<>();
map.put(null, "xx");
Set<Entry<Object,Object>> entrySet = map.entrySet();
for (Entry<Object, Object> entry : entrySet) {
System.out.println(entry.getKey() + " -- " + entry.getValue());
}
参数化类型、类型安全的集合,强制集合元素的类型必须一致
- 编译时就可以检查,而非运行时抛出异常
- 访问时,不必类型转换(插箱)
- 不同泛型之间引用不能相互赋值,泛型不存在多态
含义:数据安全的做法
泛型限定:
?表示什么类型都可以
? extends A 表示元素必须是A类或A的子类
? super A 表示元素必须是A类或A的父类
含义:遍历集合中的数据
分类:Iterator 和 ListIterator
Iterator 和 ListIterator 区别
Iterator :Collection接口下所有的实现类都可以获取的迭代器,可以在遍历时删除元素
ListIterator :List接口下所有的实现类可以获取的迭代器,可以在遍历时删除、替换、添加元素,也可以指定下标开始遍历,还可以倒叙遍历
作用:排序时使用
分类:
内置比较器:Comparable - compareTo()
外置比较器:Comparator - compare()
使用场景:
内置比较器:对象要想存入TreeSet、TreeMap中,对象所属的类必须要实现内置比较器
外置比较器:当内置比较的规则不满足现在的需求,但又不能改动内置比较器规则时
优先级别:外置比较器 > 内置比较器
ArrayList<Integer> list = new ArrayList<>();
//批量添加
Collections.addAll(list, 2, 3, 5, 1, 7, 4, 8, 6);
//排序---使用内置比较器
Collections.sort(list);//升序
//也可以使用list.sort来进行
//排序----使用外置比较器
Collections.sort(list, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1 ,o2 );
}
});
//替换
// Collections.fill(list,888);//全部替换为888
System.out.println(list);
- Collection 与 Map的区别
Collection 存单个值,可以获取迭代器进行遍历
Map存两个值(Key-Value),不可以获取迭代器,不能遍历(Map可以间接遍历)
- 理解Set为什么是无序
无序:存入顺序和取出顺序不一致,无序不等于随机
- ArrayList 与 LinkedList的区别
使用上的区别:
LinkedList添加了
队列模式-先进先出(removeFirst())
栈模式-先进后出(removeLast())
效率上的区别:由于ArrayList底层数据结构是一维数组,LinkedList底层数据结构是双向链表
添加 - 不扩容的情况:ArrayList快
添加 - 扩容的情况:LinkedList快
删除:LinkedList快
修改:ArrayList快
查询:ArrayList快
注意:工作中常用ArrayList,因为很多需求都需要使用查询功能,ArrayList查询更快
- 各种集合的应用场景
ArrayList:存数据,线程不安全
LinkedLinked:
Vector:弃用,线程安全
Stack:弃用,线程安全
HashSet:去重+无序,线程不安全
LinkedHashSet:去重+有序,线程不安全
TreeSet:排序,线程不安全
HashMap:存key+value,key去重,无序,线程不安全
LinkedHashMap:存key+value,key去重,有序,线程不安全
Hashtable:弃用,存key+value,key去重,无序,线程安全,分段式加锁-效率低
ConcurrentHashMap:存key+value,key去重,无序,线程安全,局部加锁、CAS-效率高
TreeMap:存key+value,针对于Key排序
Properties:配置文件
使用上的区别:
LinkedList添加了
队列模式-先进先出(removeFirst())
栈模式-先进后出(removeLast())
效率上的区别:由于ArrayList底层数据结构是一维数组,LinkedList底层数据结构是双向链表
添加 - 不扩容的情况:ArrayList快
添加 - 扩容的情况:LinkedList快
删除:LinkedList快
修改:ArrayList快
查询:ArrayList快
注意:工作中常用ArrayList,因为很多需求都需要使用查询功能,ArrayList查询更快
- 各种集合的应用场景
ArrayList:存数据,线程不安全
LinkedLinked:
Vector:弃用,线程安全
Stack:弃用,线程安全
HashSet:去重+无序,线程不安全
LinkedHashSet:去重+有序,线程不安全
TreeSet:排序,线程不安全
HashMap:存key+value,key去重,无序,线程不安全
LinkedHashMap:存key+value,key去重,有序,线程不安全
Hashtable:弃用,存key+value,key去重,无序,线程安全,分段式加锁-效率低
ConcurrentHashMap:存key+value,key去重,无序,线程安全,局部加锁、CAS-效率高
TreeMap:存key+value,针对于Key排序
Properties:配置文件
- 。。。