集合
集合
作用:用于装数据的结构,可以装引用数据类型或者基本
集合家族:
下面的实现类都有其父类的可继承方法
Iterable只有一个方法:iterator()迭代器:例如循环
Collection接口
可利用多态形式创建其实现类的实例(注意在没有运行,编译期间这个接口的饮用指向实现类的实例,但是。方法的话只能点出自己的抽象方法,最终运行时才会调用实现类的重写方法)
对数据的操作:
增:create
删:delete
改:update
查:read
Collection接口中的方法
add():往集合里添加数据
例如:collection.add(1)
addAll():合并集合
例如:collection1.addAll(collection2)
containsAll():判断集合时候包含
例如:collection1.containsAll(collection2)
size():返回集合的数据个数
例如:collection.add()
clear():清空集合数据
例如:collection.clear()
**contains(a)**:查看集合中是否包含该数据
例如:collection.contains(a)
**remove(a)**:删除集合中的特定数据
例如:collection.remove()
remove和contains的底层原理:
运行时contains调用子类里重写的方法,而重写的contains方法里又调用了包装类里面重写的
equals方法,因此是比较对象的内容,而dog是我们自定义的类,里面继承Objecj的equals没有重写
因此是比较的两个对象的地址值,所以对于自定义类型来说,如何判断是否相等,一定要重写equals,
因为contains和remove原理就是equals
//https://edu.51cto.com/center/course/lesson/index?id=803239
contains在运行时走子类实现的重写方法
isEmpty():检查集合中是否有数据
例如:collection.isEmpty()
removeAll(集合):删除集合里相等的全部元素
例如:collection.removeAll(集合)
toArray():将集合转为Object数组
例如:collection.toArray()
equals():判断集合内容时候相等
例如:collection.equals(collection1)
hashCode():返回集合的哈希码
例如:collection.hashCode()
iterator()迭代器
例如:collection.iterator(),能获取一个迭代器对象,类似一个可控指针
常用检查集合中是否有元素
iterator.hasNext():通过指针检查是否有下一个元素
iterator.next():通过指针取出下一个元素
其实增强for本质就是一个迭代器
迭代器不能删除数据
平时取数据的几种方法:
利用迭代器取数据:
不能删数据的原因:
(获取迭代器时类似镜像出另一个集合,删除时将原集合的数据删除,镜像的不变所以导致镜像和原集合不同步导致报错),但是可以用迭代器的remove方法删除(原理就是同步镜像)
List接口
List接口的三个实现类
List接口的常见方法
add(索引,元素):将元素插入到指定位置
get(索引):取出指定位置的值
addAll(索引,集合):将集合插入到指定位置
indexOf():返回集合指定元素第一次出现的索引
lastIndexOf():返回集合指定元素最后一次出现的索引
remove(索引):根据索引删除集合中的元素
set(索引,元素):替换指定位置的元素
subList(开始索引,结束索引):截取集合返回新的集合
ArrayList的扩容机制
1.ArrayList底层是基于数组实现的,方便查找
数组的特点:有序,查询效率高,随即增删效率低(要重新新排)
add():添加元素时先确定容量
2.底层扩容为原本的1.5倍,创建ArrayList对象时为空数组,当add添加第一个元素的时候会初始化一个长度为10的数组
位运算符:<<,>> 操作二进制,运算最快
例如8>>2=2
1000 >> 2,1向右移两位得到2
ArrayList(容量):构造器创建一个该容量的集合,可以减少运算压力,提升速度
LinkeList
基于双向链表实现的,在空间上存储是无序的,方便存储,不利于查找,用一个node块(分为数据部分跟下一个块的位置信息,和上一个位置信息)
单向链表:
双向链表:
LinkeList的常用方法:
LinkeList源码:
在add插入数据时:(不用扩容用多少加多少)
l.next = newNode:将上一个节点结尾指向新创建的节点地址
Vector原理(了解)
实现原理:通过数组实现
初始化数组大小为10
添加数据add
跟ArrayList实现一样就是多了个synchronized线程安全
扩容:默认为原来两倍,或者通过new使用带参的构造方法自定义扩容容量
Set接口
HashSet集合
底层通过map实现,不包括重复元素,不保证插入取出时顺序的一个无序集合,与list接口的方法基本相同,因为将HashSet的值添加到map的key的位置
HashSet的去重原理
比较添加内容的值跟hashCode值,如果相等就去重,因此添加自定义对象要重写equals和hashCode(是根据传入的参数值生成的)
ps:参数后跟…为不定长参数,可以传多个
TreeSet集合
自动排序插入的元素,一个有序不重复集合
TreeSet排序原理
通过树形结构进行排序,在构造方法中使用带参Comparable接口重写后的构造方法根据指定比较器进行比较排序
使用平衡二叉树排序,遍历有三种方式:
前序(根左右)
前序遍历:根左右
中序遍历:左根右(目前用的排序方式)
后序遍历:左右根
插入数据为:50 60 20 10 100 30
中序遍历后顺序为:10 20 30 50 60 100
1.如果想要实现给自定义排序,要实现comparable接口,实现compareTo这个方法,这个方法返回=0(不排序) >0 <0情况
this.age - ((Man) o).age;//正序
((Man) o).age - this.age;//倒序
2.TreeSet底层是根据TreeMap实现的
3.String方法已经实现了Comparable接口的compareTo方法可用来排序字符串(内部通过将字符串转换为char来比较的)
this.name.compalreTo(o.name);
4.如果创建treeSet传递了比较器对象,优先使用comparator的实现后的compare方法比较
5.如果没有传递则使用comparable的实现后的comparetTo方法比较
6.如果类没有实现Comparable则报类转换异常。
结论:
1、如果使用HashSet,判断自定义对象是否重复一定要实现equals和hashCode
2、如果使用TreeSet,判断自定义对象是否重复,一定要实现comparable接口,并且实现comparetTo这个方法
数组集合相互转换
数组转ArrayList使用asList方法
List转HashSet
ArrayList转HashSet
Map接口
Map接口的实现类,Map里存储的是键值对(k,v)Map<,>(只能写引用数据类型)
HashMap接口
基于哈希表实现的Map接口
Map<Integer,Integer> map1 = new HashMap<>();
Map接口自身没有迭代器功能不能直接遍历,可通过
Set<Map.Entry<String,string>> entries = map.entrySet();//.entrySet();方法转为set在进行迭代遍历
1.put方法:类似之前的add
map.put( "name",“小王");
2.get方法:根据键取取值(键不可重复否则被覆盖)
map.get ( "name" );
3.clear方法:清空
4.containsKey方法:判断是否包含
map. containsKey( "name");
5.HashMap是无序的
6.equals方法:比较值是否相等
HashMap重写了equals方法
7.isEmpty方法:判断是否存在键值对
8.KeySet方法:将键值转化为集合,用于不知道有哪些键值时进行取值
9.size方法判断有几个键值对
10.putAll方法:将另一个map合成一个大的
11.remove方法:根据键值删
12.value方法:将value返回为一个集合
从keySet往后都和遍历有关
HashMap底层原理
无序的Key不可重复,就是将HashSet的值添加到map的key的位置
用哈希表来实现的(数组(上)用于查询,加链表(下)用于增删等)
在put时首先将key生成一个散列哈希值,根据哈希值
(hashcode用于算出存放位置【横向】)算出要放在数组的哪个位置
(当两个哈希值一样时就不会再把重复的key放进去了),
然后再根据链表上的节点值进行equals(用于比较值【纵向】)比较key值
因此自定义的类使用到哈希表时一定要重写hashcode和equals方法
详解:https://edu.51cto.com/center/course/lesson/index?id=803199
HashMap扩容
当单个列表的数量大于8时这个列表会变成红黑树结构,其他不变,当小于6时就变回来了
HashMap的构造方法
1.默认16个数组,0.75是使用量当大于时就进行扩容,以算数左移一位X2的方式进行扩容
HashTable
也是通过哈希表实现的,其中的方法基本跟hashmap一样,但是都用了synchronized修饰(线程安全的,不可同时调用)hashmap是线程不安全的
Properties的用法
表示一个持久的属性集,Properties可保存在流中或从流中加载。属性列表中每个键及其对应值都是一个字符串。一般用于读配置文件
TreeMap
TreeMap是TreeSet的底层,不可重复有序的,TreeSet的值放到了TreeMap的key上,通过实现Comparable接口排序也是通过这个接口来判断是否重复或者是通过比较器
Collections工具类
操作集合的工具类
max方法:返回集合的最大值或者自定义(根据自己写的判断,
否则根据重写的比较器进行判断)比较器进行比较
例如下图结果返回100的第一条,因为返回0
reverse反转指定列表的元素,倒叙
sort按照自然顺序排序或者自定义比较器排序
能添加nulI的集合类
不能添加nulI的集合类
TreeSet:底层判断是否为空,为空报错
HashTable:因为底层之间调用key .hashcode
TreeMap:底层判断是否为空,为空报错
其他都可以添加null元素
大复习
常见问题
构造方法:初始化对象属性
1、跟类名一样
2、没有返回值,不用void修饰
1.多态的向上转型和向下转型(强转)
instanceOf判断是不是父类的实例
2.this,super
this:对象本身(当实例属性跟,构造方法中的属性名一样不能省略)
super代表父类(当父类子类的属性一样时调用父类不能省略)
3.final:常量
final不能abstarct(抽象)一起用
4.static:跟类相关的东西,在方法区,用类调用
存在与方法区的静态池中,因此当一个类的对象为空时,调用这个类中的实例属性会报空指针
为空,调用static的属性就不会,因为最终是通过类来调用
接口和抽象类:不能new对象(可以通过匿名实现类,实现抽象方法),抽象类可作为接口跟实现类之间的缓冲(因为抽象类不必须要实现接口的方法)
修饰符:private protected public 默认
5.String字符串
6.常用类,Enum枚举类,内部类(成员、静态、局部、内部)等
7.异常:
8.集合
泛型
在jdk1.5提出<>
作用:规定集合中元素的类型
例如只能是String类型的数据
自定义泛型
例如自定义一个集合MyList,定义一个add方法