集合
为什么学习java集合框架
数组的存储数据的弊端:
a:存储相同数据类型的有序集合、存储的数据是相同类型的
b:数组存储数据时 需要指定当前数组的长度而且长度不可变 (定长)需求:
- 使用数组存储学生信息 效率变低
- 使用数组存储每天的新闻信息
- 就是由于在大多数的应用场景中,数据都是动态的,导致数组存储要么浪费空间,要么浪费效率
为什么java提供集合对象存储数据信息
- 这么多集合对象用来在不同的应用场景使用。
- 本质上而言 其实不同的集合对象底层存储实现方案不同 不同的存储结构 适用不同的需求
三个知识点
泛型
什么是泛型?
广泛的类型,也是一种数据类型,而这种数据类型可以是任意类型,编写过程当中不能确定该类型,创建对象时可以指定泛型的具体类型
注意:
泛型是编译期行为,只能在编译器有效如果能够跨过编译期,那么泛型就没有任何意义
泛型类
在类后加<> 括号中编写任意长度任意字符 不能是数值
一般情况下我们通过大写的26个字母去声明当前泛型 通常:用 T 代表type 用 E 代表element
使用:
泛型类<具体类型> 变量名 = new 泛型类<具体类型>();
jdk1.7之后支持泛型的类型推断,就是后面那个具体类型可省略
泛型接口
实现类实现泛型接口时不指定泛型类型 此时创建实现类对象是可以指定泛型类型
class UserServiceImpl implements UserService
实现类实现泛型接口时指定泛型类型 那么将确定泛型类型
class UserServiceImpl implements UserService泛型方法
方法中使用泛型 该方法就是一个泛型方法
静态方法无法使用泛型类中声明的泛型类型 因为泛型类型的确定是创建对象时确定的
而静态方法是先于对象存在的 ,如果要使用,在当前静态方法上声明泛型类型
public static <泛型类型> vaid 方法名()
迭代器
迭代器:
- Iterable 是java.lang包下的接口 实现改接口都能够作为foreach的目标
- Iterator 是java.util包下的接口 迭代器 用来迭代当前集合对象的
- Iterator 是一个接口 ArrayList中通过内部类完成了对于改接口的实现 获取的其实是实现类对象
- ListIterator 是一个接口 这个接口可以支持并发修改 内部提供了add set remove方法
- 如果对于一个List集合对象要通过使用迭代器做修改(删除、添加、修改)那么请使用ListIterator
位置:
迭代器的指针指向了集合中第一个元素前面一个位置
检查:
迭代器通过hasNext()查看下面是否存在元素
移动:
通过next()移动指针,并且返回当前指针指向的元素值。
比较器
外部比较器:
如果要使用外部比较器:
- 实现java.util.Compartor接口
- 重写compare方法
- 然后在compare方法中自定义排序规则(返回值为正数,不交换位置,返回值为负数,交换位置,返回0表示相等)
特点:排序规则可以随着业务扩展随时变化的。
内部比较器
如果要使用内部比较器:
- 实现java.lang.Comparable接口
- 重写compareTo方法
- 然后在compareTo方法中自定义排序规则(返回值为正数,不交换位置,返回值为负数,交换位置,返回0表示相等)
特点:如果需求改变,排序规则也就需要改变,但由于要准守开闭原则,就不利于后期扩展
六个接口
Collection
定义:
public interface Collection extends Iterable
泛型Iterable:
接口 凡是继承/实现了Iterable的类 都能够作为foreach的目标
Iterable 是java.lang包下的接口 实现改接口都能够作为foreach的目标
Iterator 是java.util包下的接口 迭代器 用来迭代当前集合对象的常见方法:
add 、clear、remove、addAll、removeAll、retainAll、size、isEmpty、contains、containsAll、iterator
迭代方法:
foreach、迭代器
public class Test01 {
public static void main(String[] args) {
// 学习接口中的方法 接口指向实现类对象
Collection coll = new ArrayList();
//添加元素
coll.add("java");// Object obj = "java" 自动类型转换
coll.add(1);// Integer in1 = Integer.valueOf(1); Object obj = in1;
//添加元素
Collection coll1 = new ArrayList();
coll1.add("html");
coll1.add("spring");
System.out.println("往coll中添加coll1:"+coll.addAll(coll1));
//删除元素:
//coll.clear();
System.out.println("移除不存在的元素:"+coll.remove("spring"));
//System.out.println(coll.removeAll(coll1));
System.out.println("coll中的元素:"+coll);
System.out.println(coll.retainAll(coll1));
System.out.println("coll中的元素:"+coll);
//查看元素
System.out.println("查看当前集合是否为null:"+coll.isEmpty());
System.out.println("查看当前集合元素个数:"+coll.size());
System.out.println("查看当前集合是否包含元素1:"+coll.contains("1"));
}
}
public class Test02 {
public static void main(String[] args) {
//创建集合对象
Collection coll = new ArrayList();
//添加元素
coll.add("String");
coll.add("1");
coll.add("Integer");
coll.add("Scanner");
//迭代元素
System.out.println("foreach循环迭代");
for(Object obj:coll) {
String str = (String)obj;
System.out.println(str);
}
System.out.println("iterator 迭代器");
Iterator it = coll.iterator();//实现类对象
while(it.hasNext()) {//下面是否存在元素 如果存在元素 返回true 如果不存在返回false
//获取元素
System.out.println(it.next());
}
System.out.println("迭代器的变种写法");
for(Iterator it1 = coll.iterator();it1.hasNext();) {
System.out.println(it1.next());
}
}
}
List
特点:
有序 可重复 可以是null值
定义:
public interface List extends Collection
常见方法:
增加: add(index,obj) 指定位置增加指定元素 add(obj) 在末尾增加指定元素 addAll(Coll) 在末尾增加指定collection集合 addAll(index,coll) 在指定索引处插入指定collection集合
删除: remove(index/obj) 删除指定索引元素/删除指定元素 clear() 删除所有元素 removeAll(Coll) 当前集合中删除指定collection集合中的所有元素(也就是删除交集) retainAll(coll) 保留当前集合和指定集合的交集
修改: set(index,obj) 修改指定索引的值为指定值
查看: indexOf(obj) 查询指定元素的索引 lastIndexOf(obj) 查询指定元素最后一次出现的索引 subList(sindex,eindex) 截取从指定索引sindex到eindex的集合 isEmpty() 查询是否为空 get(index) 获取指定索引的值 size() 查询集合中元素个数 contains(obj) 查询指定元素是否存在 contaisAll(coll) 查询指定集合中的所有元素是否都在当前集合中
迭代:
普通for循环
增强foreach
迭代器(iterator[不能支持并发修改] listIterator[支持并发修改])
注:支持并发修改也就是允许在迭代器中对集合进行修改、增加、删除等操作
Set
特点:
无序 唯一
定义:
public interface Set extends Collection
常见方法:
add 、clear、remove、addAll、removeAll、retainAll、size、isEmpty、contains、
containsAll、iterator迭代方法:
foreach、迭代器
迭代器接口
Iterator 用来迭代元素
Iterable: 类实现该接口其对象即可 使用foreach
比较器接口
内部比较器
同上,三个知识点 -> 比较器
外部比较器
同上,三个知识点 -> 比较器
Map
数据:
k-v 键值的方式存储
k:唯一 无序 (set) v 无序可重复 (collection)常见方法:
put(k,v) 在k键添加v值,如果存在键返回对应k键的值 ,添加的值会覆盖之前的值 get(k) 获取键对应的值,如果键不存在,返回null containsKey(k) 查看键是否存在 keySet() 获取所有的key remove(k) 删除k键对应的键值对,如果键不存在 返回null 如果存在返回值 size() 查看键值对的个数 containsValue(v) 查看值是否存在 values() 获取所有的值,返回Collection集合。 entrySet() 获取所有的键值对,返回一个set集合 该集合中的每个元素都是entry对象 迭代方法:
获取键 迭代键的过程中通过get方法获取值
for(Object key:keySet()){ sout(k+"="+map.get(k)); }
获取Entry对象,通过getKey和getValue获取键和值
//获取entry对象 // 返回一个set集合 该集合中的每个元素都是entry对象 Set<Entry<String, String>> kvs = mps.entrySet(); // 实际是 HashSet中的Node对象 因为Node实现了Map中的Entry接口 for(Entry<String, String> entry:kvs) { System.out.println(entry.getKey()+"==="+entry.getValue()); }
九个常用类
ArrayList:
底层:
动态数组 ,满了会扩容2倍
优缺点分析:
通过索引获取元素以及迭代元素比较快 但是添加、删除很慢
注:由于是动态数组,频繁的增加和删除,会进行频繁的扩容、缩容,会伴随着大量的拷贝操作。增加和删除时还需要对其索引后的元素进行移动,又是一波拷贝操作(移动)
常见方法:和List一致
迭代方式:和List一致
LinkedList:
底层:
双向链表()
优缺点:
添加、删除快 获取元素慢
常见方法:
和List一样,还多了一些头尾操作:
查看 getFirst、getLast、peek、 peekFirst、 peekLast、 element获取头元素
删除 poll、 pollFirst、 pollLast、 removeFirst、 removeLast
添加 offer、 offerFirst、 offerLast、 addFirst、 addLast
Vector:
底层:
数组
特点:
线程安全 速度慢1.5倍 安全
一般不使用,太慢了
HashSet:
底层:
(1.7之前jdk版本) 数组+链表 (1.8+jdk版本)数组+链表+红黑树
优缺点:
添加、删除、修改效率都很高( 结合了数组与链表的优点,先利用求得的hashCode在数组中定位查询,然后在数组元素中的链表进行增、删、改等操作,节约了大量的时间,能快速定位)
常见方法:
add 、clear、remove、addAll、removeAll、retainAll、size、isEmpty、contains、
containsAll、iterator迭代方法:
foreach、迭代器
注意事项:
存储过程:
存储自定义对象时,先会求其值的hash值,根据hash值计算存储的位置(桶)。
然后与该位置(桶)下的其他对象进行比较(如果没有直接添加),比较时会调用该对象的equals方法 ,如果相等就不添加该对象,如果没有重写hashcode和equals方法,会调用父类默认的方法。
那何时重写呢?比如:当我们需求是,前两个对象的属性相同 我们觉得是同一个对象 此时要重写。
所以根据我们的需求选择是否重写。
TreeSet:
底层:
树 红黑树 / 二叉树 / 平衡树
优缺点:
维护数据的大小 (有序) ,添加速度和删除速度高于ArrayList 比其他的都低
查询速度高于List 低于Hash。
如果对于存储的数据有 排序的要求,那么首选TreeSet。常见方法:
同Set,多了一些针对于排序元素的操作 first last floor ceiling higher lower
迭代方法:
foreach、迭代器
注意事项:
如果存储的元素需要按照指定的需求进行排序,创建TreeSet对象时 指定比较器。
如果存在的元素是自定义对象:
1:要么自定义对象的所属类 实现了内部比较器Comparable接口 重写compareTo方法
2:要么创建TreeSet对象是 指定外部比较器Comparetor接口 重写compare方法
set中每个元素存储的时候 都是存储在一个map集合中 map集合的键是set中的元素, map中的值是自动添加的一个默认值
HashMap:
底层:
(1.7之前jdk版本) 数组+链表 (1.8+jdk版本)数组+链表+红黑树
优缺点:
添加、删除、修改效率都很高
注意:
存储过程:
存储自定义对象时,先会求其键的hash值,根据hash值计算存储的位置(桶)。
然后与该位置(桶)下的其他对象进行比较(如果没有直接添加),比较时会调用该对象的equals方法 ,如果相等就填充该对象的value值,如果没有重写hashcode和equals方法,会调用父类默认的方法。
那何时重写呢?比如:当我们需求是,前两个对象的属性相同 我们觉得是同一个对象 此时要重写。
所以根据我们的需求选择是否重写。
TreeMap:
底层:红黑树
优缺点: 维护数据的大小 (有序) ,添加速度和删除速度高于ArrayList 比其他的都低
查询速度高于List 低于Hash。
如果对于存储的数据有 排序的要求,那么首选TreeMap。
如果存储的元素需要按照指定的需求进行排序,创建TreeMap对象时 指定比较器。
如果存在的元素是自定义对象:
1:要么自定义对象的所属类 实现了内部比较器Comparable接口 重写compareTo方法
2:要么创建TreeMap对象是 指定外部比较器Comparetor接口 重写compare方法
Arrays:
对象:
针对数组进行的一些操作。
主要方法:
asList -> 数组转集合
sort(排序)、binarySearch(二分查找)、fill(填充)、 copyof (拷贝)、 copyofRange(拷贝指定范围)、toString(打印)
注:
Arrays.asList 返回的是Arrays类中的内部类ArrayList ,而这个类的对象是不允许添加以及删除元素的,也就是返回的集合对象是一个长度不可变的ArrayList。
使用binarySearch查找元素 一定要先排序 返回的是排序之后的元素索引位置
Collections:
对象:
针对集合进行的一些操作。
主要方法:
toArray -> 集合转数组
binarySearch(二分查找)、sort(排序)、shuffle(乱序)、fill(填充)、 copyof (拷贝)、 copyofRange(拷贝指定范围)、toString(打印)
问题:
Collections通过了一组方法 synchronizedXXX(XXX)
- 该组方法可以针对传入的集合对象 做线程同步,返回能够同步的线程安全的集合对象
- 但不一定是线程安全的。 及其特殊的情况下会发生问题
解决办法:
concurrent包下的同步集合实现 同步集合在jdk1.8之后采用分段锁机制完成对于数据的加锁操作 提高效率
注:
使用binarySearch查找元素 一定要先排序 返回的是排序之后的元素索引位置
返回的是排序之后的元素索引位置
Collections:
对象:
针对集合进行的一些操作。
主要方法:
toArray -> 集合转数组
binarySearch(二分查找)、sort(排序)、shuffle(乱序)、fill(填充)、 copyof (拷贝)、 copyofRange(拷贝指定范围)、toString(打印)
问题:
Collections通过了一组方法 synchronizedXXX(XXX)
- 该组方法可以针对传入的集合对象 做线程同步,返回能够同步的线程安全的集合对象
- 但不一定是线程安全的。 及其特殊的情况下会发生问题
解决办法:
concurrent包下的同步集合实现 同步集合在jdk1.8之后采用分段锁机制完成对于数据的加锁操作 提高效率
注:
使用binarySearch查找元素 一定要先排序 返回的是排序之后的元素索引位置