集合进阶
单列集合
单列集合List 系列集合特点:添加的元素是有序、可重复、有索引的;
添加对象时永远返回true;
双列集合Set 集合特点:无序、不重复、无索引;
添加对象时,如果对象在集合中不存在返回true,若已存在返回false;
Collection
Collection是单列集合的祖宗接口,所有功能都可被单列集合使用。
注意:Collection是一个接口,不能直接创建对象,只能创建实现类的对象。
常用方法
//以下是常用方法
public boolean add(E e); //把给定的元素添加到集合中
public void clear(); //清空集合中所有元素
public boolean remove(E e); //将给定的元素从集合中删除
(注意不能通过索引删除,只能通过对象删除)
public boolean contains(Object obj); //判断当前集合中是否含有给定对象
contains方法底层依赖的是object类中的equals方法,比较的是地址值,如果使用自定义对象,需要重写equals方法;
public boolean isEmpty(); //判断集合是否为空
public int size() //返回集合中元素的个数/集合的长度
遍历方式
迭代器遍历
迭代器在Java中的类是Iterator,迭代器是集合专用的遍历方法
Iterator <E> iterator(); //返回迭代器对象
//常用方法
boolean hasNext(); //判断当前位置是否有对象,有返回true,没有返回false
E next(); //获取当前位置的对象,并将迭代器移向下一个位置
//遍历方式:
Iterator <String> it = list.iterator(); //创建指针
while(it.hasNext()){ //判断是否有元素
String str = it.next(); //获取元素 移动指针
System.out.println(str);
}
细节:
迭代器遍历完成,指针不会复位,若要二次循环,需要创建新的迭代器对象
循环中只能用一次next方法
迭代器遍历时,不能用集合的方法进行增加和删除,需要用迭代器本身的方法remove进行删除
增强for遍历
·增强for遍历的底层是迭代器,为了简化迭代器的代码书写,内部原理就是一个iterator迭代器。
·所有的单列集合和数组才能用增强for进行遍历。
基本格式:
for(数据类型 变量名:数组或集合){
}
注:idea快捷方式:集合名称.for 即可
Lambda表达式遍历
default void forEach(Consumer<? super T> action);
设coll为一个集合
coll.forEach(s->System.out.println(s));
List
`Collection的方法全都继承
·List有索引,所以多了很多索引操作的方法
void add(int index,E e); //在指定位置插入指定元素,原来位置的元素往后移
E remove(int index); //删除指定位置的元素,并返回
Integer i= Integer.valueof(1);
xxx.remover(i); //删除指定元素
E set(int index,E e); //修改指定位置的元素,并返回被修改的值
E get(int index); //返回指定索引处的元素
遍历方式
·迭代器遍历
·增强for遍历
·Lambda表达式遍历
·普通for循环
·列表迭代器
//遍历方式:
ListIterator <String> it = list.listiterator(); //创建指针
while(it.hasNext()){ //判断是否有元素
String str = it.next(); //获取元素 移动指针
System.out.println(str);
}
迭代器遍历时,不能用集合的方法进行增加和删除,需要用迭代器本身的方法add进行添加
泛型
泛型:是JDK5中引入的特性,可以在编译阶段约束操作的数据类型,并进行检查。
格式:<数据类型>,注意只能支持引用数据类型。
在没有泛型的时候,默认类型全为object类,集合中可以存储任意数据类型,缺点是无法使用子类特有方法。
拓展:Java中的泛型是伪泛型。
泛型不具备继承性,但是数据具备继承性
泛型的好处
·统一数据类型
·把运行时期的问题提前到了编译时期,避免了强制类型转换可能出现的异常,因为在编译阶段类型就能确定下来。
泛型的细节
·泛型中不能使用基本数据类型
·指定泛型的具体类型后,传递数据时,可以传递该类类型或其子类类型
·如果不写泛型,默认时object类型
泛型类
使用场景
当一个类中,某个类的数据类型不确定时,就可以定义带有泛型的类。
格式
修饰符 class 类名 <类型>{
}
泛型方法
使用场景
当方法形参不确定时。
有两种方案:
1、使用类名后面定义的泛型(所有方法都可用)
2、在方法上申明自己的泛型(只有本方法可用)
格式
修饰符 <类型> 返回值类型 方法名 (类型 变量名){
}
泛型接口
格式
修饰符 interface 接口名 <类型>{
}
重点:
如何使用一个带泛型的接口
1、实现类给出具体类型
2、实现类延续泛型,创建对象时再确定
泛型的通配符
?表示不确定的类型
可以进行类型的限定
? extends E 表示可以传递E和E的所有子类类型
? super E 表示可以传递E和E的所有父类类型
应用场景
如果类型不确定,但是知道以后只能传递某个继承体系中的,就可以使用泛型的通配符。
关键点:可以限定类型的范围。
Set集合
Set集合的接口基本与collection的API一致
HashSet
基本特点:无序、不重复、无索引。
底层采取哈希表储存结构,哈希表是对于增删改查数据性能都比较好的结构。(数组+链表+红黑树)
哈希值:对象的整数表现形式
·根据HashCode方法算出来的int整数。
·该方法定义在Object类中,所有对象都可以调用,默认使用地址值进行计算。
·一般情况下,会重写Hash Code方法,利用对象内部的属性值计算哈希值。
·如果没有重写Hash Code,不同对象计算出的哈希值是不同的
·如果已经重写Hash Code,只要对象属性值相同,哈希值就是相同的
·小部分情况下,不同的属性值或者不同的地址值计算出来的哈希值可能相同(哈希碰撞)
Link Hash Set
特点:有序、不重复、无索引。(有序是指存储和取出的顺序是相同的)
原理:底层数据结构是哈希表,每个元素多了一个双链表的机制记录储存的顺序。
如果要求去重且存储有序,用Link Hash Set,否则默认使用Hash Set。
TreeSet
特点:不重复、无索引、可排序。
可排序:按照元素的默认规则(从小到大)排序。
底层使用红黑树,增删改查性能较好。
红黑树规则:
如果使用自定义对象,需要在自定义类中重写compareto方法,或者直接用接口的实现类重写。当两种同时重写时,使用第二种方法。
双列集合
双列集合的特点:
1、双列集合一次存入一对数据,分别为键和值。
2、键不能重复,值可以重复。
3、键和值是一一对应的,每一个键只能找到自己的值。
4、键+值的这个整体,我们称之为“键值对”或者“键值对对象”,在Java中叫做“Entry对象”。
Map
常见API
V put(k key, V value); //添加元素/如果键已存在,将覆盖原有的值并返回
V romeve(Object key); //根据键删除键值对元素/返回删除值
void clear(); //移除所有键值对元素
boolean containsKey(Object key); //判断集合是否包含指定的键
boolean containsValue(Object value); //判断集合是否包含指定的值
boolean isEmpty(); //判断集合是否为空
int size(); //集合的长度,也就是集合中键值对的数目
遍历方法
//通过键找值:
Set<String> keys = map.keySet();//获取所有的键,把他们放到一个单列集合中,在进行遍历。
for(String key : keys){
String value = map.get(key);
System.out.println(value);
}
//通过键值对的方式遍历
Set<Map.entry<String,String>> entries = map.entrySet();
for(Map.entry<String,String> entry : entries){
String key = entry.getKey();
String value = entry.getValue();
System.out.println(key+" "+value);
}
//通过Lambda表达式遍历
default void forEach(BiConsumer<? super k,? super V> action);//结合Lambda表达式进行遍历
map.forEach((key,value)->System.out.println(key+" "+value));
HashMap
1.HashMap底层是哈希表结构的
2.依赖hashcode方法和equals方法保证键的唯一
3.如果键储存的是自定义对象,需要重写hashcode和equals方法,否则不需要重写。
LinkedHashMap
特点:由键决定:有序、不重复、无索引。(有序是指存储和取出的顺序是相同的)
原理:底层数据结构是哈希表,每个元素多了一个双链表的机制记录储存的顺序。
Tree Map
特点:不重复、无索引、可排序。
可排序:按照元素的默认规则(从小到大)排序。
底层使用红黑树,增删改查性能较好。
三种双列集合的选择:
默认:Hash Map,因为Hash Map效率最高
如果要求输入输出有序:Linked Hash Map
如果要求排序:TreeMap
可变参数
方法的形参个数是可以发生变化的
作用:在形参中接受多个数据
格式:数据类型…变量名
public static int getNum(int...a){
}
底层原理是一个数组
细节:
1、在方法的形参中最多只能有一个可变参数
2、如果在方法的形参中还有其他参数,可变参数要写在最后
collections
作用:collections不是集合,而是集合的工具类。
collections的常用API:
public static <T> boolean addAll(Collection<T> c,T....elemnts);//批量添加元素
public static void shuffle(List ? list);//打乱集合中元素的顺序
public static <T> void sort(List<T> list);//排序
public static <T> void sort(List<T> list , Comparator<T> c);//根据指定的规则进行排序
public static <T> int BinarySeach(List <T> list,T key);//利用二分查找法查找元素
public static <T> void copy(List<T> dest,List<T> src);//拷贝集合中的元素
public static <T> int fill(List<T> list , T obj);//使用指定的元素填充集合
public static <T> void max/min(Collection<T> coll);//根据默认的排序获取最大/最小值
public static <T> void swap(List<?> list , int i,int j);//交换集合中指定元素的位置