javaSE第七章——集合
文章目录
泛型
泛型,即"参数化类型"。一提到参数,最熟悉的既是定义方法是有形参,然后调用此方法时传递实参。
参数化类型,就是将类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时传入具体的类型(类型实参)。
/**
* @author 辉欲静,而风止。
* 泛型
*
* 1、泛型的类型参数只能是类类型(包括自定义类)
* 2、泛型的类型参数可以有多个。 如果没有定义具体类型,默认为Object
*/
public class TestGeneral<T> {
private T p;
public T getP() {
return p;
}
public void setP(T p) {
this.p = p;
}
}
集合的概念
存储一个班的学员信息,假定一个班容纳20名学员。
当我们需要保存一组一样(类型相同)的元素的时候,我们应该使用一个容器来存储,数组就是这样一个容器。
数组有什么缺点?
数组一旦定义,长度将不能再变化。
然而在我们的开发实践中,经常需要保存一些变长的数据集合,于是,我们需要一些能够动态增长长度的容器来保存我们的数据。
而我们保存的数据的逻辑可能是多种多样的,于是就有了各种各样的数据结构。java中对于各种数据结构的实现,既是我们用到的集合。
集合API
集合体系概述
java的集合框架是由很多接口、抽象类、具体类组成的,都位于java.util包中。
Collection接口
Collection接口–定义了存取一组对象的方法,其子接口Set和List分别定义了存储方式。
Set中的数据对象没有顺序且不可以重复。
List中的数据对象有顺序且可以重复。
在Collection中定义了一些集合的共有方法:
import java.util.ArrayList;
import java.util.Collection;
/**
* @author 辉欲静,而风止。
*集合中的方法
* 集合中只能存储引用类型
*/
public class CollectionDemo1 {
public static void main(String[] args) {
Collection<Integer> c = new ArrayList<>();
/*
给集合里添加元素
*/
int a = 8;
c.add(1);
c.add(2);
c.add(3);
//如果是基本类型会自动装箱为引用类型
//(除基本类型之外的所有类型都是引用类型)
c.add(a);
/*System.out.println(c);*/
Collection<Integer> c1 = new ArrayList<>();
c1.add(5);
c1.add(6);
c1.add(7);
c1.add(8);
//将指定集合中的元素添加到此集合中 [1, 2, 3, 8, 5, 6, 7, 5]
c.addAll(c1);
//保留两个集合中相同的内容 [8, 5, 6, 7, 8]
c.retainAll(c1);
//清除集合中的所有元素
c.clear();
// System.out.println(c.isEmpty());//判断集合是否为空
//System.out.println(c.contains(3));//判断集合中是否包含元素3
// c.remove(10);//删除元素10
//如果c和c1里的元素一模一样没有发生改变则返回false,改变返回true
System.out.println(c.retainAll(c1));//改变返回true,不改返回false
// c.removeAll(c1);//删除指定集合中包含在该集合中的所有元素c[1, 2, 3] c1[4, 6, 7, 8]
/*Object[] c2 =c.toArray();//转数组
System.out.println(c2.length);*/
Integer[] array = c.toArray(new Integer[c.size()]);//转指定类型的数组
System.out.println(array.length);//4
System.out.println(c);
}
}
List接口及实现类
List继承了Collection接口,有三个实现的类
—ArrayList
数组列表,数据采用数组方式存储。
—LinkedList
链表
—Vector
数组列表,添加同步锁,线程是安全的。
ArrayList实现了长度可变的数组,在内存中分配连续的空间。
遍历元素和随机访问元素的效率比较高
LinkedList采用链表存储方式。插入、删除元素时效率比较高
ArrayList的常用方法
import java.util.ArrayList;
public class ArrayListDemo {
/*
list 接口允许元素重复
list继承了collection
list是有序的按照插入元素排列,可以存储重复元素,值插入后有索引,可以通过索引访问元素
ArrayLIst:底层是数组,查询快,从中间删除,添加慢
Vector:底层是数组,查询快,从中间删除,添加慢,相对于ArrayLIst是线程安全的
LinkedList:底层是双向链表,查询慢,从中间删除速度快,添加快
*/
public static void main(String[] args) {
/*
add(E e);向列表末尾添加元素,add(int index,E e);向指定位置添加元素
ArrayList();默认不创建底层数组,当添加第一个元素时,默认创建一个长度为10的数组
Arraylist(int length)创建对象时,在底层创建一个指定长度的数组,
ArrayList(Collection collection)把一个实现了collection接口的子类构造成一个ArrayList
ArrayList是动态数组,当底层数组装满后后自动扩容,扩容为原来的1.5倍
*/
ArrayList<String> list = new ArrayList<>();
/*
add方法底层数组扩容:当底层数组装满后,数组范围会变为原来的1.5倍,扩容的范围不能超过int的范围
grow();扩容方法
*/
list.add("a");
list.add("b");
list.add("c");
list.add("a");
list.add(0,"V");//add(int index,E e)向指定位置添加一个元素,其他元素向后移动
list.add("d");
list.add("e");
System.out.println(list);
System.out.println(list.get(0));//获取指定位置上的值并返回,查询快
System.out.println(list.remove(0));//删除指定位置上的元素并返回
System.out.println(list);
}
}
import java.util.ArrayList;
import java.util.Comparator;
import java.util.function.Predicate;
/**
* @author 辉欲静,而风止。
* ArrayList常用方法
*/
public class ArrayListDemo1 {
public static void main(String[] args) {
ArrayList<String> list1 = new ArrayList<>();
/*
add方法底层数组扩容:当底层数组装满后,数组范围会变为原来的1.5倍,扩容的范围不能超过int的范围
grow();扩容方法
*/
list1.add("d");
list1.add("e");
list1.add("a");
list1.add("e");
list1.add(0,"V");//add(int index,E e)向指定位置添加一个元素,其他元素向后移动
list1.add("c");
list1.add("b");
//条件删除
list1.removeIf(new Predicate<String>() {//条件删除 删除满足给定谓词的此集合的所有元素
@Override
public boolean test(String s) {
return s.equals("e");
}
});
System.out.println(list1);
//排序 匿名内部类
list1.sort(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.compareTo(o2);
}
});
System.out.println(list1);
}
}
import java.util.ArrayList;
public class ArrayListDemo2 extends ArrayList {
public static void main(String[] args) {
ArrayListDemo2 list =new ArrayListDemo2();
list.add("a");//0
list.add("b");
list.add("c");
list.add("d");//3
list.add("e");
System.out.println(list);
/* list.removeRange(0,3);//removeRange只能在ArrayList子类中使用,删除一个左闭右开的区间元素
System.out.println(list);*/
list.set(3,"zwj");//替换指定位置的元素
System.out.println(list);
}
}
LinkedList的常用方法
add(int index,Object element) 向指定位置添加指定类型的元素
addFirist(Object element) 向队首添加元素
addLast(Object element) 向队尾添加元素
get(int index) 获取指定位置元素
removeFirst() 移出队首元素
removeLast() 移出队尾元素
remove(int index) 移出指定位置元素
getFirst() 获取队首元素
getLast() 获取队尾元素
import java.util.LinkedList;
public class LinkedListDemo {
public static void main(String[] args) {
LinkedList<String> list = new LinkedList<>();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
list.add("e");
// list.remove(2);
/* Node<E> node(int index) {
// assert isElementIndex(index);
if (index < (size >> 1)) {
Node<E> x = first;
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else {
Node<E> x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}
传入一个索引,如果索引小于集合一半,从头结点开始查找,直到找到这个位置的值
如果大于一半,从尾结点开始查找,直到找到这个位置的值
*/
System.out.println(list.get(2));
System.out.println(list);
}
}
List接口集合迭代
for循环遍历
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>();
list.add(1);
list.add(5);
list.add(2);
list.add(4);
list.add(3);
/*//for循环 循环时允许删除元素但需要注意索引与集合长度之间的关系
for (int i = 0; i < list.size(); i++) {
if(list.get(i)==2){
list.remove(i);//删除索引为i的元素
}
System.out.println(list.get(i));
//System.out.println(list.get(i));
}
System.out.println(list);*/
}
增强for循环的遍历
/*//增强for循环 不允许从中删除元素
for(Integer item:list){
if(item==3){
list.remove(item);
}
System.out.println(item);
}*/
迭代器遍历
//迭代器遍历
Iterator<Integer> it = list.iterator();
while (it.hasNext()){
//System.out.println(it.next());//遍历列表
Integer item = it.next();
if(item==1){
it.remove();//删除列表中指定的元素
}
System.out.println(item);
}
System.out.println(list);
stream流遍历
import java.util.ArrayList;
import java.util.stream.Stream;
/**
* @author 辉欲静,而风止。
* stream流遍历
*/
public class StreamDemo {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
Stream<Integer> s = list.stream();
/*s.forEach(new Consumer<Integer>() {//Stream流遍历
@Override
public void accept(Integer integer) {
System.out.println(integer);
}
});
*/
s.forEach(integer -> System.out.println(integer));
}
}
Set接口
● Set接口继承了Collection接口。
Set中所存储的元素是不重复的,但是是无序的, Set中的元素是没有索引的
● Set接口有两个实现类
● HashSet
HashSet类中的元素不能重复,即彼此调用equals方法比较,都返回false。
底层数据结构是哈希表+链表
哈希表依赖于哈希值存储
● TreeSet
可以给Set集合中的元素进行指定方式的排序。存储的对象必须实现Comparable接口。
TreeSet底层数据结构是二叉树(红黑树是一种自平衡的二叉树)
Set接口集合迭代
● 三种遍历方式
增强for循环
迭代器遍历
流遍历
import java.util.HashSet;
public class HashSetDemo {
/*
set接口:键不可以重复,值没有索引
Hashset:无序,底层使用哈希表+链表+红黑树
TreeSet:有序(按照值(编码)的顺序排序)底层是红黑树
*/
public static void main(String[] args) {
HashSet<Integer> set = new HashSet<>();
set.add(2);
set.add(21);
set.add(12);
set.add(24);
set.add(2);
System.out.println(set);//[2, 21, 24, 12]
/*
hashset添加时如何判断值是否重复
添加时会调用hashcode(),equals()方法
添加时要比较内容是否相等,既要保证效率又要保证安全
*/
int h = "ssssssssss".hashCode();//先调用hashcode()计算出一个哈希值,比较哈希值,非常快但不安全
int h1 = "sssssssssss00000".hashCode();
System.out.println(h==h1);//false
int s = "通话".hashCode();
int s1 = "重地".hashCode();
System.out.println(s==s1);//true
//当哈希值相同时,再调用equals()方法比较
}
}
Map接口
Map接口概述
将键映射到值的对象
一个映射不能包含重复的键
每个键最多只能映射到一个值
Map接口的常用方法
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/*
Map集合
双列存储 key(键不能重复) value(可以重复)
clear() 清除列表中所有元素
remove(Object key) 移出指定键所对应的元素
replace(K key, V value) 替换已有键的值 如果键不存在,则不能替换
put(key,value) 添加键值对
putAll(Map<? extends K,? extends V> m)
containsKey(Object key) 判断是否包含指定的键
containsValue(Object value) 判断是否包含指定的值
get(Object key) 获取指定键所对应的值(根据键查找值,如果键不存在,则返回null)
values() 返回集合所有的值
size() 获取集合长度
isEmpty() 判断集合是否为空
keySet()
entrySet()
forEach(BiConsumer<? super K,? super V> action)
HashMap
TreeMap
Hashtable(线程安全)
*/
public class HashMapDemo1 {
public static void main(String[] args) {
Map<String,String> map = new HashMap<>();
map.put("a", "a");
map.put("a", "b");
map.put("b", "b");
map.put("w", "c");
map.put("s", "c");
map.put(null, "c");
//map.clear();
//map.remove("b");
//map.replace("b","bbbb"); //替换已有键的值 如果键不存在,不能替换
System.out.println(map.isEmpty());
System.out.println(map.containsKey("a"));
System.out.println(map.containsValue("c"));
System.out.println(map.size());
Collection<String> s = map.values();//返回所有的值
System.out.println(s);
System.out.println(map.get("ss"));//根据键查找值,键不存在返回null
System.out.println(map);
}
}
可看到键重复后值被替换,HashMap无序,TreeMap按照键排序,LinkedHashMap和添加顺序一致
HashMap
HashMap中元素的key值不能重复, 排列顺序是不固定的,可以存储一个为null的键。
public static void main(String[] args) {
Map<String,String> map = new HashMap<>();
map.put("a", "w");
map.put("z","q");
map.put("a", "b");
map.put("b", "b");
map.put("w", "c");
map.put("s", "c");
map.put(null,"o");
System.out.println(map);
}
运行结果:
{null=o, a=b, b=b, s=c, w=c, z=q}
● TreeMap
TreeMap中所有的元素都保持着某种固定的顺序,如果需要得到一个有序的Map就应该
使用TreeMap,key值所在类必须实现Comparable接口。
import java.util.TreeMap;
public class TreeMapDemo {
public static void main(String[] args) {
/*
按照键的顺序排序,用哪个类型的类作为键,那么必须实现Comparable
*/
TreeMap<String, String> tmap = new TreeMap<>();
tmap.put("b","z");
tmap.put("a","a");
tmap.put("d","d");
tmap.put("c","w");
tmap.put("c","z");
System.out.println(tmap);
}
● HashTable
实现了同步。
不能存储为null的键
import java.util.Hashtable;
public class HashTableDemo {
public static void main(String[] args) {
/*
底层也是哈希表+链表(红黑树)实现
是线程安全 synchronized Stringbuffer,Vector
*/
Hashtable<String,String> hmap = new Hashtable<>();
hmap.put("a","a");
hmap.put(null,"a");
}
}
运行结果:
Exception in thread "main" java.lang.NullPointerException
at java.util.Hashtable.put(Hashtable.java:465)
at com.ff.javaCollection1.map.HashTableDemo.main(HashTableDemo.java:15)
Map集合遍历
方式1:根据键找值
• 获取所有键的集合
• 遍历键的集合,获取到每一个键
• 根据键找值
方式2:根据键值对对象找键和值
• 获取所有键值对对象的集合
• 遍历键值对对象的集合,获取到每一个键值对对象
• 根据键值对对象找键和值
import java.util.HashMap;
import java.util.Map.Entry;
import java.util.function.BiConsumer;
import java.util.Set;
/**
* @author 辉欲静,而风止。
* map 集合的遍历
*/
public class HashMapDemo2 {
/*
Map集合
HashMap
底层存储结构
哈希表+链表/红黑树
put方法实现
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
*/
public static void main(String[] args) {
HashMap<String,String> map = new HashMap<>();
map.put("a", "a");
map.put("a", "b");
map.put("b", "b");
map.put("w", "c");
map.put("s", "c");
//Map遍历方式1:keySet()
/* Set<String> keyset = map.keySet();//返回map中所有键 封装到一个Set集合中
for(String key : keyset){
System.out.println(key+"::"+map.get(key));
} */
//方式2 entrySet()将map中底层存储键值的Entry对象,封装到一个Set集合中
/* Set<Entry<String, String>> entrySet = map.entrySet();
for(Entry<String, String> entry : entrySet){
System.out.println(entry.getKey()+"::"+entry.getValue());
}*/
//方式3
map.forEach(new BiConsumer<String, String>() {
@Override
public void accept(String k, String v) {
System.out.println(k+":::"+v);
}
});
}
}
Collections类
Collections是集合类的工具类,与数组的工具类Arrays类似
addAl l(Col lection<? super T> c, T… elements);
binarySearch(List<? extends Comparable<? super T>> l ist, T key)
sort(List l ist)
sort(List l ist, Comparator<? super T> c)
swap(List<?> l ist, int i, int j)
copy(List<? super T> dest, List<? extends T> src) ; 注意 dest size需大于等于src.size
emptyList() 返回为空的集合,不能添加数据
fi l l(List<? super T> l ist, T obj)
max(Col lection<? extends T> col l)
min(Col lection<? extends T> col l)
replaceAl l(List l ist, T oldVal, T newVal)
reverse(List<?> l ist)
@Override
public void accept(String k, String v) {
System.out.println(k+":::"+v);
}
});
}
}