初识常用类

大家好呀!我是小笙!我学习了韩顺平老师的常用类的知识,收获颇丰!现在来和大家分享笔记!

常用类

包装类(Wrapper)

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

Boolean

image-20211026161841862

Character

image-20211026162014901

Number父类下的直接子类

image-20211026165801659

装箱 & 拆箱
  • 自动拆装箱
  • 手动拆装箱
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-20211027111537252

以下是依次跳转的函数

image-20211027111819114

image-20211027111852782

image-20211027111925147

image-20211027111951932

总结

  1. 手动拆装箱和自动拆装箱底层没有本质区别
  2. 包装类转 <=>基本数据类型
    • 基本数据类型 --> 包装类 装箱 本质:valueOf函数
    • 包装类 --> 基本数据类型 拆箱 本质:charValue函数

习题

// 如下输出结果是什么
习题1
Object obj = true? new Integer(1):new Double(2.0); // 三元运算符是一个整体
System.out.println(obj); // 1.0
习题2
Object obj1;
if(true){
    obj1 = new Integer(1);
}else{
    obj1 = new Double(2.0);
}
System.out.println(obj); // 1
包装类 <=> String类
Wrapper Vs 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);
         *   }
         */
    }
}
Wrapper类的常用方法

Integer 官方文档

以Integer包装类为例

Integer

包装类的相关面试题

public class Wrapper02 {
    public static void main(String[] args) {
        /*
         * 源码:IntegerCache.low -128   IntegerCache.high 127
         *     public static Integer valueOf(int i) {
         *         if (i >= IntegerCache.low && i <= IntegerCache.high)
         *             return IntegerCache.cache[i + (-IntegerCache.low)];
         *         return new Integer(i);
         *     }
         * 如果valueOf(value) value > -128 && value < 127 则 返回 IntegerCache.cache[i + (-IntegerCache.low)]
         * 否则 返回新对象Integer
         */
        System.out.println(new Integer(1) == new Integer(1));  // false
        Integer a = 1;
        Integer b = 1;
        System.out.println(a==b); // true
        Integer m = 128;
        Integer n = 128;
        System.out.println(m==n); // false
        Integer x = 128;
        int y = 128;
        System.out.println(x==y); // true
        
    }
}

String类

String类的概述
public static void main(String[] args) {
       /**
         * String
         * 概念:是一组字符序列 本质上是char[] value 字符数组实现
         * "Al_tair"被称为字符常量 用双引号括起来的字符序列
         *  一个字符占用两个字节(每个字符不区分字母和汉字)
         * public final class String 说明String的final类,不能被其它类继承
         * private final byte[] value 用于存放字符串 value是用final修饰的类型,该数组不能指向新地址,但是能修改它的值
         */
    String name = "Al_tair";
}
接口和构造器

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对象的引用
// 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 官方文档

String

相关习题
// 习题1
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

// 习题2
// 2.1创建了几个对象 答:2
String s = "hello";
s = "haha";

// 2.2 创建了几个对象 答:1  结论:编译器会做优化,判断常量池对象是否有引用指向
String str = "hello" + "haha";  // 等价于 String str = "hellohaha";

// 2.3 创建了几个对象 答: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);
}

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数组中
}
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构造器 
}
常用方法
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
}
相关习题
// 习题1
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);
 * }
 */

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:不可变字符序列,效率低,但是因为存在常量池所以复用率高
  • 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方法

作用:输出数组

Integer[] array = {3,5,6,47,8};
// toString 输出数组
System.out.println(Arrays.toString(array)); // [3, 5, 6, 47, 8]
/*
 * // toString方法源码
 * 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方法

作用:通过二分搜索法进行查找,要求必须升序,如果数组中不存在,则返回 -(应该在的索引位置 + 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 源码
 * private static int binarySearch0(Object[] a, int fromIndex, int toIndex, Object key) {
 *   int low = fromIndex;
 *   int high = toIndex - 1;
 *
 *   while (low <= high) {
 *      int mid = (low + high) >>> 1;
 *      @SuppressWarnings("rawtypes") // 抑制警告
 *      Comparable midVal = (Comparable)a[mid];
 *      @SuppressWarnings("unchecked")
 *      int cmp = midVal.compareTo(key);
 *
 *       if (cmp < 0)
 *          low = mid + 1;
 *       else if (cmp > 0)
 *          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("程序开始");
    /*
     * status说明例子
     * 在一个if-else判断中,如果我们程式是按照我们预想的执行,
     * 到最后我们需要停止程式,那么我们使用System.exit(0),
     * 而System.exit(1)一般放在catch块中,当捕获到异常,需要停止程式,
     * 我们使用System.exit(1)。这个status=1是用来表示这个程式是非正常退出。
     */
    System.exit(0); // System.exit(0)是正常退出程序,而System.exit(1)或者说非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

日期类

第一代日期类

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

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

public static void main(String[] args) throws ParseException {
// Date 日期类
Date date = new Date(); // 当前日期
System.out.println(date); // Fri Feb 25 16:58:51 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年02月56日 05:07:32 周五

String dateStr = "2021年02月56日 05:07:32 周一";
System.out.println(sdf.format(sdf.parse(dateStr))); // 2021年12月363日 05:07:32 周一 会存在编译异常
}

SimpleDateFormat的规定格式

image-20220225170623223

第二代日期类

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

// 抽象类 可以通过getInstance方法获取实例
Calendar calendar = Calendar.getInstance();
System.out.println(calendar); 
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 LocalTime: 20:30:19.250574 LocalDate: 2022-02-25
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年02月56日 08:39:43 周五
// 所有字母“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

相关面试题

1.String类有哪些方法?

String类是Java最常用的API,它包含了大量处理字符串的方法,比较常用的有:

  • char charAt(int index):返回指定索引处的字符;
  • String substring(int beginIndex, int endIndex):从此字符串中截取出一部分子字符串;
  • String[] split(String regex):以指定的规则将此字符串分割成数组;
  • String trim():删除字符串前导和后置的空格;
  • int indexOf(String str):返回子串在此字符串首次出现的索引;
  • int lastIndexOf(String str):返回子串在此字符串最后出现的索引;
  • boolean startsWith(String prefix):判断此字符串是否以指定的前缀开头;
  • boolean endsWith(String suffix):判断此字符串是否以指定的后缀结尾;
  • String toUpperCase():将此字符串中所有的字符大写;
  • String toLowerCase():将此字符串中所有的字符小写;
  • String replaceFirst(String regex, String replacement):用指定字符串替换第一个匹配的子串;
  • String replaceAll(String regex, String replacement):用指定字符串替换所有的匹配的子串。

2.String可以被继承吗?

String类由final修饰,所以不能被继承。

扩展阅读

在Java中,String类被设计为不可变类,主要表现在它保存字符串的成员变量是final的。

  • Java 9之前字符串采用char[]数组来保存字符,即 private final char[] value;
  • Java 9做了改进,采用byte[]数组来保存字符,即 private final byte[] value;

之所以要把String类设计为不可变类,主要是出于安全和性能的考虑,可归纳为如下4点。

  • 由于字符串无论在任何 Java 系统中都广泛使用,会用来存储敏感信息,如账号,密码,网络路径,文件处理等场景里,保证字符串 String 类的安全性就尤为重要了,如果字符串是可变的,容易被篡改,那我们就无法保证使用字符串进行操作时,它是安全的,很有可能出现 SQL 注入,访问危险文件等操作。
  • 在多线程中,只有不变的对象和值是线程安全的,可以在多个线程中共享数据。由于 String 天然的不可变,当一个线程”修改“了字符串的值,只会产生一个新的字符串对象,不会对其他线程的访问产生副作用,访问的都是同样的字符串数据,不需要任何同步操作。
  • 字符串作为基础的数据结构,大量地应用在一些集合容器之中,尤其是一些散列集合,在散列集合中,存放元素都要根据对象的 hashCode() 方法来确定元素的位置。由于字符串 hashcode 属性不会变更,保证了唯一性,使得类似 HashMap,HashSet 等容器才能实现相应的缓存功能。由于 String 的不可变,避免重复计算 hashcode,只要使用缓存的 hashcode 即可,这样一来大大提高了在散列集合中使用 String 对象的性能。
  • 当字符串不可变时,字符串常量池才有意义。字符串常量池的出现,可以减少创建相同字面量的字符串,让不同的引用指向池中同一个字符串,为运行时节约很多的堆内存。若字符串可变,字符串常量池失去意义,基于常量池的 String.intern() 方法也失效,每次创建新的字符串将在堆内开辟出新的空间,占据更多的内存。

因为要保证String类的不可变,那么将这个类定义为final的就很容易理解了。如果没有final修饰,那么就会存在String的子类,这些子类可以重写String类的方法,强行改变字符串的值,这便违背了String类设计的初衷。

3.说一说String和StringBuffer有什么区别

String类是不可变类,即一旦一个String对象被创建以后,包含在这个对象中的字符序列是不可改变的,直至这个对象被销毁。

StringBuffer对象则代表一个字符序列可变的字符串,当一个StringBuffer被创建以后,通过StringBuffer提供的append()、insert()、reverse()、setCharAt()、setLength()等方法可以改变这个字符串对象的字符序列。一旦通过StringBuffer生成了最终想要的字符串,就可以调用它的toString()方法将其转换为一个String对象。

4.说一说StringBuffer和StringBuilder有什么区别

tringBuffer、StringBuilder都代表可变的字符串对象,它们有共同的父类 AbstractStringBuilder,并且两个类的构造方法和成员方法也基本相同。不同的是,StringBuffer是线程安全的,而StringBuilder是非线程安全的,所以StringBuilder性能略高。一般情况下,要创建一个内容可变的字符串,建议优先考虑StringBuilder类。

5.使用字符串时,new和""推荐使用哪种方式?

先看看 “hello” 和 new String(“hello”) 的区别:

  • 当Java程序直接使用 “hello” 的字符串直接量时,JVM将会使用常量池来管理这个字符串;
  • 当使用 new String(“hello”) 时,JVM会先使用常量池来管理 “hello” 直接量,再调用String类的构造器来创建一个新的String对象,新创建的String对象被保存在堆内存中。

显然,采用new的方式会多创建一个对象出来,会占用更多的内存,所以一般建议使用直接量的方式创建字符串。

6.两个字符串相加的底层是如何实现的?

如果拼接的都是字符串直接量,则在编译时编译器会将其直接优化为一个完整的字符串,和你直接写一个完整的字符串是一样的。

如果拼接的字符串中包含变量,则在编译时编译器采用StringBuilder对其进行优化,即自动创建StringBuilder实例并调用其append()方法,将这些字符串拼接在一起。

7.遇到过异常吗,如何处理?

在Java中,可以按照如下三个步骤处理异常:

  1. 捕获异常

    将业务代码包裹在try块内部,当业务代码中发生任何异常时,系统都会为此异常创建一个异常对象。创建异常对象之后,JVM会在try块之后寻找可以处理它的catch块,并将异常对象交给这个catch块处理。

  2. 处理异常

    在catch块中处理异常时,应该先记录日志,便于以后追溯这个异常。然后根据异常的类型、结合当前的业务情况,进行相应的处理。比如,给变量赋予一个默认值、直接返回空值、向外抛出一个新的业务异常交给调用者处理,等等。

  3. 回收资源

    如果业务代码打开了某个资源,比如数据库连接、网络连接、磁盘文件等,则需要在这段业务代码执行完毕后关闭这项资源。并且,无论是否发生异常,都要尝试关闭这项资源。将关闭资源的代码写在finally块内,可以满足这种需求,即无论是否发生异常,finally块内的代码总会被执行。

8.请介绍Java的异常接口

Throwable是异常的顶层父类,代表所有的非正常情况。它有两个直接子类,分别是Error、Exception。

Error是错误,一般是指与虚拟机相关的问题,如系统崩溃、虚拟机错误、动态链接失败等,这种错误无法恢复或不可能捕获,将导致应用程序中断。通常应用程序无法处理这些错误,因此应用程序不应该试图使用catch块来捕获Error对象。在定义方法时,也无须在其throws子句中声明该方法可能抛出Error及其任何子类。

Exception是异常,它被分为两大类,分别是Checked异常和Runtime异常。所有的RuntimeException类及其子类的实例被称为Runtime异常;不是RuntimeException类及其子类的异常实例则被称为Checked异常。Java认为Checked异常都是可以被处理(修复)的异常,所以Java程序必须显式处理Checked异常。如果程序没有处理Checked异常,该程序在编译时就会发生错误,无法通过编译。Runtime异常则更加灵活,Runtime异常无须显式声明抛出,如果程序需要捕获Runtime异常,也可以使用try…catch块来实现。

9.int和Integer有什么区别,二者在做==运算时会得到什么结果?

int是基本数据类型,Integer是int的包装类。二者在做==运算时,Integer会自动拆箱为int类型,然后再进行比较。届时,如果两个int值相等则返回true,否则就返回false。

10.说一说自动装箱、自动拆箱的应用场景

自动装箱、自动拆箱是JDK1.5提供的功能。

自动装箱:可以把一个基本类型的数据直接赋值给对应的包装类型;

自动拆箱:可以把一个包装类型的对象直接赋值给对应的基本类型;

通过自动装箱、自动拆箱功能,可以大大简化基本类型变量和包装类对象之间的转换过程。比如,某个方法的参数类型为包装类型,调用时我们所持有的数据却是基本类型的值,则可以不做任何特殊的处理,直接将这个基本类型的值传入给方法即可。

11.为啥要有包装类?

Java语言是面向对象的语言,其设计理念是“一切皆对象”。但8种基本数据类型却出现了例外,它们不具备对象的特性。正是为了解决这个问题,Java为每个基本数据类型都定义了一个对应的引用类型,这就是包装类。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

罗念笙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值