java的集合
因为数组不好用
使用数组去存储:
- 数组在内容上存储的特点:
- 有序的
- 初始化就确定长度和类型
- 数组在存储数据的弊端
- 长度不可变,不利于扩展
- 不便于添加,插入,删除等操作,效率不高
- 存储的数据单一
java集合可以分为:Coolection 和Map
- collection接口:单列数据,定义了存取一组对象的方法的集合
- list:元素有序且可重复的集合
- set:元素无序,不可重复的集合
- map接口:双列数据,key-value的集合
Collection
是List Set与Oueue接口的父接口,Collection定义方法既可以操作Set集合,也可以操作List和Queue集合
- jdk中不提供关于该接口的任何直接实现,而是提供更具体的子接口(Set和List)来实现
- java5前,集合会丢失容器中所有对象的数据类型,把所有对象都当成Object类型处理
- java5后,泛型出现,java结合就可以记住容器中对象的数据类型
boolean add(object o);
添加(在最后处加)
boolean addAll(Collection coll);
添加(多个添加)
void clear();
清空集合
int size();
获取集合中有效元素的个数
boolean isEmpty();
是否为空集合
boolean containsAll(object o);
通过元素的equals方法来判断是否是同一个对象
boolean containsAll(object o);
通过元素的equals方法来判断(两个集合中元素挨个比较)
boolean remove(object o);
只会删除找到的第一个元素
boolean removeAll(Collection c);
取当前两个集合的差集
boolean retain(Collection c);
把两个集合的差集放到当前集合中,不影响c
[1,2,3,4] [2,3] -->[1,4]
Iterator iterator();
用来遍历,返回一个迭代器对象
Iterator
用于Collection集合遍历,集合对象每次调用iterator方法时都会得到一个全新的Iteratoe对象
在调用iterator.next()方法前,必须使用hasNext()来检测
如果不调用,且下一条记录无效,直接调用itertor.next()会抛出异常 NoSuchElementException
默认游标都在集合的第一个元素前
//使用Itreator迭代器配合while进行集合的遍历
Iterator iterator = collection.iterator();//回到源点,得到collection的iterator 对象
while (iterator.hasNext()){
Object obj = oterator.next();
if(obj.equals(1)){
iterator.remove();
}
}
oterator = collection.iterator();
while (iterator.hasNext()){//判断是否有下一个元素
//1.指针下移一个集合位置
//2.将下移后的集合位置的元素返回
System.out.println(iterator.next());
}
//使用foreach循环遍历
//for (要遍历的元素类型 元素名称:要遍历的结构名称)
collection.add(3);
for(Object object:collection){
System.out.println(object);
}
foreach循环遍历集合的底层仍然是调用iterator完成操作
public class CollectionEx1{
public static void main (String[] args){
String[] str = new String[5];
//Strring 引用类型
//引用类型的对象名是地址?
//myStr?
for (String myStr:str){
myStr = "seehoppe";
System.out.println(str[i]);
}
}
}
List
List除了从Collection中继承方法外
void add(int index,Object o);
在index位置插入元素o
boolean addAll(int index,Collextion c);
在index位置开始将c中所有元素添加进来
Object get(int index);
获取indexOf 位置的元素
int indexOf(Object o);
获取元素O在集合中首次出现的位置
int lastIndexOf(Object o);
获取元素o在集合中最后一次出现的位置
Object remove(int index);
移除指定index位置的元素,并返回此元素
Object set(int index,Object o);
设置指定index位置的元素o
ArrayList
本质上ArrayList是一个对象引用的“变长”数组
- ArrayList在1.8前,直接创建初始长度为10的数组(饿汉式)
- ArrayList在1.8后,一开始创建长度为0的数组,当添加第一个元素时再创建初始容量为10的数组(懒汉式)
LinkedList
对于频繁插入或删除元素的操作,都建议使用LinkedLisr,效率较高
public void addFirst(E e);
在头部插入
public void addLast(E e);
在尾部插入
Object getFirst()
获得头部元素
Object getLast()
获得尾部元素
Object removeFirst()
移除头部元素
Object removeLast()
移除尾部元素
LinkedList:双向链表
prev--->前一个元素的位置
prev--->后一个元素的位置
Vector
addElement(Obj)
insertElementAt(obj,index)
setElementAt(obj,index)
removeElement(obj)
void removeAlklElements()
Set
- Set接口是Collection的子接口,set接口没有提供额外的方法
- Set不允许包含相同的元素,如果把两个相同的元素放到同一个Set集合中,会添加失败
- Set判断两个对象是否相同不是使用==,而是根据equals方法
HashSet
HashSet是按照Hash算法来存储集合中的元素,有很好的存取查找和删除性能
- 不是线程安全的
- 不能保证元素的排列顺序
- 集合元素是可以null
HashSet如何判断两个元素相等
两个对象先通过hashCode()方法来比较是否相等,并且两个对象的equals方法返回值也要相等对于在Set容器中的对象,对应的类一定要重写equals和hashCode,以涉嫌对象相等
对象相等必须要有相等的Hash码
Set底层是使用数组实现
底层也是数组,初始的容量为16,如果使用率超过75%,就会扩容到原来的两倍
重写hashCode()方法的基本原则
- 程序运行时,同一个对象多次被调用hashCode()方法应该返回相同的值
- 当两个对象的equals方法比较返回了true时,这两个对象的hashCode值也应该一样
- 对象中用来比较equals方法,都是用来计算hashCode值
重写equals()方法的原则 - 改写equals()方法时必须要改写hashCode()
- 相同的对象必须具有相同的hash码(散列码)
- 同常参与计算hashCode的对象的属性也应该参与到equals方法中计算
LinkedHashSet - 是HashSet的子类
- LinkedHashSet根据元素的hashCode值来决定元素的存储位置,但它同时使用双向链表来维持元素的次序,显得元素是按照插入顺序保存
- LinkedHashSet插入性能略低于HashSet,但在迭代(循环)中访问Set中元素时性能很好
- 也不允许集合元素重复
TreeSet
- 底层使用到红黑树来存储数据
- 自然排序和定制排序
- 有序且查询速度比list快
自然排序 - TreeSet会调用结合元素的compareTo(Obj)来比较元素之间的大小关系,然后按升序排序
- 如果试图把一个对象放到TreeSet中,那么这个对象的类必须实现Comparable接口
- 实现Comparable接口的类必须实现comparableTo方法,即两个对象通过compareTo的方法的返回值来比较大小
- Comparable的典型实现
- BigDecimal Interger数值型对应的包装类:按他们对应的数值来比较大小
- Character:按字符的Unicode值来比较
- Boolean:true对应的实例比fasle对应的实例要大
- String:按字符串中的字符的Unicode值来比较
- Date Time:后面的时间,日期比前面的时间日期大
定制排序
调用compare(o1,o2)方法
List练习
在list中去除重复数字值
做法一:(单纯使用list)
做法二:(使用Set辅助)
提示:
set.addAll(Collection)把Collevtion集合放入set中
list.addAll(Collection)把Collection集合放入list中
Map
- Map与Collection并列存在 key-value键值对
- key和value都可以是引用类型
- Map中的key是用Set来存储的,不允许重复,同一个Map对象所对应的类,必须重写hashCode和equals方法
- 常用String类来作为Map的键
- key与value是一对一(单向)关系,通过指定的key总能找到唯一的,确定的value
- Map的实现类:HashMap TreeMap LinkedHashMap
- 使用最后的是HashMap
- Map<K,V> K–>Set V–>Collection
Collection<V> value();
Set<K> keySet();
//添加,删除,修改
Object put(Object key,Object value);//将指定key-value放到(修改)当前map对象
void putAll(Map m);//将m中所有的键值对放到当前map中
Object remove(Object key);//移除指定key-value对,并返回value
void clear();//清空当前map的所有数据
//查询
Object get(Object key);//获得指定key中对应的value
boolean containsKey(Object key);//是否包含了指定的value
int size();//返回map中键值对的数量
boolean isEmpty();//判断是否为空
boolean equals(Object o);//判断当前map和参数对象o是否相等
//原始图操作
Set keySet();//返回key的Set集合
Collection values();//返回values的Collection集合
Set entrySet();//返回键值对所组成的Set集合
import java.util.*;
public class Main{
public static void main (String[] args){
Map map = new HashMap();
map.put(1,"xiao");
map.put(2,"ming");
map.put("xiao","hong");
System.out.println("map的所有key:");
Set keys = map.keySet();
for (Object key:keys){
System.out.println(key + "->" + map.get(key));
}
System.out.println("map的所有value");
Collection values = map.values();
Iterator iter = values.iterator();
while (iter.haseNext()){
System.out.println(iter.next);
}
System.out.println("map的所有映射关系");
Set mappings = map.entrySet();
for(Object mapping:
mappings){
Map.Entry entry = (Map.Entry) mapping;
System.out.println("key是:" + entry.getKey() + "value是:" + entry.getValue());
}
System.out.println(map);
}
}
HashMap
是Map接口使用频率最高的实现类
- 允许null键和null值,与HashSet一样不保证映射的顺序
- 所有可以构成的集合Set是无序的,不可重复的,所以key所在的类要重写equals HashCode()
- 一个key-value构成了一个entry
- 所有entry构成的Set无序,不能重复
- values构成的Collection无序可重复的,所以value所在的类要重写equals
- HashMap判断两个key(Object)相等:两个key hashCode值一样且equals方法返回true
- HashMap判断两个value(Object)相等:两个value equals 方法返回true
在jdk8前 HashMap是数组+链表结构
在jdk8后 HashMap是数组+链表+红黑树
LinkedHashMap
- LinkedHashMap是HashMap的子类
- 在HashMap存储结构的基础上,使用了一对双向链表来记录添加元素的顺序
- 他的迭代顺序是与key-Value对的插入顺序是一致