java基础笔记

287 阅读5分钟

注: 拉钩教育大数据训练营java基础模块三之java类库笔记 + 补充

Jdk11

Integer

建议 Integer.valueOf() 创建; Integer-》int : intValue();

Q: BigInteger Integer String 的底层源码分析

String

String类的常用方法 static valueOf() trime, toUpperCase(); toLowerCase(); contains(Character s);内部调用indexof(s.toString()) startWith();endsWith() substring(int i);substring(int i ,int j);不包含【j】 split(); match(); replace(char a, char b); replaceFirst (String source,String targer); replaceAll(String source,String targer);

正则表达式

StringBuilder

继承于 abstract class AbstractStringBuilder implements Appendable, CharSequence

byte [] value;

存储数据的数组,The value is used for character storage 注:JDK 8 为 char [] value

byte coder;

The id of the encoding used to encode the bytes in {@code value}.

int count;

The count is the number of characters used.

初始化与append操作

StringBuilder a = new StringBuilder();

初始化ade调用过程:初始化一个长度为16的value数组。调用super(16),其中a.length()为0,a.capacity()为16;因为capacity()返回的是数组value的大小,而length()返回的是数组中有多少数据。

StringBuilder b = new StringBuilder("hello");

初始化b时过程调用过程:super("hello".length + 16);append("str");StringingBuilder 成员方法 append(String str) 是调用其父类AbstractStringBuilder的方法。

public AbstractStringBuilder append(String str) {
    if (str == null)
    return appendNull();
    int len = str.length();
    
    ensureCapacityInternal(count + len);//检查value在添加str后是否要扩容
    /*
        如果count+len > value.length 就得扩容,否则什么都不做;
        扩容value = Arrays.copyOf(value,newCapacity(minimumCapacity));
        将旧数组value的数据复制到扩容后的新数组上,并重新引用该新数组。
    */
    
    //jdk 1.8
    str.getChars(0, len, value, count);//简单理解就是在value数组后面添加str
    /*String对象的成员方法,这里的value是String中的数组value
        getchars(int srcBegin, int srcEnd, char dst[], int dstBegin)
        把下标从srcBegin到srcEnd的字符片段 复制 到下标为dstBegin开始的dst数组中。
        底层调用了
        System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
    */
    
    //jdk 11
    putStringAt(count, str);
    
    
    count += len;//添加str后数组数据长度刷新
    return this;
}

AbstractStringBuilder 的扩容机制 int newCapacity(minimumCapacity)源代码剖析: newCapacity为原数组长度增大一倍后再加2,再比较它与minCapacity取它们的最大值,再判断下newCapacity是否超过了MAX_ARRAY_SIZE限制的大小,如果超过了且没有大于Integer.MAX_VALUE 或者 newCapacity 一开始便小于 MAX_ARRAY_SIZE的话,就返回新数组容量数值newCapacity;如果超过了Integer.MAX_VALUE就抛内存容量超出异常。

private int newCapacity(int minCapacity) {
        // overflow-conscious code
        int newCapacity = (value.length << 1) + 2;
        if (newCapacity - minCapacity < 0) {
            newCapacity = minCapacity;
        }
        return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
            ? hugeCapacity(minCapacity)
            : newCapacity;
    }

    private int hugeCapacity(int minCapacity) {
        if (Integer.MAX_VALUE - minCapacity < 0) { // overflow
            throw new OutOfMemoryError();
        }
        return (minCapacity > MAX_ARRAY_SIZE)
            ? minCapacity : MAX_ARRAY_SIZE;
    }

这里有个疑问:为什么有个MAX_ARRAY_SIZE限制,为什么不直接比较Integer.MAX_VALUE 源代码中如下,大致意思是除非有需要数组的最大容量应该留出点空间给虚拟机VM存储一些头部文件信息,任何要分配跟大容量数组的行为都可能会导致虚拟机内存不足异常。

  • 什么是虚拟机头部文件呢? 后面补坑
 /**
     * The maximum size of array to allocate (unless necessary).
     * Some VMs reserve some header words in an array.
     * Attempts to allocate larger arrays may result in
     * OutOfMemoryError: Requested array size exceeds VM limit
     */
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
StringBuilder 的 insert()与delete()

StringBuilder继承了父类的插入删除操作,insert()核心的两个重载方法是

//从offset开始添加str
//如果不需要扩容,就将数组向右偏移len个长度单位,再复制新字符串到偏移位置
public AbstractStringBuilder insert(int offset, String str){
    if ((offset < 0) || (offset > length()))
            throw new StringIndexOutOfBoundsException(offset);
        if (str == null)
            str = "null";
        int len = str.length();
        ensureCapacityInternal(count + len);
        System.arraycopy(value, offset, value, offset + len, count - offset);
        str.getChars(value, offset);
        count += len;
        return this;
}
//从index开始 添加字符str片段,其中字符片段以offset开始 长度为len
public AbstractStringBuilder insert(int index, char[] str, int offset,int len){
    ...
    System.arraycopy(value, index, value, index + len, count - index);
    System.arraycopy(str, offset, value, index, len);
    ...
}

删除操作

//从start删除到end,但不包括下标哪个元素
//因为底层调用的是System.arraycopy(),没有真正内存的删除,
//而是将value数组end位置起到(count-1)位置这些元素 拷贝到 start 开始的地方。
public AbstractStringBuilder delete(int start, int end){
    ...
    ...
    int len = end - start;
        if (len > 0) {
            System.arraycopy(value, start+len, value, start, count-end);
            count -= len;
        }
}
//同上理调用System.arraycopy()方法
 public AbstractStringBuilder deleteCharAt(int index){
     if ((index < 0) || (index >= count))
            throw new StringIndexOutOfBoundsException(index);
        System.arraycopy(value, index+1, value, index, count-index-1);
        count--;
        return this;
 }

jdk11 版本

public AbstractStringBuilder delete(int start, int end) {
        int count = this.count;
        if (end > count) {
            end = count;
        }
        checkRangeSIOOBE(start, end, count);
        int len = end - start;
        if (len > 0) {
            shift(end, -len);
            this.count = count - len;
        }
        return this;
    }
    private void shift(int offset, int n) {
        System.arraycopy(value, offset << coder,
                         value, (offset + n) << coder, (count - offset) << coder);
    }
反转和查找
public AbstractStringBuilder reverse() {
        byte[] val = this.value;
        int count = this.count;
        int coder = this.coder;
        int n = count - 1;
        if (COMPACT_STRINGS && coder == LATIN1) {
            for (int j = (n-1) >> 1; j >= 0; j--) {
                int k = n - j;
                byte cj = val[j];
                val[j] = val[k];
                val[k] = cj;
            }
        } else {
            StringUTF16.reverse(val, count);
        }
        return this;
        }
        
public AbstractStringBuilder replace(int start, int end, String str) {
        int count = this.count;
        if (end > count) {
            end = count;
        }
        checkRangeSIOOBE(start, end, count);
        int len = str.length();
        int newCount = count + len - (end - start);
        ensureCapacityInternal(newCount);
        shift(end, newCount - count);
        this.count = newCount;
        putStringAt(start, str);
        return this;
    }

StringUTF16 和 StringLatin1 以及 jdk11 中String 有关byte和字符的新特性 日后补充

日期类

Date a = new Date() 已过时

SimpleDateFormat 设置时间格式 “yy-MM-dd HH-mm-ss”
Calender类
  • java.util.Calender类主要用于描述特定的瞬间,取代Date类中的过时方法实现全球化。 该类是个抽象类,因此不能实例化对象,其具体子类针对不同国家的日历系统,其中应用最广泛的是GregorianCalendar(格里高利历),对应世界上绝大多数国家/地区使用的标准日历系统
多态三种方式
  • 通过方法的参数传递形成多态; public static void draw(Shape s){ s.show(); } draw(new Rect(1, 2, 3, 4));
  • 在方法体中直接使用多态的语法格式 Account acc = new FixedAccount();
  • 通过方法的返回值类型形成多态 Calender getInstance(){ return new GregorianCalendar(zone, aLocale); }

缺点:Date类中的年份是从1900开始的,而月份都从0开始。 格式化只对Date类有用,对Calendar类则不能使用。 非线程安全等。

JAVA8 日期类
LockDate LockTime LockDateTime(常用)
  • 获取年份字段的数值 int getYear()
  • 设置为参数指定的年 LocalDateTime withYear(int year)
  • 加上参数指定的年 LocalDateTime plusYears(long years)
  • 减去参数指定的年 LocalDateTime minusYears(long years) 年月日时分秒 的各种方法同上
Instant类
  • static Instant now() 从系统时钟上获取当前时间
  • OffsetDateTimeatOffset(ZoneOffset offset) 将此瞬间与偏移量组合以创建偏移日期时间
  • static Instant ofEpochMilli(long epochMilli) 根据参数指定的毫秒数来构造对象,参数为距离1970年1月1 日0时0分0秒的毫秒数
  • long toEpochMilli() 获取距离1970年1月1日0时0分0秒的毫秒数
DateFormatter类
  • static DateTimeFormatter ofPattern(String pattern) 根据参数指定的模式来获取对象
  • String format(TemporalAccessor temporal) 将参数指定日期时间转换为字符串
  • TemporalAccessor parse(CharSequence text) 将参数指定字符串转换为日期时间
        LocalDateTime dd = LocalDateTime.now();
        DateTimeFormatter ff = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String string  = ff.format(dd);
        System.out.println(string);

        TemporalAccessor par = ff.parse(string);
        System.out.println(par);

集合

源码分析

日后补坑