API
API: 应用程序编程接口
, 即已经写好的东西, 可以直接使用
String
- 字符串的内容是不会更改的
String name = "abc";
name = "def";
// name = "def" 是创建了一个新的字符串, 然后把引用赋给了 name
- 构建方法
String s = "abc"; // 直接赋值
String s = new String(); // 创建一个空字符串
String s = new String("abc"); // 根据传递的字符串内容构建一个新字符串
char[] chs = {'a', 'b', 'c'};
String s = new String(chs); // 根据字符数组
byte[] bytes = {97, 98, 99, 100};
String s = new String(bytes); // 根据字节数组
- 使用双引号直接赋值时, 如果该字符串在
串池
中已存在, 会复用
字符串
String s1 = "abc";
String s2 = "abc";
// s1, s2 指向同一个串池中的地址
- 使用
new
创建时, 每次new
会在堆内存
中开辟一个新空间, 不会复用
char[] chs = {'a', 'b', 'c'};
String s1 = new String(chs);
String s2 = new String(chs);
// s1, s2 指向不同的堆内存中的地址
-
字符串比较
-
==
比较基本数据类型时, 比较数据值
; 比较引用数据类型时, 比较地址值
因此对于String
, 比较的是地址值
-
s1.equals(s2)
比较内容, 完全一样才是 true -
s1.equalsIgnoreCase(s2)
比较内容, 忽略大小写
-
-
访问字符
s1.charAt(i)
-
转成字符数组
char[] chs = s1.toCharArray();
StringBuilder
可以看成一个容器, 创建之后里面的内容可以改变
因此拼接字符串时, 不会每次产生一个新的字符串, 提高效率
StringBuilder s = new StringBuilder("abc");
s.append("def");
s.reverse();
int len = s.length();
String str = s.toString();
StringJoiner
StringJoiner s = new StringJoiner(间隔符号, 开始符号, 结束符号);
e.g. StringJoiner s = new StringJoiner("---", "(", ")");
s.add("abc"); // 应该是在中间添加数据
int len = s.length();
String str = s.toString();
System
System.exit(0); // 虚拟机正常停止, 非 0 是异常停止
long l = System.currentTimeMillis(); // 从时间原点到运行这行代码的时间毫秒值形式
// 可以两行代码之间相减检查中间代码的运行时间
System.arraycopy(arr1, 0, arr2, 0, 10);
// System.arraycopy(数据源数组(被拷贝), 从数据源第几个索引开始拷贝, 目的地数组, 目的地索引, 拷贝的个数);
// 若 arr1, arr2 都是基本数据类型, 则类型需要一样
// 若 arr1, arr2 都是引用数据类型, 则子类数组可以把地址值拷贝给父类数组
Runtime
Runtime r1 = Runtime.getRuntime(); // 获取 Runtime 对象, 地址值固定(final)
r1.exit(0); // 停止虚拟机
int cpuProcessors = r1.availableProcessors(); // 获取 CPU 的线程数
long maxM = r1.maxMemory(); // JVM 能从系统获取总内存大小(单位 byte)
long totM = r1.totalMemory(); // JVM 已从系统获取总内存大小(单位 byte)
long freeM = r1.freeMemory(); // JVM 剩余内存(单位 byte)
r1.exac("写 cmd 命令");
Object
toString
Student stu = new Student();
String s = stu.toString(); // 返回对象的字符串表示形式(地址值)
sout(s); // 等同于 sout(stu);
// 可以重写 toString 方法以打印对象的属性信息
equals
Student s1 = new Student();
Student s2 = new Student();
boolean result = s1.equals(s2); // 比较地址值, 为 false
// 可以重写 equals 方法以比较对象的属性信息
// String.equals() 先判断参数是否为字符串, 是字符串再比较内容
// StringBuilder.equals() 继承 Object 的, 比较地址值
clone
clone
需要重写, 并让类实现 Cloneable
接口
-
[[D:/java_code/user/User.java|e.g.User]]
public class User implements Cloneable { // 注意 Cloneable ... @Override public String toString() { return name + ", " + id; } @Override protected Object clone() throws CloneNotSupportedException { // 注意 throws CloneNotSupportedException // 调用父类中的 clone 方法 return super.clone(); } }
-
Cloneable
这个接口中没有抽象方法, 表示当前接口是一个标记行接口 -
实现
Cloneable
表示当前类的对象可以被克隆 -
[[D:/java_code/user/Test.java|e.g.Test]]
public static void main(String[] args) throws CloneNotSupportedException { // 注意 throws CloneNotSupportedException User u1 = new User("zhangsan", "123"); User u2 = (User)u1.clone(); // 注意强转 // 会调用重写的 toString System.out.println(u1); System.out.println(u2); }
-
浅克隆
- 基本数据类型: 完全拷贝数据值
- 引用数据类型: 完全拷贝地址值
Object.clone()
是浅克隆
-
深克隆
- 基本数据类型: 完全拷贝数据值
- 字符串: 复用
- 引用数据类型: 重新创建新的
- 重写
clone
以深克隆 e.g.
// 假设 User 中有一个成员为 data 数组 @Override protected Object clone() throws CloneNotSupportedException { int[] data = this.data; int[] newData = new int[data.length]; for (int i = 0; i < data.length; i++) { newData[i] = data[i]; } User u = (User)super.clone(); // 浅克隆 u.data = newData; // 对引用数据类型的成员特别处理 return u; }
- 实际开发中, 一般使用序列化再反序列化
- 使用第三方工具如
Jackson
或者Gson
, 将对象转换为JSON
字符串, 再从JSON
字符串重建新的对象
Objects
一个对象工具类, 注意不是 Object
, 因为有 s
boolean flag = Objects.isNull(对象);
boolean flag = Objects.nonNull(对象);
boolean flag = Objects.equals(对象1, 对象2);
isNull
与nonNull
相反equals
会先作非空判断, 再比较两个对象
BigInteger
BigInteger 是 Java 提供的高精度计算类, 可以很方便地解决高精度问题。
初始化
import java.io.PrintWriter;
import java.math.BigInteger;
class Main {
static PrintWriter out = new PrintWriter(System.out);
public static void main(String[] args) {
// 将字符串以十进制的形式创建 BigInteger 对象
BigInteger a = new BigInteger("12345678910");
out.println(a); // 12345678910
// 将字符串以指定进制的形式创建 BigInteger 对象
BigInteger b = new BigInteger("1E", 16);
out.println(b); // 30
// 获取一个范围为 0 ~ 2^31-1 的随机数
BigInteger c = new BigInteger(31, new Random());
out.println(c); // 一个范围为 0 ~ 2^31-1 的随机数
// 参数不超过 long, 静态方法获取对象, 内部有优化
// 会将 -16 ~ 16 先创建好 BigInteger 对象, 多次获取不会重新创建
BigInteger d = BigInteger.valueOf(100);
out.println(d); // 100
out.close();
}
}
对象一旦创建, 内部记录的值不能发生改变
基本运算
以下均用 this 代替当前 BigIntger :
函数名 | 功能 |
---|---|
abs() | 返回 this 的绝对值 |
negate() | 返回 - this |
add(BigInteger val) | 返回 this + val |
subtract(BigInteger val) | 返回 this - val |
multiply(BigInteger val) | 返回 this * val |
divide(BigInteger val) | 返回 this / val |
remainder(BigInteger val) | 返回 this % val |
divideAndRemainder(BigInteger val) | 返回一个数组, 包含 this / val 和 this % val |
mod(BigInteger val) | 返回 this mod val |
pow(int e) | 返回 this^e |
and(BigInteger val) | 返回 this & val |
or(BigInteger val) | 返回 this |
not() | 返回 ~ this |
xor(BigInteger val) | 返回 this ^ val |
shiftLeft(int n) | 返回 this << n |
shiftRight(int n) | 返回 this >> n |
max(BigInteger val) | 返回 this 与 val 的较大值 |
min(BigInteger val) | 返回 this 与 val 的较小值 |
bitCount() | 返回 this 的二进制中不包括符号位的 1 的个数 |
bitLength() | 返回 this 的二进制中不包括符号位的长度 |
getLowestSetBit() | 返回 this 的二进制中最右边的位置 |
compareTo(BigInteger val) | 比较 this 和 val 值大小 |
toString() | 返回 this 的 10 进制字符串表示形式 |
toString(int radix) | 返回 this 的 raidx 进制字符串表示形式 |
intValue(BigInteger val) | 转为 int 类型, 超出范围数据出错 |
BigDecima
- 用于小数的精确运算
- 用来表示很大的小数
正则表达式
- 校验字符串是否满足规则
- 在一段文本中查找满足要求的内容
如何书写
字符类
代码 | 范围 |
---|---|
[abc] | a,b,c |
[^abc] | 除 a,b,c |
[a-zA-z] | a-z, A-Z |
[a-d[m-p]] | a-d, m-p |
[a-z&&[def]] | d,e,f |
[a-z&&[^bc]] | a, d-z |
[a-z&&[^m-p]] | a-l, q-z |
预定义字符(只匹配一个字符)
字符 | 范围 |
---|---|
. | 任意字符 |
\d | 数字 |
\D | 非数字 |
\s | 一个空白字符 |
\S | 非空白字符 |
\w | 英文, 数字, 下划线 |
\W | 一个非单词字符(非"英文, 数字, 下划线") |
[[D:/java_code/regex/Test.java|e.g.]]
插件
any-rule
, 支持 idea
, vscode
爬虫
[[D:/java_code/regex/Find.java|基础爬取和有条件的爬取]]
贪婪爬取与非贪婪爬取
暂略
捕获分组和非捕获分组
暂略
时间相关类
暂略
包装类
用一个对象, 把基础数据类型包起来
byte -> Byte
short -> Short
char -> Character
int -> Integer
long -> Long
float -> Float
double -> Double
boolean -> Boolean
创建
public static void main(String[] args) {
Integer i1 = new Integer(1);
Integer i2 = new Integer("1");
Integer i3 = Integer.valueOf(123);
Integer i4 = Integer.valueOf("123");
Integer i5 = Integer.valueOf("123", 8);
sout(i5); // 8 进制的 123 -> 10 进制的 83
// valueOf 会获取提前创建的 -128 ~ 127 的对象
Integer i6 = Integer.valueOf(127);
Integer i7 = Integer.valueOf(127);
sout(i6 == i7); // true
}
JDK5 以后可以自动装箱, 自动拆箱
, 赋值和运算直接写即可
Integer i1 = 10;
Integer i2 = 20;
Integer i3 = i1 + i2;
int i4 = i1;
Integer 成员方法
String str1 = Integer.toBinaryString(100); // 把整数转成 2 进制
String str2 = Integer.toOctalString(100); // 把整数转成 8 进制
String str3 = Integer.toHexString(100); // 把整数转成 16 进制
int i = Integer.parseInt("123"); // 字符串类型的整数转成 int
// (8 种包装类, 除 Character 都有对应的 parseXxx 方法)
操作数组的工具类 Arrays
int[] a = {1, 2, 3};
String s = Arrays.toString(a); // 数组拼接成字符串
int pos = Arrays.binarySearch(a, 2); // 二分查找
int[] b = Arrays.copyOf(a, 10); // 拷贝数组(原数组, 新数组长度)
int[] c = Arrays.copyOfRange(a, 1, 2); // 拷贝数组, 指定范围
Arrays.fill(a, 0); // 填充数组
Arrays.sort(a); // 默认方式排序数组
Arrays.sort(a, cmp); // 指定方式排序数组
cmp 举例
Integer[] arr = {2, 3, 1, 5, 6, 7, 8, 4, 9};
// 底层原理:
// 插入排序 + 二分查找
// 认为前面有序, 后面无序
// 遍历无序序列, 记当前遍历元素为 o1
// 向有序序列中插入 o1, 先利用二分查找确定 o1 的插入点
// 比较 o1 与当前二分到的插入点的元素 o2 的规则为 compare
Arrays.sort(arr, new Comparator<Integer>(){
@Override
public int compare(Integer o1, Integer o2) {
return o1 - o2; // 升序排序
}
// 返回值:
// 负数: 表示当前要插入的元素是"小"的, 放在前面
// 正数: 表示当前要插入的元素是"大"的, 放在前面
// 0 : 表示当前要插入的元素和现在的元素一样, 也会放在后面
});
Lambda 表达式
Arrays.sort(arr, (Integer o1, Integer o2) -> {
return o1 - o2;
});
函数式编程
面向对象: 先找对象, 让对象做事情
函数式编程: 忽略面向对象的复杂语法, 强调做什么, 而不是谁去做
格式
() -> {}
-
可以简化匿名内部类的书写
-
只能简化函数式接口的匿名内部类的书写
- 函数式接口: 有且仅有一个抽象方法的接口, 接口上方可以加
@FunctionalInterface
- 若不止一个, 则不清楚是替代哪个方法, 接口上方也不能加
@FunctionalInterface
- 函数式接口: 有且仅有一个抽象方法的接口, 接口上方可以加
-
省略格式
可以(从对应的函数式接口)推导得到的东西可以省略不写- 参数类型可以省略
Arrays.sort(arr, (o1, o2) -> { return o1 - o2; });
- 如果只有一个参数,
()
可以省略 - 如果只有一行, 大括号, 分号, return 可以省略, 需要同时省略
Arrays.sort(arr, (o1, o2) -> o1 - o2);
Java 集合对应 C++ STL
集合类不能直接存储基础数据类型, 因为其设计用于存储对象
, 只能存储对应的包装类
List<Integer> a = new ArrayList<>(); // vector
List<Integer> a = new LinkedList<>(); // list
Set<Integer> s = new HashSet<>(); // unordered_set
Set<Integer> s = new TreeSet<>(); // set
Map<String, Interger> mp = new HashMap<>(); // unordered_map
Map<String, Interger> mp = new TreeMap<>(); // map
Stack<Integer> st = new Stack<>(); // stack
Queue<Integer> q = new LinkedList<>(); // queue
Deque<Integer> q = new ArrayDeque<>(); // deque
PriorityQueue<Integer> q = new PriorityQueue<>(); // priority_queue