Arrays
binarySearch:二分查找的效率,返回下标,但是查找不存在的元素,返回的是的: -插入点-1
sort重写规则
Lambda表达式
()->{}
():对应方法的形参
->:固定格式
{}:对应方法的方法体
简化sort:
Arrays.sort(arr,(Interger o1,Interger o2)->{
return o1-o2;
});
简化匿名内部类的书写,只能简化函数式接口的匿名内部类
lambda的省略规则:
1.参数类型可以省略不写。2.如果只有一个参数,参数类型可以省略,同时()也可以省略。
3.如果Lambda表达式的方法体只有一行,大括号,分号,return可以省略不写,需要同时省略。
Arrays.sort(arr,(o1,o2)->o1-o2);
集合:
Collection:单列集合
Map:双列集合
Collection<String> coll=new ArrayList<>();
//创建对象,collection是接口不能直接创建对象
remove不能通过索引删除,只能删除的对象
contains底层是equals方法比较,所以比较的是地址值,对于特殊对象,要重写equals
遍历:
迭代器遍历:
Iterator<String> it=list.iterator();//创建指针,指向0索引
boolean next=it.hasNext();
it.next()//指向下一位
细节注意点:
1,报错NoSuchElementException(访问不存在的)
2,迭代器遍历完毕,指针不会复位
3,循环中只能用一次next方法
4,迭代器遍历时,不能用集合的方法进行增加或者删除
(可以用迭代器的remove删除)
增强for:
底层就是迭代器,只有单列或者是数组可以用
增强for会生成一个第三方变量,因此修改第三方变量不会影响里面的内容
lambda表达式:
//匿名内部类
coll.forEach(new Consumer<String>(){
@Override
public void accept(String s){
//s表示集合中每一个元素
}
} )
lambda表达式
coll.forEach(s->System.out.println(s));
List:
有序,有索引,可以重复
add默认添加在尾部
remove也可以删除元素,如果元素和下标重复的话,优先选择类型符合的重载
遍历方式:
Collection的都可以用
普通for &列表迭代器
for(int i=0;i<list.size();i++){
String s=list.get(i);
}
//列表迭代器
ListIterator
在遍历的过程中可以添加
hasprevious 逆向遍历,有元素就返回true 要先遍历到后面再用
List<String> list=new ArraysList<>();//先创建集合
ListIterator<String> it=new list.listIterator();
Arraylist:
继承list的方法
LinkedList:
底层数据结构是双链表,查询慢,增删快,但是如果操作的是首尾元素,速度也是极快的。
没有泛型的时候,集合可以添加任意类型,默认所有类型为Object
但是存在多种类型的时候就不能用其中一种的特有方法了
泛型:
泛型类
修饰符 class 类名<类型E> {}//E可以看成变量名
方法中形参不确定
使用类名后面定义的泛型 所有方法都能用
泛型方法:
在方法申明上定义自己的泛型 只有本方法可以用
修饰符 <类型T> 返回值类型 方法名(类型名 变量名)
//传参个数不确定 可变数组e
public <E> void add(ArrayList<E>,E...e){
for(E element:e)//遍历
}
泛型接口:
使用:
实现类给出具体类型
实现类延续泛型,创建对象的时候再确定
修饰符 interface 接口名<类型>{}
泛型不具备继承性,但是数据具有
对于想要传递同一类事物(即有父子关系),可以使用通配符?限定范围
? extends E:可以传递E及其子类
? super E:E及其父类
public void method(ArrayList<? extends E> list)
树:
二叉查找树:
又叫二叉排序树、二叉搜索树
每一个节点上最多有两个子节点;任意节点左子树上的值都小于当前节点;任意节点右子树上的值都大于当前节点
存储:大右小左,一样不存
二叉树遍历方式:
前序:当前->左->右
对于子节点还有子节点,要先遍历完子节点的下部分
中序:左->当前->右
后序:左->右->中
层序遍历:顾名思义
平衡二叉树:
任意节点的左右子树高度差不超过1
旋转:添加节点的时候引起的不平衡所以需要旋转
根节点的左子树的左子树有节点插入导致不平衡 —— 一次右旋
根节点的左子树的右子树有有节点插入—— 先局部左旋再整体右旋
根节点的右子树的右子树有节点插入—— 一次左旋
根节点的右子树的左子树有节点插入 —— 先局部右旋再整体左旋
从添加的节点开始,不断往上找到不平衡的父节点为止
左旋:
把支点左旋降级,再晋升原来的右子节点
对于根节点参与:
右旋:
支点右旋降级变为右子节点,晋升原来的左子节点
对于根节点参与:右旋后左子节点的右子节点给根节点作为左子节点
左子节点晋级
红黑树:
自平衡的二叉查找树;不是高度平衡的;
红黑规则:
每一个节点或是红色的,或者是黑色的
根节点必须是黑色
如果一个节点没有子节点或者父节点,则该节点相应的指针属性值为Nil,这些Nil视为叶节点,每个叶节点(Nil)是黑色的
如果某一个节点是红色,那么它的子节点必须是黑色(不能出现两个红色节点相连的情况)
对每一个节点,从该节点到其所有后代叶节点的简单路径上,均包含相同数目的黑色节点;
添加节点:
默认是红色的(效率高)
Set:
无序、不重复、无索引
api与Collection基本一致
HashSet:
Hashset集合底层采取哈希表存储数据;哈希表是一种对于增删改查数据性能都较好的结构
哈希值:对象的整数表现形式
JDK8以前的底层原理
index=(len-1)&hashcode
重复的话判断equals,一样不存
对于JDK8以前新元素存入数组,老元素挂在新元素下面
JDK8以后反之,且当链表长度大于8,数组长度大于等于64时,自动转换为红黑树
hashset存储的是自定义的对象的话,要重写equals和hashcode
LinkedHashSet:
和hashset基本一致,但是有序(能保证储存和取出顺序一致)
原理:底层数据结构是依然哈希表,只是每个元素又额外的多了一个双链表的机制记录存储的顺序。
TreeSet:
不重复、无索引,可排序,默认从小到大,基于红黑树的数据结构
对于自定义对象的排序
方法一:接入Comparable接口,重写compareto,再指定比较规则
(在对象中重写哦
方法二:比较器排序:创建TreeSet对象时候,传递比较器Comparator指定规则
lambda表达式:
方式一和方式二同时存在方式二优先
集合的应用场景:
双列集合:
Map:
put:添加数据的时候键不存在,直接存入;键存在,会覆盖键值对,然后返回被覆盖的值,反之,没覆盖则返回null。
遍历:
键找值:
//获取所有的键
Set<String> keys=map.keySet();//keySet返回值是一个set集合
//通过遍历键获取值
for(String key:keys){
String value=map.get(key);//通过键获取值
}
键值对:
//获取所有键值对对象,放入set集合中
Set<Map.Entry<String, String>> entries = map.entrySet();//打后面的然后ctrl alt v自动生成
//遍历entries
for(Map.Entry<String, String> entry:entries){
String value=entry.getValue();
String key= entry.getKey();
}
forEach:
底层也是增强for遍历
map.forEach(new BiConsumer<String, String>() {
@Override
public void accept(String key, String value) {//可以用lambda表达式简化
}
});
Hashmap:
依赖hashCode方法和equals方法保证键的唯一
如果键存储的是自定义对象,需要重写hashcode和equals方法
如果值存储自定义对象,不需要重写hashCode和equals方法
LinkedHashMap:
有序,不重复,无索引
这里的有序指的是保证存储和取出的元素顺序一致
原理∶底层数据结构是依然哈希表,只是每个键值对元素又额外的多了一个双链表的机制记录存储的顺序。
TreeMap:
参考treeset
可变参数:
用于提供不确定参数个数的方法,底层实现是在内部创建了一个数组保存传入的参数
int sum=getsum(1,2,3,4,5)
public int getsum(int...args){
//相当于创建了args数组可以直接用
}
ps:形参中最多可以用一个可变参数;如果存在其他形参,可变参数要放在最后
Collections:
ArrayList<String> list=new ArrayList<>();
Collections.addAll(list,"156","1564487","178921","asds","asdsa");
Collections.shuffle(list);//打乱数据
不可变集合:
List<String> list=List.of("161","ashd","jasjd");//无法修改,只能查询
Set<String> set=Set.of("ajosd","asjdp");
Map的不可以集合:键不可以重复;最多可以有20个元素,即10个键值对。(因为参数列表可变参数要放在最后,但是map如果要实现的话要有2个可变参数)
但是可以使用ofEntries
HashMap<String,String> hashmap=new Hashmap<>();
//先add
Set<Map.Entry<String,String>> entries=hashmap.entrySet();//获取键值对集合
Map.Entry[] arr=entries.toArray(new Map.Entry[0]);//把键值对放到一个数组 因为会自适应长度,所以写0也行的
Map map=Map.ofEntries(arr);
=
Map<Object,Object> map=Map.ofEntries( hashmap.entrySet().toArray(new Map.Entry[0]) );
//JDK10后:copyof
Map<String,String> map=Map.copyOf(hashmap);
Stream流:
先得到一条Stream流(流水线),并把数据放上去
双列先转entry或者keyset
一堆零散数据需要是同种类型
stream接口中静态方法of的细节:方法的形参是一个可变参数,可以传递一堆零散的数据,也可以传递数组,但是数组必须是引用数据类型的,如果传递基本数据类型,是会把整个数组当做一个元素,放到Stream当中。
//单列
Stream<String> stream1=list.stream();
stream1.forEach(....);
==list.steam().forEach();
//双列hm
第一种
hm.keySet().stream().forEach(....);
第二种
hm.entrySet().stream()...
//数组 基本数据类型arr 引用数据类型arr2
Arrays.stream(arr).forEach();
Arrays.stream(arr2).forEach()
//一堆零散数据
Stream.of(1,2,3,4).forEach();
使用中间方法对流水线上的数据进行操作
concat尽量保持流一致,否则返回的是俩个类型的父类
中间方法,返回新的Stream流,原来的Stream流只能使用一次,建议使用链式编程
修改Stream流中的数据,不会影响原来集合或者数组中的数据
//过滤 留下姓张的
list.stream().filter(s.startWith("张")).forEach(打印);
//limit
list.stream(),limit(n)//获取n个
//去重
list.stream().distinct()...
//合并
Stream.concat(list1.stream(),list2.stream())...;
//转换
list.stream().map(s->Integer.parseInt(s.split("-")[1]))...//与下面一样
使用终结方法对流水线上的数据进行操作
//收集 toArray
Object[] arr=list.stream().toArray()//不指定
//指定
String[] arr=list.stream().toArray(value->new String[value]);
//collect
List<String> list=list.stream().collect(Collectors.toList());//收集到list中
//同理toSet Set不会收集到重复的
方法引用:
引用处必须是函数式接口
被引用的方法必须已经存在
被引用方法的形参和返回值需要和抽象方法保持一致
被引用方法的功能要满足当前要求
符号::
引用静态方法:
格式:类名::静态方法
list.stream().map(Interge::parseInt)...//引用了Interge类中的parseInt
引用成员方法:
格式:对象::成员方法
其他类:其他类对象::方法名
本类:this::方法名(引用处不能是静态方法)
父类:super::方法名(引用处不能是静态方法)(因为静态方法没有this、super
利用其他类对象的时候要先创建对象
引用构造方法:
格式:类名::new
注意构造方法的形参和返回值是否和需要的一样
其他调用方式:
使用类名引用成员方法
类名::成员方法
引用的局限取决于抽象类第一个参数是什么类型那就只能用什么类型的引用
引用数组的构造方法
数据类型[]::new
int[]::new
方法引用改写:
list.stream().toArray(Integer[]::new);
数据类型需要和流中类型保持一致