1.集合
1.1Collection
单列集合,一个元素只能存一个值。
Collection<>是祖宗接口,子分支有List<>和Set<>
List<>特点:可重复、有序、有索引
Set<>特点:不重复、无序、无索引
Collection遍历方式一:迭代器Iterator
Iterator<String> it = names.iterator(); //names是前边自己造的一个集合 while (it.hasNext()) { String name = it.next(); System.out.println(name); }Collection遍历方式二:增强For循环
格式:for(元素的数据类型 变量名:数组或集合){} 例如:for(Student student:students) 这个前边用过,不知道有没有贴代码
Collection遍历方式三:Lambda表达式
用的是forEach方法,但是匿名内部类需要用lambda简化
names.forEach(newConsumer<String>() { @Override public void accept(String s) { System.out.println(s); } }); 简化为names.forEach(s -> System.out.println(s));三种遍历的区别:
- 迭代器遍历并删除的时候不能用list.remove(name),需要直接用迭代器的方法删除,it.remove()。适用于没有索引的集合
- for循环删除,用i--从大到小遍历,或者用i++从小到大删除但是每次删除之后进行一次i--避免漏删
- lambda遍历删除,removeIf
iterator可以遍历并删除,增强for和lambda一般只用来遍历不适合删除,且这两个只适合有索引的
1.1.1 List集合
List常用的方法有:add、remove、set、get。ArrayList适合查找,LinkedList适合增删。
1.1.1.1 ArrayList
基于数组存储数据,数组是一块连续的空间,根据索引查询的速度快,增删速度慢
JDK8 的 ArrayList 无参构造初始化是空数组,第一次add 元素时扩容到 10;之后每次添加元素,如果 size+1 超过底层数组长度,就扩容为原来的 1.5倍。
1.1.1.2 LinkedList
基于链表存储数据,链表是不连续的,每个结点存储了当前的数据值和下一个结点的地址。查询速度慢,每次都要从头节点开始查找。增删相对快。
LinkecList是基于双链表实现的,存了前一个结点的地址和后一个结点的地址。
由于双链表对首尾数据操作很快,O(1),对首尾结点的操作有很多特有的方法:
addFirst、addLast、getFirst、getLast、removeFirst、removeLast 可以用来实现栈、队列
1.1.2 Set集合
- HashSet:无序、不重复、无索引
- LinkedHashSet:有序、不重复、无索引
- TreeSet:排序、不重复、无索引(排序是从小到大排)
Java中每个对象都有自己的哈希值,是一个int类型的整数,可以用hashCode调用查看,每次调用返回的都是同一个值不会变化。
HashSet是基于哈希表存储数据的,哈希表在jdk8之前是数组和链表,jdk8之后是数组、链表和红黑树。哈希表创建一个默认长度为16的数组,默认加载因子是0.75,命名为table[]。存放数据的时候就(n-1)&哈希值,结果是几,就存到对应的数组下标中。
(n-1)&哈希值,这个运算是与运算,是一种简便计算方法,例子如下:
String str2="zzy"; System.out.println(str2.hashCode()); //得到哈希值是121145
假设目前新创建的table[]还没有存放数据,所以长度还是16,那么n=16,n-1=15=1111(二进制)
hash=121145=11101100100111001(二进制)
11101100100111001&1111=1001=9,所以存到table[9]的位置
HashSet的存放跟408考研中的存放并不一致,算法不是很相同,不要混淆。
如果遇到数组下标一致的情况:
- JDK8之前是新元素存进去,旧元素挂在新元素下边(头插)
- JDK8之后是新元素直接挂在旧元素下边(尾插、408的拉链寻址就是尾插)
哈希表扩容跟加载因子有关,我们提到默认加载因子是0.75,16*0.75=12,所以当数组存了12个数据之后,就会扩容,扩一倍变成32。
当一个坑位的挂载数据超过8个,并且数组长度超过64之后,会自动变成红黑树。(红黑树可以自己搜索了解,什么黑叔、红叔,叔变爷不变)
HashSet去重:在对象页面右键generate选择equals和hashCode一直点击next会自动重写。
TreeSet会自动排序,但是如果对象里边有多个数据,他会不知道按照什么进行排序。有两种方法:
- 实现comparable接口然后重写compareTo方法
- public TreeSet(Comparotor c) 集合自带比较器对象 用Double.compare()可以避免0.x被int强转成0
1.2 Map
Map是双列,键值对,键不可以重复,值可以重复。集合的特点都是根据键决定的。
- HashMap(无序、不重复、无索引) -> LinkedHashMap(有序、不重复、无索引)
- TreeMap(从小到大升序、不重复、无索引) key不可以为null,因为要排序。
遍历方式:
- 键找值:keySet
- 键值对:entrySet
- lambda:forEach
//keySet Set<String> set=map.keySet(); for (String key : set) { System.out.println(key+"->"+map.get(key)); } //entrySet Set<Map.Entry<String,Integer>> entrys=map.entrySet(); for(Map.Entry<String,Integer> entry : entrys){ String key=entry.getKey(); Integer value=entry.getValue(); System.out.println(key+"===>"+value); } //forEach map.forEach((key, value)->System.out.println(key+"->"+value));关于HashMap、LinkedHashMap、TreeMap这三个的底层原理与set方法一致,因为set方法穿透进去会发现底层就是map方法。
2. Stream流
jdk8新增的一套api,用于操作数组或集合的数据。
Stream是一个接口,java已经写好了它的实现方法:stream,可以直接调用。
集合获取stream流:直接list.stream
数组获取,先写一个数组names,然后Arrays.stream(names)或者Stream.of(names)
中间方法:
终结方法:调完之后不可以再继续调用其他的
max和min这两个只能拿一个数据,比如最大薪资有两个人,他只能输出一个人。
收集流可以用collect
可变参数:一个方法只能有一个可变参数,形式是:参数类型...参数名,如int...nums,并且只能放在最后,例如sun(int age,int...nums),age和nums的顺序不能变化。
3.File
File是java.io下的类,File类的对象,File只能对文件本身进行操作,不能操作文件内的数据。
绝对路径:带盘符,比如"D:\mypic"
相对路径:不带盘符,默认到idea下找工程文件。
简易指令:
- createNewFile() 创建新文件
- mkdir()创建一级文件夹
- mkdirs()创建多级文件夹
- delete删除文件,但是只能删除空的
- list遍历文件名/listFiles遍历文件对象
4.方法递归
递归就是方法自己调用自己,但是使用时要避免陷入死循环。
递归三要素:1.公式 2.有终结点 3.方向走向终结点。
要从用户思维来考虑方法。
5.字符集
标准ASCII使用一个字节存储一个字符,首位是0,可以存储128个;
GBK汉字内码扩展规范,一个字占用2个字节。规定汉字的第一个字节的第一位必须是1
UTF-8是Unicode(万国码)的一种编码方案,采取可变长编码方案,分为四个长度区:一个字节,两个字节,三个字节,四个字节。 UTF-8中汉字占三个字节。
编码解码方法:
- 编码:getBytes() 拿到二进制编码
- new String(字节数组) 拿到内容字符