🕕 Java 常见类
2022年10月10日
- Java
🕕 Java 常见类
1. Object
package java.lang;
/**
* Object 类为所有类的父类,所有对象(包括数组)都需要实现该方法
*/
public class Object {
private static native void registerNatives();
static {
registerNatives();
}
/**
* 返回该 Object 对象运行时的类,返回的类是 被表示类的静态方法锁定的 对象
* 示例如下:无需进行强制转换
*
* <p>
* {@code Number n = 0; }<br>
* {@code Class<? extends Number> c = n.getClass(); }
* </p>
*/
public final native Class<?> getClass();
/**
* 返回对象的 Hash 值
* 在存入与 Hash 值相关,例如 HashMap、HashSet 等时会用到该方法
* 遵循如下协议规定:
* 1. 在同一 Java 运行程序,同一对象每次调用该方法得到的 hash 值均相同
* 2. 若两个对象满足 equals(),那么 hashCode() 结果也必相同
* 3. 若俩个对象不满足 equals(),那么 hashCode() 结果也必不相同
*
* 通常情况下,不同对象通过 hashCode() 得到的结果值不相同,一般通过将对象的 内部地址转换为 int 实现
*/
public native int hashCode();
/**
* 重写该方法时,需要保证 上述协议:即
* 若两个对象满足 equals(),那么 hashCode() 结果也必相同
*/
public boolean equals(Object obj) {
return (this == obj);
}
/**
* 默认浅拷贝
* 任何类要实现该方法,必须 implements Cloneable,否则会抛出异常
*/
protected native Object clone() throws CloneNotSupportedException;
/**
* 返回字符串形式,建议所有子类实现该方法
*/
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
/**
* 唤醒任意一个正在等待该 对象锁 的线程
*/
public final native void notify();
/**
* 唤醒所有正在等待该 对象锁 的线程
*/
public final native void notifyAll();
/**
* 让当前线程等待,直到被其他线程 notify() | notifyAll() | 被其他线程中断 | 等待时间达到
* 当前线程必须获取该对象的 monitor
*
* 伪唤醒:线程不处于以上情况也可能恢复,因此有时需要加 while(),如下所示
* <pre>
* synchronized (obj) {
* while (<condition does not hold>)
* obj.wait(timeout);
* ... // Perform action appropriate to condition
* }
*
* @param timeout the maximum time to wait in milliseconds.
* @throws IllegalArgumentException 超时时间 < 0 不合法
* @throws IllegalMonitorStateException 当前线程并没有获取 该对象锁
* @throws InterruptedException 线程被中断,会清空中断标志位
*/
public final native void wait(long timeout) throws InterruptedException;
public final void wait(long timeout, int nanos) throws InterruptedException {
if (timeout < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (nanos < 0 || nanos > 999999) {
throw new IllegalArgumentException("nanosecond timeout value out of range");
}
if (nanos > 0) {
timeout++;
}
wait(timeout);
}
public final void wait() throws InterruptedException {
wait(0);
}
/**
* JVM 垃圾回收相关
* 在回收前,有一次逃脱的机会,该方法只能执行 一次
*/
protected void finalize() throws Throwable { }
}
1) 为什么重写 equals() 时需要重写 hashCode() 方法
- 当我们需要将 对象 添加到
HashSet
|HashMap
等Hash
相关数据结构时, - 首先会根据对象的
hashCode()
确定存入下标 - 然后在该下标处,判断
equals()
添加是否满足,- 如果满足,则说明 两个对象相等,已经存在该对象
- 若不满足,说明 两个对象不相等
- 因此,若我们没有 重写
hashCode()
,那么两个对象的hashCode()
与对象地址有关,几乎不可能hashCode()
相等- 那么,存入下标也不一定能够保证是相等的
- 这样这两个对象,很大概率会放在不同下标的桶中,表示 两个对象 不相等
- 而我们预期是,这两个对象 应该是相等的,放在同一数组下标,且在查找时,发现
equals()
满足条件
- 因此,在此种情况下,我们首先要满足相同对象的
hashCode()
相等,然后才会判断equals()
- 只重写了
equals()
让两个对象相等,是无法满足条件的
- 只重写了
2. 包装类
1) Integer
- 缓存区间 [-128, 127]
- 可通过
java.lang.Integer.IntegerCache.high
设置 右区间边界值
public final class Integer extends Number implements Comparable<Integer> {
@Native public static final int MIN_VALUE = 0x80000000;
@Native public static final int MAX_VALUE = 0x7fffffff;
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i); // 不存在于缓存中,新生成一个 包装类
}
// 缓存内部类
private static class IntegerCache {
static final int low = -128;
static final int high; // 默认 = 127,也可以自定义大小
static final Integer cache[]; // 缓存数组
static {
int h = 127;
// 获取用户自定义的 high 值,如果存在的化,但是最终会取 max{自定义 high, 127}
String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
// high >= 127
assert IntegerCache.high >= 127;
}
private IntegerCache() {}
}
}
2) Byte
- 缓存区间 [-128, 127]
- 全部缓存
public final class Byte extends Number implements Comparable<Byte> {
public static final byte MIN_VALUE = -128;
public static final byte MAX_VALUE = 127;
// 缓存数组存放所有 byte 值
public static Byte valueOf(byte b) {
final int offset = 128;
return ByteCache.cache[(int)b + offset];
}
// 缓存内部类,无法自定义缓存区间
private static class ByteCache {
private ByteCache(){}
static final Byte cache[] = new Byte[-(-128) + 127 + 1];
static {
for(int i = 0; i < cache.length; i++)
cache[i] = new Byte((byte)(i - 128));
}
}
}
3) Boolean
- 直接缓存的
TRUE
&FALSE
两个变量,无所谓缓存不缓存
public final class Boolean implements java.io.Serializable, Comparable<Boolean> {
public static final Boolean TRUE = new Boolean(true);
public static final Boolean FALSE = new Boolean(false);
// 每次返回的 都是一个 新的 Boolean 对象
public static Boolean valueOf(boolean b) {
return (b ? TRUE : FALSE);
}
}
4) Character
- 缓存区间 [0, 127]
- 无法修改缓存区间大小
// Character 本身范围就是 非负数
public final class Character implements java.io.Serializable, Comparable<Character> {
public static final char MIN_VALUE = '\u0000';
public static final char MAX_VALUE = '\uFFFF';
public static Character valueOf(char c) {
if (c <= 127) { // 缓存范围 - [0, 127]
return CharacterCache.cache[(int)c];
}
return new Character(c);
}
// 缓存类
private static class CharacterCache {
private CharacterCache(){}
static final Character cache[] = new Character[127 + 1]; // [0, 127]
static {
for (int i = 0; i < cache.length; i++)
cache[i] = new Character((char)i);
}
}
}
5) Short
- 缓存区间 [-128, 127]
- 无法修改缓存区间大小
public final class Short extends Number implements Comparable<Short> {
public static final short MIN_VALUE = -32768;
public static final short MAX_VALUE = 32767;
public static Short valueOf(short s) {
final int offset = 128;
int sAsInt = s;
if (sAsInt >= -128 && sAsInt <= 127) { // must cache
return ShortCache.cache[sAsInt + offset];
}
return new Short(s);
}
private static class ShortCache { // [-128, 127]
private ShortCache(){}
static final Short cache[] = new Short[-(-128) + 127 + 1];
static {
for(int i = 0; i < cache.length; i++)
cache[i] = new Short((short)(i - 128));
}
}
}
6) Float
- 无缓存,直接返回新对象
public static Float valueOf(float f) {
return new Float(f); // 无缓存,直接返回新对象
}
7) Double
- 无缓存,直接返回新对象
public static Double valueOf(double d) {
return new Double(d); // 无缓存,直接返回新对象
}
8) Long
- 缓存区间 [-128, 127]
- 无法修改缓存区间大小
public static Long valueOf(long l) {
final int offset = 128;
if (l >= -128 && l <= 127) { // [-128, 127]
return LongCache.cache[(int)l + offset];
}
return new Long(l);
}
// 缓存池 - [-128, 127]
private static class LongCache {
private LongCache(){}
static final Long cache[] = new Long[-(-128) + 127 + 1];
static {
for(int i = 0; i < cache.length; i++)
cache[i] = new Long(i - 128);
}
}
3. 字符串类
1) String
// final 修饰类 - 无法被继承
public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
// 存储 char[] 数组,final 修饰一旦初始化不可再更改
// JDK 9 开始转换为 byte[] 存储,节省了存储空间
private final char value[];
private int hash; // 默认 hash 值,当为 0 时,hashCode() 时需要根据 val[] 元素重新计算
// 重写 equals,依次比较每个元素
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
// 重写 hashCode(),保证 equals 成立条件下,hashCode 肯定相等
public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i]; // 与每个元素有关,取决于元素个数 & 元素顺序
}
hash = h;
}
return h;
}
// 字符串池,最初为空,由类 {@code String} 私下维护。
// 当调用 intern 方法时,如果池中已经包含一个等于 {@link equals(Object)} 方法确定的此 {@code String} 对象的字符串,则返回池中的字符串。
// 否则,将此 {@code String} 对象添加到池中,并返回对此 {@code String} 对象的引用。
// 因此对于任何两个字符串 s & t,当且仅当 s.equals(t) 满足条件时,s.intern() == t.intern()
public native String intern();
}
2) StringBuilder
public final class StringBuilder extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
{
static final long serialVersionUID = 4383685877147921099L;
/**
* 默认创建长度为 16 的空数组
*/
public StringBuilder() {
super(16);
}
/**
* 创建长度为 capacity 的空数组
*/
public StringBuilder(int capacity) {
super(capacity);
}
/**
* 在指定字符串长度的基础上,再加上 16 的初始容量
*/
public StringBuilder(String str) {
super(str.length() + 16);
append(str);
}
// 插入元素
// 在插入过程中,若 新的总长度 > 数组已有长度,则扩容为 2n + 2 --> 来自抽象父类
public StringBuilder append(StringBuffer sb) {
super.append(sb);
return this;
}
@Override
public StringBuilder insert(int offset, Object obj) {
super.insert(offset, obj);
return this;
}
// 删除元素
@Override
public StringBuilder delete(int start, int end) { // 删除区间 [start, end) | [start, len)
super.delete(start, end);
return this;
}
@Override
public StringBuilder deleteCharAt(int index) {
super.deleteCharAt(index);
return this;
}
// 查找元素
@Override
public int indexOf(String str, int fromIndex) {
return super.indexOf(str, fromIndex);
}
// 反转字符串
@Override
public StringBuilder reverse() {
super.reverse();
return this;
}
// 并没有重写 equal & hashCode
3) StringBuffer
- 方法同 StringBuilder
- 所有方法加上
synchronized
关键字修饰
+
操作
String 的 - String 的
+
操作实际调用的是StringBuilder.append().toString()
- 但是,在循环体中,不宜使用
+
拼接字符串- 每次循环都产生一个
StringBuilder
对象,有多少次循环就会产生多少个StringBuilder
对象,可能造成 内存溢出
- 每次循环都产生一个
4. Arrays.sort()
- 针对
byte
char
short
,len > 29 | len > 3200 时,优先选择 计数排序- 计数排序,遍历数组获得 min & max,建立对应长度的数组
- 再次遍历,每个数组下标处记录元素的出现次数
- 最后遍历,填充结果集
- 由于 以上三种数据类型 值的取值范围较小,因此可以通过建立这么长的数组,且 len 越大,每个下标处频次越高,效果越好
- 针对
所有基本数据类型
,len < 47 时,优先选择 插排 - 针对
所有基本数据类型
,len < 286 时,优先选择 快排 - 其余情况,针对
所有基本数据类型 & 对象类型
,使用 归并排序,算法稳定 - 针对
所有基本数据类型
,采用的是DualPivotQuicksort
类;针对对象类型
,使用的是ComparableTimSort
类的算法
final class DualPivotQuicksort {
private DualPivotQuicksort() {} // 私有构造函数,防止实例化
private static final int MAX_RUN_COUNT = 67; // 归并排序最大允许次数
private static final int MAX_RUN_LENGTH = 33; // 归并排序中运行的最大长度
// 如果要排序的数组的长度小于 286,则优先使用快速排序而不是归并排序
private static final int QUICKSORT_THRESHOLD = 286;
// 如果要排序的数组的长度小于 47,则使用插入排序优先于快速排序
private static final int INSERTION_SORT_THRESHOLD = 47;
// 如果要排序的字节数组的长度大于 29,则优先使用计数排序而不是插入排序
private static final int COUNTING_SORT_THRESHOLD_FOR_BYTE = 29;
// 如果要排序的 short | char 数组的长度大于 3200,则优先使用计数排序而不是快速排序
private static final int COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR = 3200;
}
5. 异常类
1) 类图
2) Throwable
public class Throwable implements Serializable {
// 返回详细信息
public String getMessage() {
return detailMessage;
}
//
public String toString() {
String s = getClass().getName();
String message = getLocalizedMessage();
return (message != null) ? (s + ": " + message) : s;
}
//
public void printStackTrace() {
printStackTrace(System.err);
}
}
3) try-catch-finally
① 若 finally 中存在 return,则会直接返回 finally 中的结果
- 如果在 finally 中存在 return 语句,那么 try-catch 中的 return 值都会被覆盖
- 如果有返回值,会把 try 中 return 的变量当前值 保存到 局部变量表 中,压入操作数栈
- 然后跳转到 finally 中继续执行
- 执行完 finally 语句后,会返回之前保存在 局部变量表 里的值
public static void main(String[] args) throws FileNotFoundException {
System.out.println("执行结果:" + test());
}
private static int test() {
int num = 0;
try {
num++; // num = 1
return num;
} catch (Exception e) {
e.getMessage();
} finally {
num++; // num = 2
return num; // 返回 2
}
}
② finally 中的代码不执行
- 在 try-catch 语句中执行了
System.exit(0)
- 在 try-catch 语句中出现了死循环
- 在 finally 执行之前掉电或者 JVM 崩溃了