常用类

165 阅读17分钟

常用类

Object类

修饰符和类型方法的描述
protected Objectclone()创建并返回此对象的副本
booleanequals(Object obj)指示一些其他对象是否等于此
protected voidfinalize()当垃圾收集确定不再有对该对象的引用时,垃圾收集器在对象上调用该对象
Class<?>getClass()返回此 Object的运行时类
inthashCode()返回对象的哈希码值
voidnotify()唤醒正在等待对象监视器的单个线程
voidnotifyAll()唤醒正在等待对象监视器的所有线程
StringtoString()返回对象的字符串表示形式
voidwait()导致当前线程等待,直到另一个线程调用该对象的 notify()方法或 notifyAll()方法
voidwait(long timeout)导致当前线程等待,直到另一个线程调用 notify()方法或该对象的 notifyAll()方法,或者指定的时间已过
voidwait(long timeout, int nanos)导致当前线程等待,直到另一个线程调用该对象的 notify()方法或 notifyAll()方法,或者某些其他线程中断当前线程,或一定量的实时时间

equals

1.五种特性

x.equals(x); // 自反性 true
x.equals(y) == y.equals(x); // 对称性,一致性 true
if (x.equals(y) && y.equals(z)) x.equals(z); // 传递性 true
x.equals(null); // 与 null 的比较  false

2.equals方法 和 == 比较运算符 的区别

== :如果判断基本数据类型,判断值是否相同;如果判断引用数据类型,判断的是地址是否相同(是否是同一个对象)

equals:是Object类中的方法,只能用来判断引用数据类型,默认是判断地址是否相同,但是像String类重写了该方法,用来判断字符串值是否相同

// Object类的源码
public boolean equals(Object obj) {
    return (this == obj);
}
​
/**
 * String类的源码
 * Compares this string to the specified object.  The result is {@code
 * true} if and only if the argument is not {@code null} and is a {@code
 * String} object that represents the same sequence of characters as this
 * object.
 */
public boolean equals(Object anObject) {
    if (this == anObject) { // 比较地址是否相同
        return true;
    }
    if (anObject instanceof String) { // 判断是否为String 或者 String的父类
        String aString = (String)anObject; // 向下转型:目的是为了获得String类的属性和方法
        if (!COMPACT_STRINGS || this.coder == aString.coder) {
            return StringLatin1.equals(value, aString.value);
        }
    }
    return false;
}
​
// StringLatin1类的源码 底层就是比较字符数组中每个字符是否相同
@HotSpotIntrinsicCandidate
public static boolean equals(byte[] value, byte[] other) {
    if (value.length == other.length) {
        for (int i = 0; i < value.length; i++) {
            if (value[i] != other[i]) {
                return false;
            }
        }
        return true;
    }
    return false;
}

hashCode

作用:返回该对象的哈希码值(散列值),是为了提高哈希表的性能

注意细节

  • 提高具有哈希结构的容器的效率
  • 两个引用都指向同一个对象,则哈希值一定相同
  • 哈希值主要是根据地址来的,将对象的内部地址转换成一个整数来实现的

toString

默认返回:全类名 + @ + 哈希值十六进制

作用:用于返回该对象的属性信息

// Object源码
// java.lang.Object@16b98e56
public String toString() {
    return getClass().getName() + "@" + Integer.toHexString(hashCode());
}

当直接输出一个对象时,toString方法会被默认的调用

Object o = new Object();
System.out.println(o.toString()); // java.lang.Object@16b98e56
System.out.println(o); //java.lang.Object@16b98e56

clone()

概念:clone() 是 Object 的 protected 方法,它不是 public,一个类不显式去重写 clone(),其它类就不能直接去调用该类实例的 clone() 方法

@HotSpotIntrinsicCandidate
protected native Object clone() throws CloneNotSupportedException;

Cloneable 接口只是规定,如果一个类没有实现 Cloneable 接口又调用了 clone() 方法,将会抛出异常

public class ObjectDemo01 {
    public static void main(String[] args) throws CloneNotSupportedException {
        cloneImpl clone = new cloneImpl();
        clone.clone();
    }
}
​
// 没有实现Cloneable接口,直接调用clone.clone()会出现CloneNotSupportedException异常
class cloneImpl implements Cloneable{
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
// Invoking Object's clone method on an instance that does not implement Cloneable
// Cloneable接口原码
public interface Cloneable {
}

区分浅拷贝和深拷贝

  • 浅拷贝:拷贝对象和原始对象的引用类型引用同一个对象
  • 深拷贝:拷贝对象和原始对象的引用类型引用不同对象

可以使用重写的方法进行拷贝,但是方式复杂并且有风险,并且还需要类型转换,可以使用拷贝构造函数或者拷贝工厂来拷贝一个对象(例子取自java全栈体系

public class CloneConstructorExample {
    private int[] arr;
​
    public CloneConstructorExample() {
        arr = new int[10];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = i;
        }
    }
​
    public CloneConstructorExample(CloneConstructorExample original) {
        arr = new int[original.arr.length];
        for (int i = 0; i < original.arr.length; i++) {
            arr[i] = original.arr[i];
        }
    }
​
    public void set(int index, int value) {
        arr[index] = value;
    }
​
    public int get(int index) {
        return arr[index];
    }
}
​
CloneConstructorExample e1 = new CloneConstructorExample();
CloneConstructorExample e2 = new CloneConstructorExample(e1);
e1.set(2, 222);
System.out.println(e2.get(2)); // 2

finalize

概念:当垃圾回收器确定不存在该对象的更多引用时,由对象的垃圾回收器调用此方法

注意细节

  • 当某个对象没有任何引用时,则jvm虚拟机就会来销毁该对象,在销毁该对象前,就会调用该对象的finalize方法

    public class person {
        public person() {}
        // 该方法已经被废除,不推荐使用
        @Override
        protected void finalize() throws Throwable {
            System.out.println("我已经被销毁了...");
        }
    }
    ​
    class test{
        public static void main(String[] args) {
            new person();
            System.gc(); // 运行垃圾回收器
        }
    }
    ​
    // 显示效果:我已经被销毁了...
    
  • 垃圾回收机制的调用,由系统来决定,我们可以通过System.gc() 主动触发垃圾回收机制

Wrapper类

包装类的分类

包装类基本数据类型直接父类
booleanBooleanObject
charCharacterObject
byteByteNumber
shortShortNumber
intIntNumber
longLongNumber
floatFloatNumber
doubleDoubleNumber

image-20220326131823205

装箱 & 拆箱

  • 手动拆装箱
  • 自动拆装箱
// 代码示例
public class Wrapper01 {
    public static void main(String[] args) {
        // jdk5以前手动装箱&手动拆箱;jdk5之后可以自动拆装箱
        // 以Character为例
        char name = 'n';
        // 手动装箱
        // Character ch1 = new Character(name); // 不推荐
        Character ch2 = Character.valueOf(name);
        // 手动拆箱
        char name2 = Character.valueOf(ch2); // 本质就是使用charValue方法
        char name3 = ch1.charValue();
​
        // 自动装箱
        Character ch3 = name; // 本质使用的就是valueOf方法
        // 自动拆箱
        char CH4 = ch3; // 本质就是使用charValue方法
    }
}

底层分析

image-20220326132417215

缓冲池(重点!!!)

基本类型对应的缓冲池如下:

  • boolean :true and false
  • byte :all values
  • short : between -128 and 127
  • int :between -128 and 127
  • char :in the range \u0000 to \u007F

在使用这些基本类型对应的包装类型时,就可以直接使用缓冲池中的对象。

// 以Integer为例
// new Integer(1) 与 Integer.valueOf(1)或者数值1 的区别在于:
// 1.new Integer(123) 每次都会新建一个对象
// 2.Integer.valueOf(123) 会使用缓存池中的对象,多次调用会取得同一个对象的引用
System.out.println(new Integer(1) == new Integer(1));  // false
Integer a = 1;
Integer b = 1;
System.out.println(a==b); // true
Integer a = Integer.valueOf(1);
Integer b = Integer.valueOf(1);
System.out.println(a==b); // true

缓冲池源码分析

// 以Integer为例 jdk1.8中缓存池的大小默认为 -128~127
static final int low = -128;
static final int high;
static final Integer cache[];
​
static {
    // high value may be configured by property
    // 最大值会根据配置数据而改变,但是h的值至少大于127 Math.max(i, 127);
    int h = 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);
            // Maximum array size is Integer.MAX_VALUE
            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++);
​
    // range [-128, 127] must be interned (JLS7 5.1.7)
    assert IntegerCache.high >= 127;
}

String类

概述

是一组字符序列 本质上是char[] value 字符数组实现

public static void main(String[] args) {
   /*
    * "Al_tair"被称为字符常量 用双引号括起来的字符序列
    *  一个字符占用两个字节(每个字符不区分字母和汉字)
    */
    String name = "Al_tair";
}
​
// public final class String 说明String的final类,不能被其它类继承
// private final byte[] value 用于存放字符串 value是用final修饰的类型,该数组不能指向新地址,但是能修改它的值
public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    /** The value is used for character storage. */
    private final char value[];
}

接口和构造器

image-20211028164429590

String内存图

// 运行代码,内存图如下
class code{
    public static void main(String[] args){
        String a = "Al_tair";
        String b = new String("Al_tair");
    }
}

image-20220223163658951

字符串 VS 字符数组

结合代码和内存图分析

class Text{
    String str = new String("lns");
    // final指的是char类型数据存储的地址不能改变,但是值是可以改变的
    final char[] ch = {'j','a','v','a'};
    public void change(String str,char[] ch){
        str = "zlr";
        ch[1] = 'c';
    }
    public static void main(String[] args) {
        Text text = new Text();
        text.change(text.str,text.ch);
        System.out.println(text.str.toString()+" and "+text.ch[1]); // lnsandc
    }
}

image-20220223162328369

String类的常用方法

  • equals 区别大小写,判断字符串的内容是否相同
  • equalsIgnoreCase 忽略大小写 来判断字符串的内容是否相同
  • length 获取字符串的个数,或者称为字符串长度
  • indexOf 获取字符在字符串中第一次出现的索引,索引从0开始,如果没有找到则返回-1
  • lastindexOf 获取字符在字符串中最后一次出现的索引,索引从0开始,如果没有找到则返回-1
  • substring 截取指定范围的字串
  • trim 去掉字符串前后的空格
  • charAt 获取某索引处的字符
  • compareTo 比较两个字符串的大小,如果前者大于等于后者,则返回自然数;反之后者大,则返回负数
  • intern 如果常量池中已经包含值相同的字符串,则返回常量池中的字符串引用地址,否则将String对象添加到常量池中,并返回String对象的引用
// intern 方法的使用
String a = "l";
String b = new String("l");
System.out.println(a.equals(b)); // true
System.out.println(a == b); // false
System.out.println(a == b.intern()); // true
System.out.println(b == b.intern()); // false
​
// equals()方法源码
public boolean equals(Object anObject) {
    if (this == anObject) { // 地址是否相同
        return true;
    }
    if (anObject instanceof String) { // 是否为String类或者String父类
        String aString = (String)anObject;
        if (!COMPACT_STRINGS || this.coder == aString.coder) {
            return StringLatin1.equals(value, aString.value);
        }
    }
    return false;
}
@HotSpotIntrinsicCandidate
public static boolean equals(byte[] value, byte[] other) {
    if (value.length == other.length) {
        for (int i = 0; i < value.length; i++) {
            if (value[i] != other[i]) {
                return false;
            }
        }
        return true;
    }
    return false;
}
​
// 占位符的讲解 涉及方法format <=> c语言输出
// %s,%d,%.3f,%c
String name = "lns";
int age = 18;
double height = 185.35;
char gender = '男';
​
String Info = "姓名:%s\t年龄:%d\t身高:%.3f\t性别:%c";
String show = String.format(Info,name,age,height,gender);
System.out.println(show); // 姓名:lns 年龄:18   身高:185.350  性别:男

包装类 <=> String类

public class WrapperVsString {
    public static void main(String[]args){
        // String类 转换成 包装类
        String age = "120"; 
        Integer age2 = Integer.valueOf(age);  // 方式一:valueOf函数 本质上就是parseInt()方法
        Integer a2 = Integer.parseInt(age); // 方式二:parseInt函数
        Integer age3 = new Integer(age);  //不推荐,本质就是parseInt()方法
​
        // 包装类 转换成 String类
        Integer height = 180; // 自动装箱
        String h = String.valueOf(height); // 方式一:valueOf函数 本质就是调用toString()方法
        String h2 = height + "";  // 方式二: 类型转换 Integer + ""
        String h3 = height.toString(); // 方式三: toString()函数
​
        /*
         *   String.valueOf()源码
         *   public static String valueOf(Object obj) {
         *       return (obj == null) ? "null" : obj.toString();
         *   }
         * 
         *   Integer.valueOf()源码
         *   public static Integer valueOf(String s) throws NumberFormatException {
         *        return Integer.valueOf(parseInt(s, 10)); // 10指的是传入的数字是十进制数
         *   }
         *
         *   new Integer()源码
         *   @Deprecated(since="9")
         *   public Integer(String s) throws NumberFormatException {
         *          this.value = parseInt(s, 10);
         *   }
         */
    }
}

StringBuffer类

概念:代表可变的字符序列,可以对字符串内容进行增删,是一个容器

image-20220223203041672

构造方法

Constructor and Description
StringBuffer()构造一个没有字符的字符串缓冲区,初始容量为16个字符。
StringBuffer(CharSequence seq)构造一个包含与指定的相同字符的字符串缓冲区 CharSequence
StringBuffer(int capacity)构造一个没有字符的字符串缓冲区和指定的初始容量。
StringBuffer(String str)构造一个初始化为指定字符串内容的字符串缓冲区。
/*
 * Constructs a string buffer with no characters in it and an
 * initial capacity of 16 characters.
 * StringBuffer()构造器
 */
@HotSpotIntrinsicCandidate
public StringBuffer() {
    super(16); // 初始容量为16个字符 存储在父类的value数组中
}

常用方法

修饰符和类型方法和描述
StringBufferappend(String str)将指定的字符串附加到此字符序列
StringBufferdelete(int start, int end)删除此序列的子字符串中的字符
intlength()返回长度(字符数)
StringBufferreplace(int start, int end, String str)用指定的String中的字符替换此序列的子字符串中的 String
intindexOf(String str)返回指定子字符串第一次出现的字符串内的索引
public static void main(String[] args) {
    // 常用方法
    // append 增
    StringBuffer stringBuffer = new StringBuffer("");
    stringBuffer.append("lns"); // lns
    /*
     *  append源码
     *  不管传入什么数据类型,返回StringBuffer类型
     *  public synchronized StringBuffer append(String str) {
     *      toStringCache = null;
     *      super.append(str);
     *      return this;
     *  }
     */
​
    // delete 删除
    // 删除索引范围 [start,end)
    stringBuffer.delete(0,1); // 删除第一个字符 ns
​
    // replace 替换
    // 替换范围[start,end)
    stringBuffer.replace(0, 1,"ln"); // lns
​
    // indexOf 查找
    // 查找第一次在字符串中出现的索引,如果查找到会返回你查找的字符串首个字母索引,如果找不到返回-1
    stringBuffer.indexOf("ns"); // 1
​
    // length 长度
    System.out.println(stringBuffer.length()); // 3
}

StringBuffer底层分析

添加null字符串

String str = null;
StringBuffer sb = new StringBuffer();
sb.append(str);
System.out.println(sb); // null
System.out.println(sb.length()); // 4  
/*
 *  // 底层分析
 *  // StingBuffer类
 *  public synchronized StringBuffer append(String str) {
 *      toStringCache = null;
 *      super.append(str); // 跳转到父类
 *      return this;
 *  }
 *  // AbstractStringBuilder抽象类
 *  public AbstractStringBuilder append(String str) {
 *      if (str == null) {
 *          return appendNull(); // 跳转到该方法
 *      }
 *      int len = str.length();
 *      ensureCapacityInternal(count + len);
 *      putStringAt(count, str);
 *      count += len;
 *      return this;
 *  }
 *  // appendNull方法
 *  private AbstractStringBuilder appendNull() {
 *      ensureCapacityInternal(count + 4);
 *      int count = this.count;
 *      byte[] val = this.value;
 *      if (isLatin1()) {
 *          val[count++] = 'n';
 *          val[count++] = 'u';
 *          val[count++] = 'l';
 *          val[count++] = 'l';
 *      } else {
 *          count = StringUTF16.putCharsAt(val, count, 'n', 'u', 'l', 'l');
 *      }
 *      this.count = count;
 *      return this;
 *  }
 */
 StringBuffer sb = new StringBuffer(str); // 抛出空指针异常 NullPointerException
 /*
 * AbstractStringBuilder(String str) {
 *    int length = str.length(); // str为null 
 *    int capacity = (length < Integer.MAX_VALUE - 16)
 *           ? length + 16 : Integer.MAX_VALUE;
 *    final byte initCoder = str.coder();
 *    coder = initCoder;
 *    value = (initCoder == LATIN1)
 *           ? new byte[capacity] : StringUTF16.newBytesFor(capacity);
 *    append(str);
 * }
 */

字符串拼接

// 创建了几个对象 答:3  结论:字符串常量相加地址存放在常量池,字符串变量相加地址存放在String对象中
// sum 指向的是value[](String对象),再指向常量池中"HelloString"字符串
public static void main(String[]args){
    String m = "Hello";
    String n = "String";
    /*
     * 解读:
     * 1. 创建新对象 new StringBuilder();
     * 2. 通过append函数添加字符串 “Hello”
     * 3. 通过append函数添加字符串 “String”
     * 4. 返回new String("HelloString");
     */
    String sum = m + n;
}
// 分析sum 的指向和底层源码
// debug test
// first insert
public StringBuilder() {
    super(16);
}
//secong insert  str = "Hello"
public StringBuilder append(String str) {  
    super.append(str);
    return this;
}
// third insert str = "String"
public StringBuilder append(String str) {
    super.append(str);
    return this;
}
// last one
public String toString() {
    // Create a copy, don't share the array
    return isLatin1() ? StringLatin1.newString(value, 0, count): StringUTF16.newString(value, 0, count);
}

String <=> StringBuffer

String类和StringBuffer类的区别

  • String保存的是字符串常量,里面的值不能更改,每次值的更新实际上就是更改地址,效率低
  • Stringbuffer保存的是字符串变量,里面的值是可以改变的,不需要每次都更改地址,效率高

String类和StringBuffer类的相互转换

public static void main(String[] args) {
    // String和StringBuffer的相互转换
    // String => StringBuffer
    String str = "lns";
    StringBuffer stringBuffer = new StringBuffer(str); // 方式一: 使用StringBuffer构造器
    StringBuffer append = new StringBuffer().append(str); // 方式二: 使用的是append方法
​
    // StringBuffer => String
    StringBuffer sbr = new StringBuffer("zlr");
    String s = sbr.toString(); // 方式一: 使用toString方法
    String s1 = new String(sbr); // 方式二:使用String构造器 
}

StringBuilder类

概念:一个可变的字符序列。 线程不安全。 此类设计用作简易替换为StringBuffer在正在使用由单个线程字符串缓冲区的地方。 在可以的情况下,建议使用这个类别优先于StringBuffer ,因为它在大多数实现中将更快。

常用方法大部分与 StringBuffer类似

image-20220224105411449

特殊点:没有做互斥处理,因此在单线程下使用

// 源码剖析 区别在于关键字 synchronized 保证线程安全
// StringBuffer 的append方法
@Override
@HotSpotIntrinsicCandidate
public synchronized StringBuffer append(String str) {
    toStringCache = null;
    super.append(str);
    return this;
}
​
// StringBuilder 的append方法
@Override
@HotSpotIntrinsicCandidate
public StringBuilder append(String str) {
    super.append(str);
    return this;
}

String,StringBuffer,StringBuilder的区别

  • String:不可变字符序列,效率低,但是因为存在常量池所以复用率高,String 不可变,因此是线程安全的
  • StringBuffer:可变字符序列,效率较高(增删),线程安全
  • StringBuilder:可变字符序列,效率最高,线程不安全

使用原则

  • 如果字符串存在大量的修改操作,一般使用StringBuffer或者StringBuider

    • 如果字符串存在大量的修改操作,并在单线程的情况,使用StringBuilder
    • 如果字符串存在大量的修改操作,并在多线程的情况,使用StringBuffer
  • 如果字符串很少修改,被多个对象引用,使用String 比如:配置信息等

Math类

概念:Math类包含执行基本数学运算的方法

常用方法

public static void main(String[] args) {
    // Math类中大部分是静态方法,可以直接通过类名.方法名访问
    // abs 绝对值
    int abs = Math.abs(-10);
    System.out.println(abs); // 10
​
    // pow 求幂
    double pow = Math.pow(2,4);
    System.out.println(pow); // 16.0
​
    // ceil 向上取整,返回>=该参数的最小整数(整数会转换成double型)
    double ceil = Math.ceil(-3.002);
    System.out.println(ceil); // -3.0
​
    // floor 向下取整,返回<=该参数的最大整数(整数会转换成double型)
    double floor = Math.floor(3.2);
    System.out.println(floor); // 3.0
​
    // round 四舍五入 <=> Math.floor(参数+0.5)
    double round = Math.round(3.24);
    System.out.println(round); // 3.0
​
    // sqrt 求开平方
    double sqrt = Math.sqrt(4);
    System.out.println(sqrt); // 2.0
​
    // random 随机数 [0,1)
    int random = (int)(Math.random()*50+50);
    System.out.println(random); // 整数范围 [50,100)
}

Arrays类

概念:该类包含用于操作数组的各种方法(如排序和搜索),大部分方法也是静态方法

常用方法

toString方法

作用:将数组的值按照一定格式以字符串的方式输出

// 测试代码
public static void main(String[] args) {
    Integer[] array1 = null;
    System.out.println(Arrays.toString(array1)); // null
    Integer[] array2 = {};
    System.out.println(Arrays.toString(array2)); // []
    Integer[] array3 = new Integer[3];
    System.out.println(Arrays.toString(array3)); // [null,null,null]
    Integer[] array4 = {3,5,6,47,8};
    System.out.println(Arrays.toString(array4)); // [3, 5, 6, 47, 8]
}
​
// toString方法源码(以整数数组为例)
// 1.数组为null  Integer[] array = null;
// 2.数组为空 Integer[] array = {};
// 3.底层使用StringBuider来拼接数组值,并且转换成String
public static String toString(int[] a) {
    if (a == null) 
        return "null";
    int iMax = a.length - 1;
    if (iMax == -1)
        return "[]";
​
    StringBuilder b = new StringBuilder();
    b.append('[');
    for (int i = 0; ; i++) {
        b.append(a[i]); 
        if (i == iMax)
            return b.append(']').toString();
        b.append(", ");
    }
}
sort方法

作用:排序数组默认从小到大

// sort重载,可以通过传入一个接口Comparator实现定制排序
Integer[] array = {3,5,6,47,8};
Arrays.sort(array);
System.out.println(Arrays.toString(array)); // [3, 5, 6, 8, 47]
Arrays.sort(array,new Comparator(){
    @Override
    public int compare(Object o1, Object o2) {
        Integer i1 = (Integer)o1;
        Integer i2 = (Integer)o2;
        return i2 - i1; // 决定是升序还是降序
    }
});
System.out.println(Arrays.toString(array)); // [47, 8, 6, 5, 3]
​
// MySort的冒泡实现
public class MySort {
    public static void main(String[] args) {
        int[] arr = {6,4,5,6,845,4,51};
        bubble(arr, new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                int i1 = (Integer)o1;
                int i2 = (Integer)o2;
                return i1 - i2;
            }
        });
        System.out.println(Arrays.toString(arr));
    }
​
    public static void bubble(int[] arr, Comparator c){
        int temp = 0;
        for (int i = 0; i < arr.length - 1; i++) {
            for (int j = 0; j < arr.length - 1 - i; j++) {
                if(c.compare(arr[j],arr[j+1]) >= 0){ // 动态绑定机制
                    temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                }
            }
        }
    }
}
binarySearch方法

作用:通过二分搜索法进行查找,要求必须升序,如果数组中不存在,则返回 -(low + 1)

Integer[] array = {3,5,6,47,8};
Arrays.sort(array); // [3, 5, 6, 8, 47]
int index = Arrays.binarySearch(array,9); 
System.out.println(index); // -5 应该在索引4位置(8和471之间),返回-(4+1)
​
// binarySearch 源码
public static int binarySearch(int[] a, int fromIndex, int toIndex,
                               int key) {
    rangeCheck(a.length, fromIndex, toIndex);
    return binarySearch0(a, fromIndex, toIndex, key);
}
​
// Like public version, but without range checks.
private static int binarySearch0(int[] a, int fromIndex, int toIndex,
                                 int key) {
    int low = fromIndex;
    int high = toIndex - 1;
​
    while (low <= high) {
        // 无符号右移,按位右移补零操作符
        // >>> 操作符运算 要快于加减乘除运算
        int mid = (low + high) >>> 1; 
        int midVal = a[mid];
​
        if (midVal < key)
            low = mid + 1;
        else if (midVal > key)
            high = mid - 1;
        else
            return mid; // key found
    }
    return -(low + 1);  // key not found.
}
其他方法
// copeOf 数组的赋值 如果赋值的长度大于原数组的长度,则多余的数据用null填入
Integer[] integers = Arrays.copyOf(array, array.length-1);
System.out.println(Arrays.toString(integers)); // [3, 5, 6, 8]
​
// fill 数组的填充 替换数组中的所有数据
int[] fillNum = {2,45,78,85,15};
Arrays.fill(fillNum,2);
System.out.println(Arrays.toString(fillNum)); // [2, 2, 2, 2, 2]
​
// equals 比较两个数组元素内容是否相同
int[] equalsNum = {2,45,78,85,15};
int[] equalsNum2 = {2,45,78,85,15};
System.out.println(Arrays.equals(equalsNum,equalsNum2)); // true

System类

概念:System类包含几个有用的类字段和方法。 它不能被实例化。

常用方法

public static void main(String[] args) {
    // gc方法:调用垃圾回收器
    new System01();
    System.gc(); 
​
    // currentTimeMillis方法:在1970年1月1日UTC之间的当前时间和午夜之间的差异,以毫秒为单位
    System.out.println(System.currentTimeMillis()); // 1645776480314
​
    // arraycopy方法:复制数组(深拷贝)
    int[] src = {1,2,3};
    int[] desc = {0,0,0};
    /*
     * 从左到右的五个参数描述
     *  src      the source array. 被复制内容的数组
     *  srcPos   starting position in the source array. 源数组索引位置(从哪个位置开始拷贝)
     *  dest     the destination array. 复制内容得到的数组
     *  destPos  starting position in the destination data. 目标数组的索引位置
     *  length   the number of array elements to be copied. 拷贝的数组长度
     */
    System.arraycopy(src,0,desc,0,3);
    System.out.println(Arrays.toString(desc)); //[1, 2, 3]
    System.out.println(src == desc); // false 
​
    // exit方法:退出程序
    System.out.println("程序开始");
    // System.exit(0)是正常退出程序,而System.exit(1)或者说非0表示非正常退出程序
    System.exit(0); 
    System.out.println("程序结束"); // 不执行
}
@Override
protected void finalize(){
    System.out.println("我已经被销毁了");
}

BigIneger和BigDecimal类

概念:BigIneger 适合保存比较大的整型数据;BigDecimal 适合保存精度更高的浮点型数据

常用方法

// BigIneger 适合保存比较大的整型数据  long数据类型无法存储
BigInteger bigInteger = new BigInteger("998456349564561256465489");
System.out.println(bigInteger); // 998456349564561256465489
// + - * / 运算 => 方法实现 add subtract multiply divide
bigInteger = bigInteger.add(new BigInteger("1"));
System.out.println(bigInteger); // 998456349564561256465490
bigInteger = bigInteger.divide(new BigInteger("2"));
System.out.println(bigInteger); // 499228174782280628232745
bigInteger = bigInteger.subtract(new BigInteger("2"));
System.out.println(bigInteger); // 499228174782280628232743
bigInteger = bigInteger.multiply(new BigInteger("2"));
System.out.println(bigInteger); // 998456349564561256465486
​
​
​
// BigDecimal 适合保存精度更高的浮点数  double数据类型无法存储
BigDecimal bigDecimal = new BigDecimal("9980.2561295645485648548485646541");
System.out.println(bigDecimal); // 9980.2561295645485648548485646541
// + - * / 运算 => 方法实现 add  subtract multiply divide
bigDecimal = bigDecimal.add(new BigDecimal("1"));
System.out.println(bigDecimal); // 9981.2561295645485648548485646541
bigDecimal = bigDecimal.divide(new BigDecimal("2")); // 如果除不尽则返回算术异常
System.out.println(bigDecimal); // 4990.62806478227428242742428232705
bigDecimal = bigDecimal.subtract(new BigDecimal("2"));
System.out.println(bigDecimal); // 4988.62806478227428242742428232705
bigDecimal = bigDecimal.multiply(new BigDecimal("2"));
System.out.println(bigDecimal); // 9977.25612956454856485484856465410
// 解决小数除法异常问题:指定精度(JDK9以后不建议使用)
bigDecimal = bigDecimal.divide(new BigDecimal("2.3326"),BigDecimal.ROUND_CEILING);
System.out.println(bigDecimal); // 4277.31121047952866537548167909376

源码分析BigIneger

// BigIneger 适合保存比较大的整型数据  long数据类型无法存储
BigInteger bigInteger = new BigInteger("998456349564561256465489");
System.out.println(bigInteger); // 998456349564561256465489
​
// 源码分析
public BigInteger(String val) {
    this(val, 10); // 默认十进制
}
public BigInteger(String val, int radix) {
    int cursor = 0, numDigits;
    final int len = val.length();
​
    if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)
        throw new NumberFormatException("Radix out of range");
    if (len == 0)
        throw new NumberFormatException("Zero length BigInteger");
​
    // 检查符号
    int sign = 1;
    int index1 = val.lastIndexOf('-');
    int index2 = val.lastIndexOf('+');
    if (index1 >= 0) {
        if (index1 != 0 || index2 >= 0) {
            throw new NumberFormatException("Illegal embedded sign character");
        }
        sign = -1;
        cursor = 1;
    } else if (index2 >= 0) {
        if (index2 != 0) {
            throw new NumberFormatException("Illegal embedded sign character");
        }
        cursor = 1;
    }
    if (cursor == len)
        throw new NumberFormatException("Zero length BigInteger");
​
    // Skip leading zeros and compute number of digits in magnitude
    while (cursor < len &&
           Character.digit(val.charAt(cursor), radix) == 0) {
        cursor++;
    }
​
    if (cursor == len) {
        signum = 0;
        mag = ZERO.mag;
        return;
    }
​
    numDigits = len - cursor;
    signum = sign;
​
    // 预分配预期大小的数组。可能太大,但永远不能太小,通常是准确的
    long numBits = ((numDigits * bitsPerDigit[radix]) >>> 10) + 1;
    if (numBits + 31 >= (1L << 32)) {
        reportOverflow();
    }
    int numWords = (int) (numBits + 31) >>> 5;
    int[] magnitude = new int[numWords];
​
    // Process first (potentially short) digit group
    int firstGroupLen = numDigits % digitsPerInt[radix];
    if (firstGroupLen == 0)
        firstGroupLen = digitsPerInt[radix];
    String group = val.substring(cursor, cursor += firstGroupLen);
    magnitude[numWords - 1] = Integer.parseInt(group, radix);
    if (magnitude[numWords - 1] < 0)
        throw new NumberFormatException("Illegal digit");
​
    // Process remaining digit groups
    int superRadix = intRadix[radix];
    int groupVal = 0;
    while (cursor < len) {
        group = val.substring(cursor, cursor += digitsPerInt[radix]);
        groupVal = Integer.parseInt(group, radix);
        if (groupVal < 0)
            throw new NumberFormatException("Illegal digit");
        destructiveMulAdd(magnitude, superRadix, groupVal);
    }
    // Required for cases where the array was overallocated.
    mag = trustedStripLeadingZeroInts(magnitude);
    if (mag.length >= MAX_MAG_LENGTH) {
        checkRange();
    }
}

日期类

第一代日期类

Date:精确到毫秒,代表瞬间

SimpleDateFormat:格式和解析日期类(日期 <=> 文本)

public static void main(String[] args) throws ParseException {
    // Date 日期类
    Date date = new Date(); // 当前日期
    System.out.println(date); // Mon Apr 25 11:49:31 CST 2022
    Date date2 = new Date(4564956); // 输入距离1970年1月1日的毫秒数
    System.out.println(date2); // Thu Jan 01 09:16:04 CST 1970
​
    // SimpleDateFormat 格式和解析日期类 按照自己的格式的日期  年 月 日 时 分 秒 星期
    SimpleDateFormat sdf = new SimpleDateFormat("YYYY年MM月dd日 hh:mm:ss E");
    System.out.println(sdf.format(date)); // 2022年04月25日 11:28:41 周一
​
    String dateStr = "2021年02月26日 05:07:32 周一";
    System.out.println(sdf.format(sdf.parse(dateStr))); // 2021年12月28日 05:07:32 周一  
}

SimpleDateFormat的规定格式

image-20220225170623223

第二代日期类

Calendar类(日历) 是一个抽象类

// 抽象类 可以通过getInstance方法获取实例
Calendar calendar = Calendar.getInstance();
System.out.println("年:"+calendar.get(calendar.YEAR)); // 年:2022
System.out.println("月:"+calendar.get(calendar.MONTH)+1); // 月:2 源码:JANUARY} which is 0
System.out.println("日:"+calendar.get(calendar.DAY_OF_MONTH)); // 日:25
System.out.println("小时:"+calendar.get(calendar.HOUR)); // 小时:8
System.out.println("分钟:"+calendar.get(calendar.MINUTE)); // 分钟:11
System.out.println("秒:"+calendar.get(calendar.SECOND)); // 秒:46

第三代日期类 (JDK8)

LocalDate 日期:年月日

LocalTime 时间:时分秒

LocalDateTime:年月日 时分秒

LocalDateTime localDateTime = LocalDateTime.now();
LocalTime localTime = LocalTime.now();
LocalDate localDate = LocalDate.now();
// localDateTime: 2022-02-25T20:30:19.250574 
// LocalDate: 2022-02-25
// LocalTime: 20:30:19.250574 
System.out.println("localDateTime: "+localDateTime+" LocalTime: "+
                   localTime+" LocalDate: "+localDate);
​
System.out.println("年: "+localDateTime.getYear()); // 年: 2022
System.out.println("月: "+localDateTime.getMonth()); // 月: FEBRUARY
System.out.println("日: "+localDateTime.getDayOfMonth()); // 日: 25
System.out.println("时: "+localDateTime.getHour()); // 时: 20
System.out.println("分: "+localDateTime.getMinute()); // 分: 33
System.out.println("秒: "+localDateTime.getSecond()); // 秒: 45

DateTimeFormatter格式日期类

//  DateTimeFormatter 格式日期类
LocalDateTime localDateTime = LocalDateTime.now();
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("YYYY年MM月dd日 hh:mm:ss E");
System.out.println(dateTimeFormatter.format(localDateTime)); //  2022年04月25日 11:28:41 周一
  所有字母“A”至“Z”和“a”至“z”保留为图案字母。 定义了以下图案字母: 
  Symbol  Meaning                     Presentation      Examples
  ------  -------                     ------------      -------
   G       era                         text              AD; Anno Domini; A
   u       year                        year              2004; 04
   y       year-of-era                 year              2004; 04
   D       day-of-year                 number            189
   M/L     month-of-year               number/text       7; 07; Jul; July; J
   d       day-of-month                number            10
​
   Q/q     quarter-of-year             number/text       3; 03; Q3; 3rd quarter
   Y       week-based-year             year              1996; 96
   w       week-of-week-based-year     number            27
   W       week-of-month               number            4
   E       day-of-week                 text              Tue; Tuesday; T
   e/c     localized day-of-week       number/text       2; 02; Tue; Tuesday; T
   F       week-of-month               number            3
​
   a       am-pm-of-day                text              PM
   h       clock-hour-of-am-pm (1-12)  number            12
   K       hour-of-am-pm (0-11)        number            0
   k       clock-hour-of-am-pm (1-24)  number            0
​
   H       hour-of-day (0-23)          number            0
   m       minute-of-hour              number            30
   s       second-of-minute            number            55
   S       fraction-of-second          fraction          978
   A       milli-of-day                number            1234
   n       nano-of-second              number            987654321
   N       nano-of-day                 number            1234000000
​
   V       time-zone ID                zone-id           America/Los_Angeles; Z; -08:30
   z       time-zone name              zone-name         Pacific Standard Time; PST
   O       localized zone-offset       offset-O          GMT+8; GMT+08:00; UTC-08:00;
   X       zone-offset 'Z' for zero    offset-X          Z; -08; -0830; -08:30; -083015; -08:30:15;
   x       zone-offset                 offset-x          +0000; -08; -0830; -08:30; -083015; -08:30:15;
   Z       zone-offset                 offset-Z          +0000; -0800; -08:00;
​
   p       pad next                    pad modifier      1
​
   '       escape for text             delimiter
   ''      single quote                literal           
   [       optional section start
   ]       optional section end
   #       reserved for future use
   {       reserved for future use
   }       reserved for future use 

Instant 时间戳

// Instant -> Date
Instant instant = Instant.now();
System.out.println(instant); // 2022-02-25T14:48:47.557358800Z
java.util.Date from = Date.from(instant);
System.out.println(from); // Fri Feb 25 22:48:47 CST 2022// Date -> Instant
Instant instant1 = from.toInstant();
System.out.println(instant1); // 2022-02-25T14:55:27.377Z