Java基础(三)——包装类、字符串类、日期类、大数类的使用与原理

版本说明发布日期
1.0发布文章第一版2020-11-07
1.1新增一个小节:【不要被double骗了】2020-11-24
之前【由此引申出的编译器常量优化机制】的答案是错的,进行了更正

文章目录

前言

  • 这篇文章不是面面俱到的基础知识集合,只是我个人的学习笔记。学习资料来源于《拉勾教育Java就业急训营》。
  • 以下所有内容仅代表个人观点,不一定正确。

常用类库总览

包名说明
java.lang核心包,包含了一些比较重要的类,该包中的所有内容由Java虚拟机自动导入。例如System、String。这个lang其实是language的缩写。
java.util工具包,提供了工具类和集合类。如Scanner、Random、List。
java.io输入输出包,提供了大量流相关的类。如FileInputStream。
java.net网络包,提供了网络编程相关的类。如ServerSocket、Socket。
java.sql数据包,提供了大量数据库操作相关的类。如DriverManager、Connection

java.lang包中的一些常用的类

Object类——这就是万物皆对象~

基本概念

  • 位于java.lang.Object。
  • 是java中所有类的根类,也就是说是java所有类的直接或者间接父类。
    • 一个人只能有一个对象,但是一个java它可以有无数个对象(说到这里,有些小伙伴流下了羡慕的口水)。
    • java表示自己对象太多,不好管啊!所以用一个Object类统一管理。这么一说Object有点像曾经的东厂哈哈哈。
  • 如果一个类定义的时候没有extends关键字,则默认会extends Object。这就是上面说的直接父类。

常用方法

方法声明功能介绍
Object()无参构造方法。
boolean equals(Object obj)用于判断两个对象是否相等。Object类中的逻辑是比较地址是否相等,与 == 运算符的结果一致。所以该方法通常需要重写。若该方法被重写,同时则应该重写hashCode方法,以保证结果的一致性。
int hashCode()用于获取调用对象的哈希码值(可通俗理解为内存地址的编号)。若两个对象调用equals方法相等,则各自调用该方法的结果必须相同;若两个调用对象equals方法不相等,则各自调用该方法的结果应该不相同。所以该方法通常需要与equals方法同时重写。
String toString()用于获取调用对象的字符串形式。该方法默认返回的字符串为:包名.类名@哈希码值的十六进制。为了返回更有意义的数据,该方法通常需要重写。使用print打印引用或使用字符串拼接引用时,都会自动调用该方法。
Class<?> getClass()用于返回调用对象执行时的Class实例,反射机制使用。
boolean equals(Object obj)
  • Java API文档对于equals方法提出了几个特性,当我们重写equals时,应当自觉遵循这些特性。
  • 自反性:对于任何非空引用x,x.equals(x)应该返回true。
  • 对称性:对于任何非空引用x和y,x.equals(y)应该返回true,当且仅当y.equals(x)返回true。
  • 传递性:对于任何非空引用x、y和z。如果x.equals(y)返回true、y.equals(z)返回true。则x.equals(z)也应该返回true。
  • 一致性:对于任何非空引用x和y,如果未修改对象上用于equals比较的信息,则多次调用x.equals(y)应该始终返回true或始终返回false。
  • 非空性:对于任何非空引用x,x.equals(null)应该返回false。
  • 为了满足这些特性,下面给一个重写的例子。当然方法不是绝对的,只要能满足这些特性就OK啦~
public class Person {
	private String id;

	public Person(String id) {
		this.id = id;
	}

	public void setId(String id) {
		this.id = id;
	}

	//重写Object的equals方法
	@Override
	public boolean equals(Object obj) {
		if (obj instanceof Person) {
			//比较特征
			return this.id.equals(((Person) obj).id);
		}
		return false;
	}
	
	//重写hashCode方法
	@Override
	public int hashCode(){
		return id.hashCode();
	}

	public static void main(String[] args) {
		Person yu = new Person("1996817");
		Person angel = new Person("1997414");
		System.out.println("angel.equals(yu):" + angel.equals(yu));
		System.out.println("更改id");
		yu.setId("1997414");
		System.out.println("angel.equals(yu):" + angel.equals(yu));
		System.out.println("yu.equals(angel):" + yu.equals(angel));
		System.out.println("angel.equals(angel):" + angel.equals(angel));
		System.out.println("angel.equals(null):" + angel.equals(null));
	}
}
  • 运行结果如下:
angel.equals(yu):false
更改id
angel.equals(yu):true
yu.equals(angel):true
angel.equals(angel):true
angel.equals(null):false
int hashCode()
  • hashCode是在使用哈希集合时,在散列表中用到的。这一点从API文档中也能看到。所以说,我们应该尽量让equals不等的对象,hashCode也不等。而equals相等的对象,hashCode必须相等。
  • 上面说过,重写了equals方法,必然还需要重写hashCode方法。但是怎么重写呢?
    • 最简单最偷懒的方法,就是直接返回equals比较的特征值。比如上面例子重写的hashCode。
    • 更合理的重写方式呢,可以调用Objects类的一个静态方法:hash(Object… values)。
自动生成equals、hashCode、toString
  • 如果你用的idea,恭喜你,这三个方法可以自动按照模板生成。生成方式和getter、setter类似。
  • 下面这两个方法就是自动生成的,可以感受一下:
	@Override
	public boolean equals(Object o) {
		if (this == o) return true;
		if (o == null || getClass() != o.getClass()) return false;
		Person person = (Person) o;
		return Objects.equals(id, person.id);
	}

	@Override
	public int hashCode() {

		return Objects.hash(id);
	}
	
	@Override
	public String toString() {
		return "Person{" +
				"id='" + id + '\'' +
				'}';
	}

包装类

基本概念

  • 位于java.lang.Byte、java.lang.Short等。
  • 用于将基本数据类型包装成对象,以满足Java“万物皆对象”的理念。
  • 目前包装类有以下几种:Byte、Short、Integer、Long、Float、Double、Boolean、Character。分别对应一种基本数据类型。
  • 数字类型的包装类统一继承了抽象类Number。
  • 将基本数据类型转换为包装类,称为装箱;将包装类转换为基本数据类型,称为拆箱。从Java1.5开始,增加了大量自动拆箱和装箱的机制。
  • 下面讲解几种典型的包装类。

Integer

常用常量
常量声明功能
public static final int MAX_VALUE表示int类型可以描述的最大值,即2^31-1
public static final int MIN_VALUE表示int类型可以描述的最小值,即-2^31
public static final int SIZE表示int类型二进制形式的位数
public static final int BYTES表示int类型所占的字节个数
public static final Class TYPE表示int类型的Class实例
常用方法
方法声明功能介绍
int intValue()获取调用对象中的整数值并返回。作为拆箱的标准方法。
static Integer valueOf(int i)根据参数指定整数值得到Integer类型对象。作为装箱的标准方法。
boolean equals(Object obj)比较调用对象与参数指定的对象是否相等
String toString()返回描述调用对象数值的字符串形式
static int parseInt(String s)将字符串类型转换为int类型并返回。字符串不合理时会抛出NumberFormatException。
static String toString(int i)获取参数指定整数的十进制字符串形式。注意和上面的toString的区别:静态且参数为int。
static String toBinaryString(int i)获取参数指定整数的二进制字符串形式
static String toHexString(int i)获取参数指定整数的十六进制字符串形式
static String toOctalString(int i)获取参数指定整数的八进制字符串形式
自动装箱机制
  • Java1.5之后有了自动装箱机制,从而让下面两行代码的效果是等价的。也就是说Integer对整数类型的赋值运算,会自动调用valueOf。
Integer a = 100;
Integer b = Integer.valueOf(100);
  • 如果想看下自动装箱池是什么样的,可以去看源码:Integer类的静态内部类IntegerCache。
自动装箱池(常量池)
  • 猜猜下面的结果是啥
public class IntegerTest {
    public static void main(String[] args){
        Integer a = 1;
        Integer b = 1;
        Integer c = Integer.valueOf(1);
        Integer d = new Integer(1);
        Integer e = 128;
        Integer f = 128;

        System.out.println(a==b);
        System.out.println(c==b);
        System.out.println(d==b);
        System.out.println(f==e);
    }
}
  • 结果是
true
true
false
false
  • 有的小伙伴又懵了:怎么着?说好的==比地址呢?怎么结果看起来如此木有规律!?
  • 但是这个真的比的是地址!为什么呢?因为包装类有一个叫自动装箱池的东西,对于-128~127的整数,对应的包装类都作为常量存放在了内存当中。所以a、b、c都是直接指向的内存中的这些常量,地址也就理所当然是相同的了。
  • 需要注意的是,如果是通过直接调用构造方法,则不会用到自动装箱池,而是指向的新new出来的内存。
自动拆箱机制
  • 猜猜下面的结果是啥
Integer a = 1;
Integer b = 2;
Long g = 3L;
System.out.println(g == (a + b));
System.out.println(g.equals(a + b));
  • 结果如下:
true
false
  • 为什么呢?
    • 对于第一个比较:大家可能第一时间会想到==比较的是地址,所以理应为false。但是包装类在进行运算符运算的时候,会触发“自动拆箱机制”,也就是说a + b这东西,计算结果会从Integer变为int。而Long与int进行==比较,Long也会变为long。所以最终就变成了基本数据类型的比较,结果自然是true。
    • 对于第二个比较:这个比较简单,因为Long类重写了equals方法,自己去看一下就知道了。如果比较的是非Long类型,则直接为false。

Double

  • Double和Integer基本大同小异,只是有一个方法需要提及一下:boolean isNaN()
  • 这个方法是非静态的,所以肯定是Double的引用来调用,也就是说调用这个方法的肯定是一个数字。所以为啥还要判断是否是数字呢?
  • 然后看一下下面这个例子就明白了哈哈哈。此非数字不是彼非数字。
public class DoubleTest {
	public static void main(String[] args) {
		Double a = 0/0.0;
		System.out.println(a);
		System.out.println(a.isNaN());
	}
}
  • 运行结果如下。也就是说这个方法是用来判断是否存在0/0.0的情况的。顺道提一句,0/0直接编译器报算术运算错误哈。之所以0.0可以除,0不能除,终究还是因为误差的问题。
NaN
true
  • 还有一个boolean isInfinite()方法也是同理。无穷大嘛,一个非零数字除以0.0的情况。

Boolean

  • 同样是大同小异,但是依然有一个小东东需要说明一下,这个东东就是boolean parseBoolean(String s)方法
  • 这个方法通过查看源码可以看到,当s是"true"时(且不区分大小写),则返回true;否则,其他任何情况下都是返回false。
  • 还有一个小小细节。别的包装类都有常量SIZE和BYTES,但Boolean没有哦~看过我写的《Java基础(一)》的小伙伴肯定都明白是怎么肥四。

Character

  • 大家猜猜我要说什么?没错!同样是大同小异!但是Character有几个方法还是比较常用的,下面列一下:
方法声明功能
static boolean isUpperCase(char ch)判断是否为大写字符
static boolean isLowerCase(char ch)判断是否为小写字符
static boolean isDigit(char ch)判断是否为数字字符
static char toUpperCase(char ch)转换为大写字符
static char toLowerCase(char ch)转换为小写字符

总而言之~

  • 总而言之,手动装箱方式:valueOf()
  • 总而言之,手动拆箱方式:xxxValue()
  • 总而言之,字符串转换为基本数据类型的方式:parseXxx()

Math

  • 位于java.lang.Math。提供了各种和数学相关的方法,例如对数、幂、根、三角函数等。
  • 这个包其实没啥好讲的,因为用不用得好,和编程水平没啥关系,主要取决于数学水平。哈哈哈哈!!!不过还是放几个常用的方法来感受一下吧:
方法声明功能
static int max(int a, int b)返回两个参数中的最大值
static int min(int a, int b)返回两个参数中的最小值
static double pow(double a, double b)返回a的b次幂
static int abs(int a)返回参数的绝对值
static long round(double a)返回参数四舍五入到整数的结果
static double sqrt(double a)返回参数的平方根
static double random()返回0.0到1.0的随机数。不过不推荐用这个方法,因为Random类更加强大。
  • 哦对了,提一句。这个类除了构造方法,其他的所有东西都是static修饰的哦!

字符串相关类

String!!!!!!!!!重点中的重点!!!!!!!!!

基本概念

  • 位于java.lang.String。该类被final修饰。
  • 从jdk1.9开始,该类的底层不使用char[]来存储数据,而是改成byte[]加上编码标记,从而节约了一些空间。
  • String实例描述的字符串内容是常量,无法改变。实际开发中String看起来可以改变,是因为String的引用改变了,而不是同一个String实例中的byte[]变化了。原因如下:
    • String类的byte[]被final修饰,也就是说不能改变其引用。
    • String类没有提供单独修改byte[]中某个下标值的方法。
    • byte[]的长度不能变化。

String的常量池的概念!!!重点!!!

  • 由于String描述的字符串内容不可改变,因此Java虚拟机将首次出现的字符串放入常量池(位于方法区)。若后续出现了相同字符串内容,则直接使用池中已有的字符串对象,从而提高了性能。
由此引申出的String实例化问题
  • String a = "123";这样的代码,只生成了一个String实例,并且这个实例存在于方法区。然后a指向了方法区的实例。
  • String a = new String("123");实际上产生了两个实例。因为行代码翻译一下是这样的:
    • 在方法区中实例化常量字符串对象"123"。
    • 构造方法使用常量池中的"123",在堆区中实例化了字符串对象"123"。
    • a指向堆区中实例化的字符串对象。
由此引申出的编译器常量优化机制
  • String a = "ab" + "cd";这行代码,因为两个都是常量,所以javac在编译的时候,会将其优化为String a = "abcd";
  • 变量+字符串常量就不会有这种优化。
为了验证我又没有说明白,举个栗子折磨一下大家
  • 下面的代码总共创建了几个String对象?分别在哪存储?在哪一行代码创建的?运行结果是什么?
public class StringTest {
	public static void main(String[] args) {
		String str1 = "常量池测试";
		String str2 = "常量池测试";
		String str3 = new String("常量池测试");
		String srt4 = "常量池" + "测试";
		String str5 = "常量池";
		String str6 = str5 + "测试";
		System.out.println(str1 == str2);
		System.out.println(str3 == str2);
		System.out.println(srt4 == str2);
		System.out.println(str6 == str3);
	}
}
  • 其实这个问题是我自己编的,所以没有参考答案,我也不保证我是100%正确的哈哈哈!大家如果有不同意见,随时交流~
  • 创建了5个对象:
    • 常量池中的对象"常量池测试",在str1的那一行创建;
    • 堆区中的对象"常量池测试",在str3的那一行创建。
    • 常量池中的对象"常量池",在str5的那一行创建;
    • str6那一行稍微复杂一点:根据String的变量拼接原理:先是实例化了一个StringBuilder,依次append(str5)和append(“测试”)。最后再toString给str6。而StringBuilder的toString方法,其实是调用了new String(byte[] value)。所以整个过程创建了两个String对象:
      • 常量池中的对象"测试";
      • 堆区中的"常量池测试";
  • 运行结果如下。如果没懂的,再看看我上面说的,就能懂啦~
true
false
true
false

常用方法

基础
方法声明功能
char charAt(int index)返回指定下标位置的字符。
int length()返回字符串字符序列的长度
boolean isEmpty()判断字符串是否为空
int compareTo(String anotherString)比较大小关系。调用字符串的字符依次减参数字符串字符,最后长度相减。
int compareToIgnoreCase(String str)不考虑大小写比较大小关系。
判断型
方法声明功能
boolean contains(CharSequence s)用于判断当前字符串是否包含参数指定的内容
boolean startsWith(String prefix)判断字符串是否以参数字符串开头
boolean startsWith(String prefix, int toffset)从指定位置开始是否以参数字符串开头
boolean endsWith(String suffix)判断字符串是否以参数字符串结尾
boolean equals(Object anObject)用于比较字符串内容是否相等并返回
boolean equalsIgnoreCase(String anotherString)用于比较字符串内容是否相等并返回,不考虑大小写, 如:'A’和’a’是相等
与byte[]、char[]相互转换
方法声明功能
byte[] getBytes()转换为byte数组并返回
char[] toCharArray()转换为char数组并返回
  • 转为String的话,直接使用构造方法即可。
变化型
  • 因为字符串的值不能改变,所以变化型的方法都是通过新实例化对象来实现的。也就是说调用方法前后,原字符串并不会发生变化。
方法声明功能
String toLowerCase()返回字符串的小写形式
String toUpperCase()返回字符串的大写形式
String trim()返回去掉前导和后继空白的字符串
String replace(char oldChar, char newChar)使用newChar替换此字符串中出现的所有oldChar
查找型
方法声明功能
int indexOf(int ch)返回指定字符第一次出现的下标。不存在则返回-1。
int indexOf(int ch, int fromIndex)从fromIndex位置开始,返回指定字符第一次出现的下标。不存在则返回-1。
int indexOf(String str)返回指定字符串第一次出现的下标。不存在则返回-1。
int indexOf(String str, int fromIndex)从fromIndex位置开始,返回指定字符串第一次出现的下标。不存在则返回-1。
int lastIndexOf(int ch)返回指定字符最后一次出现的下标。不存在则返回-1。
int lastIndexOf(int ch, int fromIndex)从fromIndex位置开始,返回指定字符最后一次出现的下标。不存在则返回-1。
int lastIndexOf(String str)返回指定字符串最后一次出现的下标。不存在则返回-1。
int lastIndexOf(String str, int fromIndex)从fromIndex位置开始,返回指定字符串最后一次出现的下标。不存在则返回-1。
  • 注意一下ch的参数类型是int,这是为了兼容不同的字符集,索性用4个字节的int类型来处理。
截取子串
方法声明功能
String substring(int beginIndex, int endIndex)返回字符串中从下标beginIndex(包括)开始到endIndex(不包括)结束的子字符串
String substring(int beginIndex)返回字符串中从下标beginIndex(包括)开始到字符串结尾的子字符串
正则表达式相关
  • 正则表达式是什么玩意儿?其实是一个用于校验字符串格式是否正确的一种表达式。这个我就不在这里赘述了,因为他又难记又麻烦。大家如果用到了,直接面向百度编程即可
方法名称方法
boolean matches(String regex)判断字符串是否匹配参数指定的正则表达式规则
String[] split(String regex)参数regex为正则表达式,以regex所表示的字符串为分隔符,将字符串拆分成字符串数组
String replaceFirst(String regex, String replacement)替换与正则表达式匹配的第一个子字符串
String replaceAll(String regex, String replacement)替换与正则表达式匹配的所有子字符串

可变字符串类(StringBuilder和StringBuffer)

基本概念

  • 位于java.lang.StringBuilder和java.lang.StringBuffer。
  • 用于解决String的内容无法变更的问题。
  • StringBuffer从java 1.0就存在,是线程安全的,所以效率较低。
  • StringBuilder从Java 5.0开始出现,是非线程安全的,所以效率较高。

构造方法——决定初始容量

方法声明功能
StringBuilder()无参构造,初始容量为16
StringBuilder(int capacity)容量为参数指定大小
StringBuilder(String str)根据字符串构造对象,容量为:16+字符串长度
  • 通常来讲,后期使用中,如果容量不够了,扩容逻辑是:2 + 当前容量 * 2。

常用方法

方法声明功能
int capacity()返回当前容量
int length()用于返回字符串的字符的个数
String toString()转换为字符串
StringBuilder insert(int offset, String str)在指定下标插入字符串,并返回自己
StringBuilder append(String str)在末尾追加字符串,并返回自己
StringBuilder deleteCharAt(int index)将下标为index的单个字符删除,并返回自己
StringBuilder delete(int start,int end)删除字符串,并返回自己。左闭右开区间
StringBuilder replace(int start,int end, String str)替换字符串,并返回自己。左闭右开区间
StringBuilder reverse()将字符串反转,并返回自己
查找方法同String查找方法同String
  • 可以看到,很多变化型的方法都会返回自己。这个作用是什么呢?其实是为了让对象能够在一行代码中连续调用。比如str.append("xxx").deleteCharAt(1);
  • 需要注意的是,String类内容变化时,是会生成新的对象,而调用对象本身不会改变。而StringBuilder和StringBuffer,改变的是调用对象自己。

日期相关的类

java 8之前的日期类。过气网红们,了解一下就行~

System类中的currentTimeMills()

  • System类位于java.lang.System
  • 该类有一个方法static long currentTimeMills(),用于返回当前时间与1970年1月1日0时0分0秒之间以毫秒为单位的时间差
  • 这个类以前常用于测试算法的执行时间。

Date类

基本概念
  • 位于java.util.Date
  • 用于描述特定的时间点,也就是年月日时分秒(毫秒)。
常用方法
方法声明功能
Date()使用无参的方式构造对象,也就是当前系统时间。会自动根据时区偏移。
Date(long date)根据参数指定毫秒数构造对象, 参数为距离1970年1月1日0时0分0秒的毫秒数。所以可以用currentTimeMills()。会自动根据时区偏移
long getTime()返回距离1970年1月1日0时0分0秒的毫秒数
void setTime(long time)设置时间为距离基准时间time毫秒的时间点。会自动根据时区偏移
  • 为了说明什么叫根据时区偏移,我就举个栗子吧
public class DateTest {
    public static void main(String[] args){
        System.out.println(new Date());
        System.out.println(new Date(0));
        System.out.println(new Date(System.currentTimeMillis()));
    }
}
  • 上面代码的运行结果如下。可以看到,因为我现在在东8区,所以第二行打印的不是70年0时,而是70年8时。同理,当前时间也是东8区的当前时间。
Fri Nov 06 12:38:00 CST 2020
Thu Jan 01 08:00:00 CST 1970
Fri Nov 06 12:38:00 CST 2020

SimpleDateFormat类

基本概念
  • 位于java.text.SimpleDateFormat。用于实现日期和文本之间的转换
常用方法
方法声明功能
SimpleDateFormat()构造方法,提供了一种默认的格式
SimpleDateFormat(String pattern)根据参数指定的模式来构造对象,模式主要有: y-年、M-月、d-日、h-时、m-分、s-秒。例如"yyyy-MM-dd hh-mm-ss"
final String format(Date date)用于将日期类型转换为文本类型
Date parse(String source)用于将文本类型转换为日期类型
void applyPattern(String pattern)将对象变更为指定的模式
  • 举例如下:
public class SimpleDateFormatTest {
    public static void main(String[] args){
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat();
        System.out.println(sdf.format(date));

        sdf.applyPattern("yyyy-MM-dd HH:mm:ss");
        System.out.println(sdf.format(date));
    }
}
  • 结果如下。注意,MM和mm不能搞反了哈!
2020/11/6 下午12:46
2020-11-06 12:46:30

Calendar类

基本概念
  • 位于java.util.Calendar
  • 用于弥补Date类不能全球化的缺点,取代了Date类中过时的方法。
  • 该类是抽象类。通过getInstance方法可以获取该类的子类的对象。不同的子类针对不同国家的日历系统。
    • getInstance具体返回哪个子类呢?可以通过构造方法传参指定;也可以不传参,系统自动根据电脑所在位置,生成对应的子类。
    • 这种返回值体现多态的用法,也是一种很常用的设计思路,小伙伴们可以自行领会一下~
常用方法
方法声明功能
static Calendar getInstance()用于获取Calendar子类的实例
void set(int year, int month, int date, int hourOfDay, int minute, int second)用于设置年月日时分秒信息。注意,设置的月份需要固定-1
Date getTime()用于将Calendar类型转换为Date类型
void set(int field, int value)设置指定字段的数值。field为Calendar类中的常量,例如YEAR, MONTH等
void add(int field, int amount)向指定字段增加数值
  • 举例如下:
public class CalendarTest {
    public static void main(String[] args){
        Calendar calendar = Calendar.getInstance();
        SimpleDateFormat sdf = new SimpleDateFormat();
        
        calendar.set(2018, 10-1, 9, 1, 1, 1);

        System.out.println(sdf.format(calendar.getTime()));

        calendar.add(Calendar.YEAR, 1);
        System.out.println(sdf.format(calendar.getTime()));
    }
}
  • 结果如下。
2018/10/9 上午1:01
2019/10/9 上午1:01

java 8新出现的日期类。冉冉升起的新星

基本概念

  • 这套新的日期类为什么会出现呢?
    • java 1.0设计的Date类,并没有考虑全球化的问题,其日历系统仅仅是针对美国的。
    • 后来为了全球化java 1.1设计了Calendar类,但是这个类用起来过于繁琐、非线程安全,遭到勤劳勇敢的打工人们的唾弃。
    • 所以一套崭新、强大、简单、支持全球化的日期相关类就应运而生了。
  • 主要成员:java.time包:日期/时间API的基础包。
    • java.time.chrono包:该包提供对不同日历系统的访问。
    • java.time.format包:该包能够格式化和解析日期时间对象。
    • java.time.temporal包:该包包含底层框架和扩展特性。
    • java.time.zone包:该包支持不同时区以及相关规则的类。

LocalDate类、LocalTime类、LocalDateTime类

基本概念
  • 这三个类在使用上基本一致,只是LocalDate只描述日期、LocalTime只描述时间、LocalDateTime描述日期和时间。所以这三个就一起讲了。
  • 这三个类和String类似,主要特征(年月日时间)均为final修饰。所以每次变更时间,实际上是返回了新创建的对象,原对象并未改变。
常用方法
  • 以LocalDateTime类为例:
方法声明功能
static LocalDateTime now()获取系统当前日期时间,自动根据时区偏移。
static LocalDateTime of(int year, int month, int dayOfMonth, int hour, int minute, int second)根据参数指定的年月日时分秒信息来设置日期时间
int getYear()获取年份数值
int getMonthValue()获取月份数值
Month getMonth()获取月份枚举值
int getDayOfMonth()获取日数值
int getHour()获取小时数
int getMinute()获取分钟数
int getSecond()获取秒数
LocalDateTime withYear(int year)设置为指定的年
LocalDateTime withMonth(int month)设置为指定的月
LocalDateTime withDayOfMonth(int dayOfMonth)设置为指定的日
LocalDateTime withHour(int hour)设置为指定的时
LocalDateTime withMinute(int minute)设置为指定的分
LocalDateTime withSecond(int second)设置为指定的秒
LocalDateTime plusYears(long years)加上指定的年
LocalDateTime plusMonths(long months)加上指定的月
LocalDateTime plusDays(long days)加上指定的日
LocalDateTime plusHours(long hours)加上指定的时
LocalDateTime plusMinutes(long minutes)加上指定的分
LocalDateTime plusSeconds(long seconds)加上指定的秒
LocalDateTime minusYears(long years)减去指定的年
LocalDateTime minusMonths(long months)减去指定的月
LocalDateTime minusDays(long days)减去指定的日
LocalDateTime minusHours(long hours)减去指定的时
LocalDateTime minusMinutes(long minutes)减去指定的分
LocalDateTime minusSeconds(long seconds)减去指定的秒

Instant类

基本概念
  • 这个类也是用于描述日期时间的类,区别在于这个类默认创建的是本初子午线的时间,不会根据时区自动偏移。
常用方法
方法声明功能
static Instant now()获取本初子午线当前时间
OffsetDateTime atOffset(ZoneOffset offset)将此瞬间与偏移量组合,以创建偏移的日期时间
static Instant ofEpochMilli(long epochMilli)根据距离1970年1月1日0时0分0秒的毫秒数来构造对象
long toEpochMilli()获取距离1970年1月1日0时0分0秒的毫秒数

DateTimeFormatter类

基本概念
  • 用于格式化和转换新版的日期。使用方法和以前的SimpleDateFormat类似。
常用方法
方法声明功能
static DateTimeFormatter ofPattern(String pattern)根据参数指定的模式来获取对象
String format(TemporalAccessor temporal)将日期时间转换为字符串。TemporalAccessor是一个接口,像LocalDateTime、Instant等都实现了该接口
TemporalAccessor parse(CharSequence text)将字符串转换为日期时间

给新伙伴们一个总的栗子~

public class NewDateSeriesTest {
	public static void main(String[] args) {
		LocalDate localDate = LocalDate.of(2008, 8, 8);
		System.out.println(localDate);

		System.out.println("==========================当前时区时间!!!==========================");
		LocalDateTime localDateTime = LocalDateTime.now();
		System.out.println(localDateTime);
		System.out.println(localDateTime.getDayOfMonth());
		System.out.println(localDateTime.getMonth());
		System.out.println("======================在变了!在变了!====================");
		System.out.println("with:" + localDateTime.withYear(2022));
		System.out.println("我不变:" + localDateTime);
		System.out.println("plus:" + localDateTime.plusYears(2022));
		System.out.println("我就不变!" + localDateTime);
		System.out.println("minus:" + localDateTime.minusDays(2));
		System.out.println("我偏不变~" + localDateTime);

		System.out.println("====================来看一看instant!=====================");
		Instant instant = Instant.now();
		System.out.println("本初子午线时间:" + instant);
		System.out.println("东八区时间:" + instant.atOffset(ZoneOffset.ofHours(8)));

		System.out.println("===================保持队形!==================");
		DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss");
		System.out.println(formatter.format(localDateTime));
	}
}
  • 运行结果如下。比较简单,就不解释了。
2008-08-08
==========================当前时区时间!!!==========================
2020-11-07T17:04:52.634306100
7
NOVEMBER
======================在变了!在变了!====================
with:2022-11-07T17:04:52.634306100
我不变:2020-11-07T17:04:52.634306100
plus:4042-11-07T17:04:52.634306100
我就不变!2020-11-07T17:04:52.634306100
minus:2020-11-05T17:04:52.634306100
我偏不变~2020-11-07T17:04:52.634306100
====================来看一看instant!=====================
本初子午线时间:2020-11-07T09:04:52.697385200Z
东八区时间:2020-11-07T17:04:52.697385200+08:00
===================保持队形!==================
2020-11-07 05:04:52

java.math包中常用的类

BigDecimal

基本概念

  • 位于java.math.BigDecimal
  • 用于弥补float和double类型在运算时的误差问题。比如0.1+0.2,如果是double相加,会有很小的误差,但是用BigDecimal就不会有任何误差。
  • BigDecimal的运算逻辑比较复杂,所以性能开销会比基本运算符大很多。慎用!

常用方法

方法声明功能
BigDecimal(String val)根据参数指定的字符串来构造对象
BigDecimal add(BigDecimal augend)加法运算
BigDecimal subtract(BigDecimal subtrahend)减法运算
BigDecimal multiply(BigDecimal multiplicand)乘法运算
BigDecimal divide(BigDecimal divisor)除法运算

要点

除不尽就出问题!
  • 猜猜下面代码的结果:
public class BigDecimalTest {
    public static void main(String[] args) {
        BigDecimal a = new BigDecimal("0.1");
        BigDecimal b = new BigDecimal("0.7");
        double c = 0.1;
        double d = 0.7;
        System.out.println(c / d);
        System.out.println(a.divide(b));
    }
}
  • 结果如下。可以看到double可以算无限小数,但是BigDecimal默认不能算,因为他觉得不!精!确!
0.14285714285714288
Exception in thread "main" java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.
	at java.base/java.math.BigDecimal.divide(BigDecimal.java:1723)
	at com.UsefulNativeClass.BigDecimalTest.main(BigDecimalTest.java:14)
  • 那我想让BigDecimal进行四舍五入计算怎么办呢?就需要用到math包下面的另外一个类——RoundingMode(java 9之后就需要用这个枚举类了,之前是可以用BigDecimal里面的常量的)。直接举个例子吧~
public class BigDecimalTest {
    public static void main(String[] args) {
        BigDecimal a = new BigDecimal("0.11");
        BigDecimal b = new BigDecimal("0.7111");
        System.out.println(a.divide(b, RoundingMode.HALF_UP));
    }
}
  • 运行结果是0.15。RoundingMode这个枚举类里面还有很多别的舍入模式,感兴趣的老铁们可以自己去看看。
  • 需要注意的是,这个舍入模式保留的小数点位数,取决于被除数,也就是例子中的a。
不要被double骗了
  • 其实BigDecimal的构造方法很多,例如还可以通过double类型来构造。
  • 那么问题来了~小伙伴们觉得下面的代码执行结果是什么呢?
public class BigDecimalTest {
    public static void main(String[] args) {
        BigDecimalTest test = new BigDecimalTest();
        test.doubleTest();
    }

    private void doubleTest(){
        double d = 1.2;
        BigDecimal a = new BigDecimal(d);
        System.out.println(a);
    }
}
  • 很多小伙伴感觉太简单了:1.2!真的是么?结果如下。小伙伴们恍然大悟:哦!!!!虽然d = 1.2,但是d的值却不是精确的1.2,所以构造方法的入参,也并不是1.2,而是一个无限接近的数字。所以,尽量不要使用double来构造BigDecimal哟~
1.1999999999999999555910790149937383830547332763671875

BigInteger

基本概念

  • 位于java.math.BigInteger。
  • 这个类就很浅显了,作用是用来处理long都无法处理的超超超超超超超超超超超超超超超级大整数的运算。
  • 因为是整数运算嘛,所以提供了取余运算,别的真没啥好说的。

常用方法

方法声明功能
BigInteger(String val)根据参数指定的字符串来构造对象
BigInteger add(BigInteger val)加法运算
BigInteger subtract(BigInteger val)减法运算
BigInteger multiply(BigInteger val)乘法运算
BigInteger divide(BigInteger val)除法运算
BigInteger remainder(BigInteger val)取余运算
BigInteger[] divideAndRemainder(BigInteger val)同时进行取商和取余运算。返回值中,下标为0的是商,1是余。
  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值