常用类

常用类

Object类

修饰符和类型 方法的描述
protected Object clone()创建并返回此对象的副本
boolean equals(Object obj)指示一些其他对象是否等于此
protected void finalize()当垃圾收集确定不再有对该对象的引用时,垃圾收集器在对象上调用该对象
Class<?> getClass()返回此 Object的运行时类
int hashCode()返回对象的哈希码值
void notify()唤醒正在等待对象监视器的单个线程
void notifyAll()唤醒正在等待对象监视器的所有线程
String toString()返回对象的字符串表示形式
void wait()导致当前线程等待,直到另一个线程调用该对象的 notify()方法或 notifyAll()方法
void wait(long timeout)导致当前线程等待,直到另一个线程调用 notify()方法或该对象的 notifyAll()方法,或者指定的时间已过
void wait(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类

包装类的分类

包装类 基本数据类型 直接父类
boolean Boolean Object
char Character Object
byte Byte Number
short Short Number
int Int Number
long Long Number
float Float Number
double Double Number

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数组中
}

常用方法

修饰符和类型 方法和描述
StringBuffer append(String str)将指定的字符串附加到此字符序列
StringBuffer delete(int start, int end)删除此序列的子字符串中的字符
int length()返回长度(字符数)
StringBuffer replace(int start, int end, String str)用指定的String中的字符替换此序列的子字符串中的 String
int indexOf(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
posted @ 2022-06-11 12:47  罗念笙  阅读(25)  评论(0)    收藏  举报