02.API
API
Application Programming Interface 应用程序编程接口
字符串
String
-
程序中所有字符串文字, 都为此类的对象
-
字符串不可变, 它们的值在创建后不能被改变
-
创建对象的方式
-
String name = "xxx"
-
String name = new String(String original)
-
String name = new String(char[] chs)
-
需求: 修改字符串的内容
- 如: abc – {‘a’, ‘b’, ‘c’} – {‘Q’, ‘b’, ‘c’} – Qbc
1
2
3char[] chs = {'a', 'b', 'c', 'd'};
String s4 = new String(chs);
sout(s4); // abcd
-
-
String name = new String(byte[] chs)
-
应用场景: 在网络当中传输的数据都是字节信息, 一般要将字节信息进行转换, 转成字符串, 此时就要用到这个构造
1
2
3byte[] bytes = {97, 98, 99, 100};
String s5 = new String(bytes);
sout(s5); // abcd
-
-
-
内存模型
-
当使用双引号直接赋值时, 系统会检查该字符串在串池中是否存在,不存在则创建新的, 存在则复用 (节约内存)
-
每次 new 都会创造一个新空间, 这种方式创建对象不会复用 (占内存)
-
-
常用方法
- 字符串比较
boolean equals()
boolean equalsIgnoreCase()
- int compareTo(String s) : 对字符串进行字典序比较
- 字符串遍历
char charAt(int index)
: 根据索引返回字符int length()
- 字符串比较
-
字符串截取
String substring(int beginIndex, int endIndex)
String substring(int beginIndex)
- 字符串替换
String replace(target, replacement)
StringBuilder
-
StringBuilder 可以看成是一个容器, 创建之后里面的==内容是可变==的
-
作用: 提高字符串的操作效率 (拼接和反转字符串时常用StringBuilder)
-
构造方法
StringBuilder strb = new StringBulder()
StringBuilder strb = new StringBulder(String str)
-
常用方法
StringBuilder append(任意类型)
: 添加数据, 并返回对象本身StringBuilder reverse()
: 反转容器中的内容int length()
: 返回长度String toString()
: 将StringBuilder转换成String
StringJoiner
-
与 StringBuilder 一样可以看成是一个容器, 创建之后里面的==内容是可变==的
-
作用: 提高字符串的操作效率, 而且代码编写更加简洁, 但是目前市场上很少有人用(JDK8后出现的)
-
构造方法
StringJoiner sj = new StringJoiner(间隔符号)
: 创建一个对象, 指定拼接时的间隔符号StringJoiner sj = new StringJoiner(间隔符号, 开始符号, 结束符号)
: 创建一个对象, 指定拼接时的间隔符号、开始符号、结束符号
-
常用方法
StringJoiner add(添加的内容)
int length()
String toString()
java已经写好的类, java在底层对它们做了一些处理, 使得打印对象不是地址值而是属性值
字符串原理
-
字符串存储的内存原理
- 直接赋值会复用字符串常量池中的
- new 出来不会复用, 而是开辟一个新空间
-
==
比较的到底是什么- 基本数据类型比较数据值
- 引用数据类型比较地址值
-
字符串拼接的底层原理
-
无变量直接拼接: 会复用串池中的字符串
-
有变量拼接
-
JDK8前:
String s2 = s1 + "b"
相当于new StringBuilder().append(s1).append("b").toString()
-
JDK8后: 预估空间, 创建数组
-
-
结论: 如果很多字符串变量拼接, 不要直接 + , 在底层会创建多个对象, 浪费时间, 浪费空间 (建议使用StringBuilder)
-
-
StringBuilder提高效率原理图
-
StringBuilder源码分析
- 默认创建一个长度为16的字节数组
- 添加的内容长度小于16, 则直接存
- 添加的内容长度大于16, 则扩容 (原来容量 * 2 + 2)
- 如果扩容后还不够, 则以实际长度为准扩容
ArrayList
-
集合和数组的对比
-
数组长度固定; 集合长度可变 (自动扩容)
-
数组可以存基本数据类型和引用数据类型; 集合可以存引用数据类型, 如果要存基本数据类型, 只能存包装类
基本数据类型 对应的包装类 byte Byte short Short char Character int Integer long Long float Float double Double boolean Boolean
-
-
泛型(<E>): 集合中存储数据的类型
-
创建集合对象
ArrayList<数据类型> list = new ArrayList<>()
-
ArrayList 时 Java 已经写好的一个类, 这个类在底层做了一些处理
- 打印对象不是地址值, 而是集合中存储数据内容
-
成员方法
- 增
boolean add(E e)
: 返回值表示是否添加成功
- 删
boolean remove(E e)
: 返回值表示是否删除成功E remove(int index)
: 删除指定索引的元素, 返回被删除的元素
- 改
E set(int index, E e)
: 返回原来的元素
- 查
E get(int index)
int size()
- 增
Math
-
常用方法
int abs(int a)
double ceil(double a)
: 向上取整double floor(double a)
: 向下取整int round(float a)
: 四舍五入int max(int a, int b)
double pow(double a, double b)
: b可以是负数或小数double sqrt(double a)
double cbrt(double a)
double random()
: 返回值为double的随机值, 范围[0.0, 1.0)
System
-
常用方法
void exit(int status)
: 终止当前java虚拟机(0 : 正常停止;1 : 异常停止)long currentTimeMillis()
: 返回当前系统的时间毫秒值形式(时间原点 1970.1.1 8:0:0)void arraycopy(数据源数组, 起始索引, 目的地数组, 起始索引, 拷贝个数)
: 数组拷贝
-
输出语句
System.out.println()
- System : 类名
- out : 静态变量
- System.out : 获取打印的对象
- println() : 方法
- 参数 : 表示打印的内容
- 核心逻辑
- 当我们打印一个对象的时候, 底层会调用对象的toString方法, 把对象变成字符串, 然后再打印再控制台上, 打印完毕换行处理
Runtime
-
常用方法
Runtime getRuntime()
: 获取当前系统的运行环境对象void exit(int status)
: 停止虚拟机int availableProcessors()
: 获得CPU的线程数long maxMemory()
: JVM能从系统中获取总内存大小(单位byte)long totalMemory()
: JVM已经从系统中获取总内存大小(单位byte)long freeMemory()
: JVM剩余内存大小(单位byte)Process exec(String command)
: 运行cmd命令
Object
-
顶级父类, 只有空参构造
-
常用方法
-
String toString()
- 默认情况下, 因为Object类中的toString方法返回的是地址值, 所以, 默认情况下, 打印一个对象打印的就是地址值, 但是地址值对于我们是没有意义的
- 处理方案: 重写父类Object中的toString方法
-
boolean equals(Object obj)
-
同上, 默认的Object方法比较的是地址值, 需要重写
1
2
3
4
5
6
7
8
9
10
11
12String s = "abc";
StringBuilder sb = new StringBuilder("abc");
sout(s.equals(sb)); // false
// equals方法是被s调用的, 而s是字符串
// 所以equals要看String类中的
// 字符串中的equals方法, 先判断参数是否为字符串
// 如果是字符串, 再比较内部的属性
// 但如果参数不是字符串的, 直接返回false
sout(sb.equals(s)); // false
// 由于StringBuildedr中没有重写equals方法
// 使用的是Object中的, 即比较地址值
-
-
protected Object clone(int a)
- 方法在底层会帮我们创建一个对象, 并把原对象中的数据拷贝过去
- 书写细节
- 重写Object中的clone方法
- 让JavaBean类实现Cloneable接口
- 创建原对象并调用clone
- 浅克隆 (Object默认浅克隆)
- 不管对象内部的属性是基本数据类型还是引用数据类型, 都完全拷贝过来
- 深克隆 (自己重写或使用第三方工具)
- 基本数据类型拷贝过来, 常量池中的字符串复用, 引用数据类型会重新创建新的
-
Objects
-
工具类
-
常用方法
boolean equals(Object a, Object b)
: 先做非空判断, 再比较两个对象- 方法底层先判断a是否为null, 如果是null, 直接返回false, 如果不是, 那么就利用a再次调用equals方法
boolean isNull(Object obj)
boolean nonNull(Object obj)
BigInteger
-
在底层占用字节个数: byte1个字节, short2个字节, int4个字节, float4个字节, double8个字节, long8个字节
-
构造方法
-
BigInteger(int num, Random rnd)
: 获取随机大整数, 范围: [0, 2num - 1] -
BigInteger(String val)
: 获取指定的大整数 -
BigInteger(String val, int radix)
: 获取指定进制的大整数 -
public static BigInteger valueOf(long val)
: 静态方法获取BigInteger的对象, 内部有优化
-
-
总结
-
如果BigInteger表示的数字没有超出long的范围, 可以用静态方法获取
-
如果BigInteger表示的超出long的范围, 可以用构造方法获取
-
对象一旦创建, BigInteger内部记录的值不能发生改变
1
2
3
4
5
6BigInteger bd1 = BigInteger.valueOf(10);
BigInteger bd2 = BigInteger.valueOf(5);
BigInteger bd3 = BigInteger.valueOf(10);
sout(bd1 == bd2); // false
sout(bd1 == bd3); // true -
只要进行计算都会产生一个新的BigInteger对象
-
-
常见方法
BigInteger add(BigInteger val)
: 加法BigInteger subtract(BigInteger val)
: 减法BigInteger multiply(BigInteger val)
: 乘法BigInteger divide(BigInteger val)
: 除法, 获取商BigInteger[] divideAndRemainder(BigInteger val)
: 除法, 获取商和余数boolean equals(Object x)
BigInteger pow(int exponent)
BigInteger max/min(BigInteger val)
int intValue(BigInteger val)
: 转为int类型正数, 超出范围数据有误
BigDecimal
-
用于小数的精确运算
-
构造方法
BigDecimal(double val)
: 有可能不准确, 不建议使用BigDecimal(String val)
: 更加精确public static BigDecimal valueOf(double val)
-
细节
- 如果表示的数字不大, 没有超出double的取值范围, 建议使用静态方法
- 如果要表示的数字比较大, 超出了double的取值范围, 建议使用构造方法
- 如果我们传递的是0~10之间的整数(如果是小数还是会重新new), 包含0和10, 那么方法会返回已经创建好的对象, 不会重新new
-
常用方法
BigDecimal add(BigDecimal val)
BigDecimal substract(BigDecimal val)
BigDecimal multiply(BigDecimal val)
BigDecimal divide(BigDecimal val)
: 整除BigDecimal divide(BigDecimal val, 精确几位, 舍入模式)
- 舍入模式(RoundingMode)
- UP : 远离零方向舍入
- DOWN : 向零方向舍入
- CEILING : 向正无限大方向舍入
- FLOOR : 向负无限大方向舍入
- HALF_UP : 四舍五入(0.5向上舍)
- HALF_DOWN : 四舍五入(0.5向下舍)
- 舍入模式(RoundingMode)
正则表达式
-
作用
- 校验字符串是否满足规则
- 在一段文本中查找满足要求的内容
-
用法
-
[] : 只匹配其中的一个
-
(?i)xxx : 忽略xxx的大小写
-
贪婪爬取
-
ab+ 或 ab*
- 贪婪(尽可能多): abbbbbbbbbbb…
-
java默认的是贪婪爬取
-
-
非贪婪
- ab+? 或 ab*?
- 非贪婪(尽可能少): ab
- ab+? 或 ab*?
-
正则表达式在字符串中的作用
- boolean matches(String regex) : 判断字符串是否满足正则表达式的规则
- String replaceAll(String regex, String newStr) : 按照正则表达式的规则进行替换
- String[] split(String regex) : 按照正则表达式的规则切割字符串
-
捕获分组
-
每组有组号
- 以左括号为基准, 最左边的是第一组, 其次是第二组, 以此类推
-
\\组号 : 表示把第x组的内容拿出来再用一次
-
以 (.)\\1* 为例
- (.) : 以任意单字符看作第一组
- \\1 : 把第一组拿出来再次使用
- * : 作用于 \\1, 表示把第一组拿出来用0次或多次
-
后续还要继续使用本组数据
- 正则内部使用 : \\组号
- 正则外部使用 : $组号
- 例 :
String s = str.relpaceAll("(.)\\1*", "$1");
-
-
非捕获分组
- 仅仅是把数据括起来, 不占用组号
- xxx(?=yyy) : ? 指代前面的数据xxx, = 表示xxx后面要跟随的数据, 获取时只获取xxx
- xxx(?:yyy) : ? 指代前面的数据xxx, : 表示xxx后面要跟随的数据, 获取时获取所有
- xxx(?!yyy) : ? 指代前面的数据xxx, ! 表示xxx后面要跟随的数据, 获取时只获取不包含yyy的xxx文本
爬虫
-
Pattern : 表示正则表达式对象
-
Matcher : 文本匹配器, 按照正则表达式的规则去读取字符串, 从头开始读取
1
2
3
4
5
6
7
8
9
10
11
12// 获取正则表达式对象
Pattern p = Pattern.compile(regex);
// 获取文本匹配器对象
// m在str中找符合p规则的小串
Matcher m = p.matcher(str);
// 寻找匹配器中满足规则的子串
// 如果没有返回false, 如果有返回true, 在底层记录子串的 起始索引 和 结束索引+1
while(m.find()) {
// 方法底层会根据find方法记录的索引进行字符串的截取
String s = m.group();
sout(s);
}
JDK7以前的时间相关类
Date
-
Javabean类, 用来描述时间, 精确到毫秒
-
构造方法
Date date = new Date()
: 创建当前时间对象Date date = new Date(毫秒值)
: 创建指定时间对象
-
常用方法
void setTime(long time)
: 设置/修改毫秒值long getTime()
: 获取时间对象的毫秒值
SimpleDateFormat
-
作用
-
格式化: 把时间变成我们喜欢的格式
-
解析: 把字符串表示的时间变成Data对象
-
-
构造方法
SimpleDateFormat()
: 使用默认格式SimpleDateFormat(String pattern)
: 使用指定格式
-
常用方法
final String format(Date date)
: 格式化 (日期对象 – 字符串)Date parse(String source)
: 解析 (字符串 – 日期对象)
Calendar
-
Calendar代表了系统当前时间的日历对象, 可以单独修改、获取时间中的年、月、日
-
细节
- Calendar是一个抽象类, 不能直接创建对象
- 月份范围: 0~11
- 星期范围: 1~7 (但是1代表星期日)
- 字段表示 (Calendar类中有常量表示)
- 0 – 纪元 1 – 年 2 – 月 3 – 一年中的第几周 4 – 一个月中的第几周 5 – 一个月中的第几天(日期)
-
获取Calendar日历类对象的方法
public static Calendar getInstance()
: 获取当前时间的日历对象
-
常用方法
final Date getTime()
: 获取日期对象final setTime(Date date)
: 给日历设置日期对象long getTimeInMillis()
: 得到时间毫秒值void setTimeInMillis(long millis)
: 给日历设置时间毫秒值int get(int field)
: 取日历中的某个字段信息void set(int field, int value)
: 修改日历的某个字段信息void add(int field, int amount)
: 为某个字段增加/减少指定的值
JDK8新增的时间相关类
-
代码更简单, 数据更安全==(对象不可变)==
-
月份范围: 1~12
Date相关
ZoneId
-
时区
- 洲名/城市名 国家名/城市名
-
常用方法
static Set<String\> getAvailableZoneIds()
: 获取Java中支持的所有时区static ZoneId systemDefault()
: 获取系统默认时区static ZoneId of(String zoneId)
: 获取一个指定时区
Instant
-
时间戳
-
常用方法
static Instant now()
: 获取当前时间的Instant对象 (标准时间)static Instant ofXxxx(long epochMilli)
: 根据 (秒/毫秒/纳秒) 获取Instant对象ZonedDateTime atZone(ZoneId zone)
: 指定时区boolean isXxx(Instant otherInstant)
: 判断系列的方法Instant minusXxx(long millisToSubtract)
: 减少时间系列的方法Instant plusXxx(long millisToSubstract)
: 增加时间系列的方法
ZonedDateTime
-
带时区的时间
-
常用方法
static ZonedDateTime now()
: 获取当前时间的ZonedDateTime对象static ZonedDateTime ofXxx(...)
: 获取指定时间的ZonedDateTime对象ZonedDateTime withXxx(时间)
: 修改时间系列的方法ZonedDateTime minusXxx(时间)
: 减少时间系列的方法ZonedDateTime plusXxx(时间)
: 增加时间系列的方法
SimpleDateFormat相关
DateTimeFormatter
-
常用方法
static DateTimeFormatter ofPattern(格式)
: 获取格式对象String format(时间对象)
: 按照指定方式格式化
Calendar相关
LocalDate
-
年、月、日
LocalTime
-
时、分、秒
LocalDateTime
-
年、月、日、时、分、秒
-
常用方法
static XXX now()
: 获取当前时间对象static XXX of(...)
: 获取指定时间对象- get开头方法 : 获取日历中的年、月、日、时、分、秒等信息
- isBefore, isAfter : 比较两个 LocalDate
- with开头的 : 修改时间系列的方法
- minus开头的 : 减少时间系列的方法
- plus开头的 : 增加时间系列的方法
public LocalDate toLocalDate()
: LocalDateTime转换成一个LocalDate对象public LocalTime toLocalTime()
: LocalDateTime转换成一个LocalTime对象
工具类
Duration
-
计算时间间隔 (秒, 纳秒)
Period
-
计算日期间隔 (年、月、日)
ChronoUnit
-
计算日期间隔
包装类
-
基本数据类型对应的引用类型
-
获取Integer对象的方法
public Integer(int value)
public Integer(String s)
public static Integer valueOf(int i)
public static Integer valueOf(String s)
public static Integer valueOf(String s, int radix)
- 区别
- 前两种通过 new 创建对象
- 后三种当创建 -128~127 的数据对象时, 不会创建新的, 而是调用已经创建好的对象
-
JDK5提出的新机制
- 自动装箱: 把基本数据类型自动变成其对应的包装类
- 自动拆箱: 把包装类自动变成其对应的基本数据类型
- 在底层自动调用静态方法valueOf得到一个Integer对象
- 即在JDK5以后, int 和 Integer 可以看作同一个东西
-
常用方法
static String toBinaryString(int i)
static String toOctalString(int i)
static String toHexString(int i)
static int parseInt(String s)
: 将字符串类型的整数转成int类型的整数- 8种包装类, 除了Character都有对应的parseXxx方法, 进行类型转换
Arrays
-
操作数组的工具类
-
常用方法
-
static String toString(数组)
: 把数组拼接成一个字符串 -
static int binarySearch(数组, 查找的元素)
: 二分查找法查找元素 -
static int[] copyOf(原数组, 新数组长度)
: 拷贝数组 -
static int[] copyOfRange(原数组, 起始索引, 结束索引)
: 拷贝数组 (指定范围) -
static void fill(数组, 元素)
: 填充数组 -
static void sort(数组)
: 按照默认方法进行数组排序 -
static void sort(数组, 排序规则)
: 按照指定的规则排序-
只能给引用数据类型的数组进行排序, 如果数组是基本数据类型的, 需要变成其对应的包装类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28// 底层原理:
// 利用插入排序 + 二分查找的方式进行排序
// 默认把0索引的数据当作是有序的序列, 1索引到最后认为是无序的序列
// 遍历无序序列得到里面的每一个元素, 假设当前遍历得到的元素是A
// 把A往有序序列中进行插入, 在插入时, 利用二分查找确定A元素的插入点
// 拿着A元素, 跟插入到的元素进行比较, 比较的规则就compare方法的方法体
// 如果返回值是负数, 拿着A继续跟前面的数据进行比较
// 如果返回值是整数, 拿着A继续跟后面的数据进行比较
// 如果返回值是0, 也拿着A跟后面的数据进行比较
// 匿名内部类
Arrays.sort(arr, new Comparator<Integer>() {
// compare方法的形式参数:
// 参数一 o1: 表示在无序序列中, 遍历得到的每一个元素
// 参数二 o2: 有序序列中的元素
// 返回值:
// 负数: 表示当前要插入的元素o1放在前面
// 正数: 表示当前要插入的元素o1放在后面
// 0: 表示当前要插入的元素o1跟现在的元素o2是一样的, 也放在后面
public int compare(Integer o1, Integer o2) {
return 0;
}
});
// 简单理解:
// o1 - o2 : 升序排列
// o2 - o1 : 降序排列
-
-
Lambda表达式
-
函数式编程 (Functional programming)
- 是一种思想特点, 忽略面向对象的复杂语法, 强调做什么, 而不是谁去做
-
JDK8后出现的新语法形式
- ( ) -> { }
- ( ) : 对应着方法的形参
- -> : 固定格式
- { } : 对应着方法的方法体
- ( ) -> { }
-
注意点
- 可以用来简化匿名内部类内部类的书写
- 但只能简化函数式接口的匿名内部类写法
- 有且仅有一个抽象方法的接口叫做函数式接口, 接口上方可以加
@FunctionalInterface
注释
- 有且仅有一个抽象方法的接口叫做函数式接口, 接口上方可以加
1
2
3
4
5// Lambda完整格式
Arrays.sort(arr, (Integer o1, Integer o2) -> {
return o1 - o2;
}
); -
省略规则
- 参数类型可以省略
- 如果只有一个参数, 参数类型和( )都可以省略
- 如果Lambda表达式的方法体只有一行, 大括号, 分号, return可以省略不写, 需要同时省略
1
2// Lambda省略写法
Arrays.sort(arr, (o1, o2) -> o1 - o2);