字符集
String -> 字符序列 (中文\英文)
JVM -> 1个char = 2个byte Unicode
操作系统 -> windows:GBK->GB2312 Linux:UTF-8 ISO8859-1
UTF-8: 1char = 3byte
gbk: 1char = 2byte
编码、解码
byte[] getBytes(); -> 根据默认字符集来编码
new String(bs); -> 按照默认字符集解码
byte[] getBytes(“charset”) -> 按照指定字符集编码
new String(bs1, “gbk”); -> 按照指定字符集解码
String str = "你好";
// 字符 -> 字节 (编码)
byte[] bs = str.getBytes();
System.out.println(str);
// [-28, -67, -96, -27, -91, -67]
System.out.println(Arrays.toString(bs));
// [-60, -29, -70, -61]
byte[] bs1 = str.getBytes("GBK");
System.out.println(Arrays.toString(bs1));
// 字节 -> 字符 (解码)
String s1 = new String(bs);
System.out.println("s1: " + s1);//s1:你好
String s2 = new String(bs1, "gbk");
System.out.println("s2: " + s2);//s2: 你好
解决乱码
// 手动制造乱码
String str = "你好";
byte[] bs = str.getBytes();
String s = new String(bs, "ISO8859-1");
System.out.println(s); // ä½ å¥½
// ----------------------
// 将 s 的乱码解决
/*byte[] b = s.getBytes("ISO8859-1");
s = new String(b, "UTF-8");
System.out.println(s);*/
// 简化成一句话
s = new String(s.getBytes("ISO8859-1"), "UTF-8");
System.out.println(s);
泛型
接口/类<泛型/类型>
将类型作为参数, 编译时有效, 规范程序员的 -> 编译时语法
泛型的本质是, 支持Object类型
使用
定义泛型: 类/接口的定义上就加上
在这个类的方法中, 具体类型就可以使用 E 来代替
泛型的意义: 当类/方法 可以支持任意类型时, 就可以将类型动态传入
不确定类型, 但是又想要具体类型
public class GenericClass<T, L> {
public void print(T a, L b) {
System.out.println(a + "," + b);
}
public class Demo03Generic {
public static void main(String[] args) {
GenericClass gc =new GenericClass();//使用时没规定类型,就可以使用任意类型object
gc.print(1, "hehe");
GenericClass<Date, String> gc1 = new GenericClass<>();//规定了类型
gc1.print(new Date(), "hello");
GenericClass<Date, Date> gc2 = new GenericClass<>();
gc2.print(new Date(), new Date(0));
}
//1,hehe
//Thu Jul 23 20:36:14 CST 2020,hello
//Thu Jul 23 20:36:14 CST 2020,Thu Jan 01 08:00:00 CST 1970
数据结构
数据结构: 存储数据的方式
数组, 链表, 栈, 队列, 二叉树
数组结构: ArrayList
链表结构(双向链表): LinkedList
队列: Queue
栈: Stack, Deque
- 线性结构有四种:栈、队列、链表、数组
栈
弹夹
push():压栈
pop():弹栈
Stack: 先进后出, 后进先出
public class Stack<T>{
private Object[] data; // 定义一个用于存数据的仓库
private int size; // 表示栈中的元素个数
public Stack(int cap){ // cap: 表示栈的最大容量
data = new Object[cap];
}
// 压栈
public void push(T a){
data[size++] = a;
}
// 弹栈 -> 从栈顶开始
public T pop() {
T a = (T) data[size-1];
size --;
return a; // return data[--size]
}
// 获取元素个数
public int size() {
return size;
}
// 判断栈是否满
public boolean isFull() {
return size == data.length;
}
// 判断栈是否为空
public boolean isEmpty() {
return size == 0;
}
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[");
for (int i = 0; i < size; i++) {
sb.append(data[i]);
sb.append(",");
}
if (size != 0) {
// 去掉最后一个逗号
sb.delete(sb.length() - 1, sb.length());
}
sb.append("]");
return sb.toString();
}
}
public static void main(String[] args){
Stack<Integer> stack = new Stack(8);
while (!stack.isFull()) {
stack.push(3);
}
System.out.println(stack);
while (!stack.isEmpty()) {
int a = stack.pop();
System.out.println(a);
}
System.out.println(stack);
}
//[3,3,3,3,3,3,3,3]
//3
//3
//3
//3
//3
//3
//3
//3
//[]
链表
结点为单位, 只能从head访问
末尾添加元素, 插入元素, 获得指定位置的元素, 删除指定位置元素
// 单向链表
public class SingleLinked<T>{
// 结点类型
private class Node {
private T data; // 用于存储数据
private Node next; // 用于存下一个结点的地址
public Node(T data) {
this.data = data;
}
}
// 最开始初始化链表时, head不存储数据, next是null
private Node head = new Node(null);
// 添加新的结点
public void add(T a){
// 寻找next=null 的结点
Node node = head;
while (node.next != null) {
node = node.next;
}
// node.next == null
node.next = new Node(a);
}
// 得到index-1位置上的元素
private Node getIndexPreNode(int index) {
Node node = head;
// 要找到index-1这个位置的Node
for (int i = 0; i < index; i++) {
node = node.next;
}
return node;
}
// 在index位置上插入元素
public void insert(int index, T a) {
Node node = getIndexPreNode(index);
Node node3 = new Node(a);
node3.next = node.next;
node.next = node3;
}
// 获得index位置上的元素
public T get(int index) {
Node node = getIndexPreNode(index);
return node.next.data;
}
// 删除index位置上的元素
public void remove(int index) {
Node node = getIndexPreNode(index);
node.next = node.next.next;
}
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[");
Node node = head;
while (node.next != null) {
node = node.next;
sb.append(node.data);
sb.append(", ");
}
sb.append("]");
return sb.toString();
}
public static void main(String[] args){
SingleLinked<Integer> linked = new SingleLinked();
linked.add(3);
linked.add(5);
linked.add(2);
linked.insert(1, 8);
System.out.println(linked);
System.out.println(linked.get(3));
linked.remove(2);
System.out.println(linked);
//[3, 8, 5, 2, ]
//2
//[3, 8, 2, ]
数组和链表的优劣势比较:
1.数组的物理空间连续, 碎片化空间使用不彻底
链表物理空间不连续, 空间使用彻底
2.链表只能从head开始访问, 访问效率低
数组可以随机访问任意元素, 访问效率高
3.链表插入/移除元素, 只需要操作1~2个元素, 效率高
数组插入/移除元素, 涉及到大量元素的移动, 效率低
List有序列表
- 允许重复元素
- 有序号/下标,添加顺序就是访问顺序
- 比collection多了index下标,可以访问获取某一个元素
- 有两个实现类:ArrayList和LinkedList
- List的遍历/迭代: 可以用
Iterator
forEach
for
API
可以使用index下标
void add(int index, E element)
void addAll(int index, Collection<? extends E> c)
E set(int index, E element)
E get(int index)
List.subList(index1,index2)获取子集
int indexOf(Object o)
int lastIndexOf(Object o)
E remove(int index)迭代删除,详见day15
List<String> list = new ArrayList<>();
list.add("张三丰");
list.add("张无忌");
list.add("赵敏");
list.add("张三丰");
for (int i = 0; i < list.size(); i++) {
String s = list.get(i);
System.out.println(s);
// list.remove(s);
list.remove(i);
i--;
}
System.out.println(list);
集合的框架
1.Collection(I):
|- List(I) -> 顺序结构(数组和链表):有序,允许有重复值、null值
|- ArrayList - 底层数据结构:数组,线程不安全、效率高,查询快、增删慢
|- LinkedList - 底层数据结构:双向链表,底层实现:节点(node)+下一个节点引用(next,pre),
线程不安全、效率高,查询慢、增删快
|- Vector - 数组,线程安全、效率低,查询快、增删慢
ArrayList和vector区别:1.效率 2.扩容机制:arralist1倍,后面两倍
linklist和arraylist区别: 上面总结
|- Queue(I) -> 队列结构(普通队列)、先进先出,底层实现:数组/链表
|- Deque(I) 队列结构(双端队列, 栈)
实现类 |- LinkedList
|- Set(I) -> 散列结构、无序,是map的映射,是map的key值、不允许重复
|- HashSet底层数据结构:哈希表(散列表),存储位置:hashcode计算,判断唯一:equals,允许有null值
实现类 |- LinkedHashSet - 底层数据结构:哈希表,有序且唯一,
|- SortedSet(I)- TreeSet二叉树 -底层数据结构:红黑树,作用:排序,有序且唯一,如何保证元素唯一:equals、0则为相同
以上三个类区分:排序用treeset,有序集合用LinkedHashSet,HashSet用来存储普通数据,
List和Set的区别: 有序性
唯一性
获取元素
2.Map 底层数据结构:哈希表,底层实现:hash值配合使用的数组和链表
迭代方式:keyset,values,entryset
HashMap 就是Map的实现、特点同上,无序的,key和value都允许有null值、但key上null只能有一个,
如何保证key值唯一:hashCode和equals判断,线程不安全、效率高,初始容量:16、
加载因子(扩容):0.75倍开始扩容为原来的两倍、扩容方法resize()
实现类:LinkedHashMap:独有特点:有序、按插入顺序排序,key和value都允许有null值
TreeMap 底层数据结构:红黑树,作用:根据key排序
HashTable 底层数据结构:哈希表,线程安全、效率低,key和value都不允许有null值,无序
ConcurrentHashMap 底层实现:sagment数组+HashEntry数组,
特点:锁分离,线程安全、效率低,作用:解决并发问题、效率比hashtable快一些,无序
hashMap和hashTable区别:线程安全效率
可否解决并发(多线程)
继承自
hashmap与treemap区别,前面用于增删改,后面用于排序
3.Comparable和Comparator
4.集合的遍历:
for循环
迭代器:next,remove
foreach
foreach和迭代器区别:不能作删除
for循环和迭代器区别:有下标用for循环,arraylist;linkedlist用迭代器
5.Collections:java.util包下类
常用方法:sort()排序
shuffle()打乱
copy()复制