19-常用类
包装类
包装类与基本数据转换
package org.example;
/**
* @author adekang
* @version 1.0
* @date 2023/8/19
*/
public class Integer01 {
public static void main(String[] args) {
int n1 = 100;
Integer integer1 = n1;
}
}
包装类与String转换
package org.example;
/**
* @author adekang
* @version 1.0
* @date 2023/8/19
*/
public class Integer01 {
public static void main(String[] args) {
Integer i = 100;
// 方式一
String str1 = i + "";
// 方式二
String str2 = i.toString();
String str3 = String.valueOf(i);
// String - > Integer
String str4 = "123456";
Integer i2 = Integer.parseInt(str4);
}
}
常用方法
package org.example;
/**
* @author adekang
* @version 1.0
*/
public class WrapperMethod {
public static void main(String[] args) {
System.out.println(Integer.MIN_VALUE); //返回最小值
System.out.println(Integer.MAX_VALUE);//返回最大值
System.out.println(Character.isDigit('a'));//判断是不是数字
System.out.println(Character.isLetter('a'));//判断是不是字母
System.out.println(Character.isUpperCase('a'));//判断是不是大写
System.out.println(Character.isLowerCase('a'));//判断是不是小写
System.out.println(Character.isWhitespace('a'));//判断是不是空格
System.out.println(Character.toUpperCase('a'));//转成大写
System.out.println(Character.toLowerCase('A'));//转成小写
}
}
面试题
package org.example;
/**
* @author adekang
* @version 1.0
* @date 2023/8/19
*/
public class Integer01 {
public static void main(String[] args) {
//
// Integer 在 -128~127 是从数组中取值 大于这个范围则是 返回一个包装对象
Integer i1 = 128;
Integer i3 = 128;
System.out.println(i1 == i3);
// 只要有基本数据类型就判断是否值相同
int i2 = 128;
Integer i4 = 128;
System.out.println(i2 == i4);
}
}
String
- String对象用于保存字符串,也就是一组字符序列
- 字符串常量对象是用双引号括起的字符序列。
- 字符串的字符使用Unicode字符编码,一个字符(不区分字母还是汉字)占两个字节。
- String类较常用构造器(其它看手册):
String类实现了
接口SeriaLizabLe
[String可以串行化:可以在网络传输] 接口Comparable
[String 对象可以比较大小]
String是final 类,不能被其他的类继承 String有属性private final char vaLue[]; 用于存放字符串内容 定要注意: value 是一个finaL类型, 不可以修改
创建
package org.example;
/**
* @author adekang
* @version 1.0
* @date 2023/8/19
*/
public class Integer01 {
public static void main(String[] args) {
String s = "ade";
String s2 = new String("ade");
}
}
方式一:先从常量池查看是否有"ade"
数据空间,如果有,直接指向;如果没有则重新创建,然后指向。s最终指向的是常量池的空间地址
方式二:先在堆中创建空间,里面维护了value属性,指向常量池的ade
空间。如果常量池没有"ade"
,重新创建,如果有,直接通过value指向。最终指向的是堆中的空间地址。
package org.example;
/**
* @author adekang
* @version 1.0
* @date 2023/8/19
*/
public class Integer01 {
public static void main(String[] args) {
String s = "ade";
String d = "ade";
System.out.println(s == d); // 所以会相等
String s2 = new String("ade");
String s3 = new String("ade");
System.out.println(s2 == s3);
}
}
// true
// false
在 Java 中,String.intern()
方法用于将字符串对象添加到字符串常量池中,并返回该字符串在常量池中的引用。如果字符串常量池已经包含了等于该字符串的字符串,则返回常量池中对应字符串的引用。
使用 String.intern()
方法的主要目的是为了节省内存空间和提高字符串的比较效率。当我们多次使用相同的字符串时,通过将字符串对象 intern 后,可以避免创建多个相同内容的字符串对象,而是直接引用已经存在的字符串对象。
下面是一个示例代码:
javaCopy Code
String str1 = new String("Hello");// 创建一个新的字符串对象String str2 = "Hello";// 直接引用常量池中的字符串对象// 使用 intern 方法将 str1 添加到常量池,并返回常量池中的引用String str3 = str1.intern();
System.out.println(str1 == str2);// 输出 false,因为 str1 和 str2 引用的是不同的对象
System.out.println(str2 == str3);// 输出 true,因为 str2 和 str3 引用的是同一个对象
需要注意的是,String.intern()
方法在JDK 6
之前的版本中,会把首次遇到的字符串复制到永久代的字符串常量池中。而在 JDK 7
及以后的版本中,字符串常量池被移到了堆中,因此这种复制行为不会发生。
**String.intern()
方法最终返回的是常量池的地址(对象)**
特性
- String是一个final类,代表不可变的字符序列
- 字符串是不可变的。一个字符串对象一旦被分配, 其内容是不可变的.
package org.example;
/**
* @author adekang
* @version 1.0
* @date 2023/8/19
*/
public class Integer01 {
public static void main(String[] args) {
String a = "abc";
String b = "def";
String c = a + b;
String d = "abc" + "def";
System.out.println(c == "abcdef"); // 堆中相加 false
System.out.println(d == "abcdef"); // 常量池中相加 true
}
}
底层是
StringBuilder sb = new StringBuilder();
sb.append(a);
sb.append(b);
sb
是在堆中,并且append
是在原来字符串的基础上追加的. 重要规则:
String c1 = "ab" + "cd";
常量相加,看的是池。 String c1 = a + b;
变量相加,是在堆中
String类是保存字符串常量的。每次更新都需要重新开辟空间,效率较低,因此java设计者还提供了StringBuilder
和StringBuffer
来增强String的功能,并提高效率。
常用方法
equals //区分大小写,判断内容是否相等
equalslgnoreCase //忽略大小写的判断内容是否相等
length //获取字符的个数,字符串的长度
indexOf //获取字符在字符串中第1次出现的索引,索引从0开始,如果找不到,返回-1
lastlndexOf //获取字符在字符串中最后1次出现的索引,索引从0开始,如找不到,返回-1
substring //截取指定范围的子串
trim //去前后空格
charAt // 获取某索引处的字符,注意不能使用Str[index]这种方式.
toUpperCase // 转换成大写
toLowerCase // 转换成小写
concat // 拼接字符串
replace // 替换字符串中的字符
split // 分割字符串, 对于某些分割字符,我们需要 转义比如 | \\等
toCharArray // 转换成字符数组
compareTo //比较两个字符串的大小,如果前者大,
// 则返回正数,后者大,则返回负数,如果相等,返回0
// (1) 如果长度相同,并且每个字符也相同,就返回 0
// (2) 如果长度相同或者不相同,但是在进行比较时,可以区分大小
// 就返回 if (c1 != c2) {
// return c1 - c2;
// }
// (3) 如果前面的部分都相同,就返回 str1.len - str2.len
format // 格式字符串
//1. %s , %d , %.2f %c 称为占位符
//2. 这些占位符由后面变量来替换
//3. %s 表示后面由 字符串来替换
//4. %d 是整数来替换
//5. %.2f 表示使用小数来替换,替换后,只会保留小数点两位, 并且进行四舍五入的处理
//6. %c 使用char 类型来替换
String name = "john";
int age = 10;
double score = 56.857;
char gender = '男';
//将所有的信息都拼接在一个字符串.
String info =
"我的姓名是" + name + "年龄是" + age + ",成绩是" + score + "性别是" + gender + "。希望大家喜欢我!";
@startuml
!theme plain
top to bottom direction
skinparam linetype ortho
interface CharSequence << interface >> {
+ subSequence(int, int): CharSequence
+ length(): int
+ charAt(int): char
+ compare(CharSequence, CharSequence): int
+ codePoints(): IntStream
+ isEmpty(): boolean
+ toString(): String
+ chars(): IntStream
}
interface Comparable<T> << interface >> {
+ compareTo(T): int
}
interface Constable << interface >> {
+ describeConstable(): Optional<ConstantDesc>
}
interface ConstantDesc << interface >> {
+ resolveConstantDesc(Lookup): Object
}
interface Serializable << interface >>
class String {
- throwMalformed(int, int): void
- throwUnmappable(byte[]): void
~ join(String, String, String, String[], int): String
+ stripLeading(): String
+ regionMatches(int, String, int, int): boolean
- throwMalformed(byte[]): void
+ equals(Object?): boolean
- decode3(int, int, int): char
+ formatted(Object[]?): String
+ stripIndent(): String
+ contains(CharSequence): boolean
- decode4(int, int, int, int): int
+ toUpperCase(): String
+ toString(): String
~ checkBoundsBeginEnd(int, int, int): void
- isASCII(byte[]): boolean
+ translateEscapes(): String
- encodeUTF8(byte, byte[], boolean): byte[]
+ getChars(int, int, char[], int): void
+ codePoints(): IntStream
+ join(CharSequence, Iterable<CharSequence>): String
+ matches(String): boolean
+ join(CharSequence, CharSequence[]): String
- nonSyncContentEquals(AbstractStringBuilder): boolean
+ hashCode(): int
- encodeASCII(byte, byte[]): byte[]
- rangeCheck(char[], int, int): Void
~ checkOffset(int, int): void
- isMalformed4(int, int, int): boolean
- isNotContinuation(int): boolean
- isMalformed3_2(int, int): boolean
~ getBytesUTF8NoRepl(String): byte[]
+ contentEquals(CharSequence): boolean
+ compareTo(String): int
+ indexOf(String, int): int
~ checkIndex(int, int): void
~ indexOf(byte[], byte, int, String, int): int
- lookupCharset(String): Charset
+ valueOf(float): String
+ getBytes(int, int, byte[], int): void
+ trim(): String
+ replace(char, char): String
- indexOfNonWhitespace(): int
+ replace(CharSequence, CharSequence): String
- scale(int, float): int
- malformed3(byte[], int): int
+ transform(Function<String, R>): R
+ lastIndexOf(int, int): int
+ replaceAll(String, String): String
+ valueOf(Object?): String
- encode(Charset, byte, byte[]): byte[]
+ resolveConstantDesc(Lookup?): String
+ split(String): String[]
+ codePointAt(int): int
~ coder(): byte
- encodeUTF8_UTF16(byte[], boolean): byte[]
~ valueOfCodePoint(int): String
- throwUnmappable(int): void
+ length(): int
- isMalformed3(int, int, int): boolean
+ getBytes(String): byte[]
+ contentEquals(StringBuffer): boolean
+ describeConstable(): Optional<String>
- encode8859_1(byte, byte[]): byte[]
+ valueOf(boolean): String
- isMalformed4_3(int): boolean
~ newStringUTF8NoRepl(byte[], int, int): String
- safeTrim(byte[], int, boolean): byte[]
- newStringNoRepl1(byte[], Charset): String
+ toUpperCase(Locale): String
+ valueOf(int): String
+ toLowerCase(): String
+ valueOf(char): String
+ toCharArray(): char[]
- getBytesNoRepl1(String, Charset): byte[]
+ chars(): IntStream
- malformed4(byte[], int): int
+ valueOf(char[], int, int): String
+ codePointCount(int, int): int
+ indexOf(int): int
+ startsWith(String, int): boolean
~ getBytes(byte[], int, byte): void
+ codePointBefore(int): int
+ toLowerCase(Locale): String
+ stripTrailing(): String
+ indexOf(String): int
+ startsWith(String): boolean
+ offsetByCodePoints(int, int): int
- lastIndexOfNonWhitespace(): int
+ format(Locale, String, Object[]?): String
+ valueOf(long): String
+ lastIndexOf(String): int
- decodeWithDecoder(CharsetDecoder, char[], byte[], int, int): int
+ intern(): String
~ checkBoundsOffCount(int, int, int): void
~ lastIndexOf(byte[], byte, int, String, int): int
+ isEmpty(): boolean
+ valueOf(double): String
~ decodeASCII(byte[], int, char[], int, int): int
+ charAt(int): char
~ getBytes(byte[], int, int, byte, int): void
+ concat(String): String
+ regionMatches(boolean, int, String, int, int): boolean
+ valueOf(char[]): String
+ lines(): Stream<String>
- outdent(List<String>): int
+ copyValueOf(char[], int, int): String
+ repeat(int): String
+ equalsIgnoreCase(String?): boolean
+ substring(int, int): String
+ indent(int): String
+ copyValueOf(char[]): String
~ isLatin1(): boolean
- encode8859_1(byte, byte[], boolean): byte[]
+ lastIndexOf(String, int): int
- isMalformed4_2(int, int): boolean
+ endsWith(String): boolean
~ newStringNoRepl(byte[], Charset): String
+ isBlank(): boolean
- decodeUTF8_UTF16(byte[], int, int, byte[], int, boolean): int
+ split(String, int): String[]
+ getBytes(): byte[]
+ lastIndexOf(int): int
~ value(): byte[]
+ subSequence(int, int): CharSequence
+ compareToIgnoreCase(String): int
- decode2(int, int): char
+ indexOf(int, int): int
- encodeWithEncoder(Charset, byte, byte[], boolean): byte[]
+ substring(int): String
~ getBytesNoRepl(String, Charset): byte[]
+ strip(): String
+ getBytes(Charset): byte[]
+ format(String, Object[]?): String
+ replaceFirst(String, String): String
}
String -[#008200,dashed]-^ CharSequence
String -[#008200,dashed]-^ Comparable
String -[#008200,dashed]-^ Constable
String -[#008200,dashed]-^ ConstantDesc
String -[#008200,dashed]-^ Serializable
@enduml
StringBuffer
类
java.lang.StringBuffer
代表可变的字符序列,可以对字符串内容进行增删。很多方法与String相同,但StringBuffer
是可变长度的。
StringBuffer
是一个容器。
String VS StringBuffer
- String保存的是字符串常量,里面的值不能更改,每次String类的更新实际上就是更改地址,效率较低 //private final char value[];
StringBuffer
保存的是字符串变量,里面的值可以更改,每次StringBuffer
的更新实际上可以更新内容,不用每次更新地址,效率较高 //char[] value; //这个放在堆.
StringBuffer
与 String 相互转换
package org.example.StringBuffer_;
public class StringBuffer01 {
public static void main(String[] args) {
String str = "hello";
// 方式一 通过构造器 返回的是一个StringBuffer对象,对str本身没有影响
StringBuffer stringBuffer = new StringBuffer(str);
// 方式二 通过append方法 返回的是一个StringBuffer对象,对str本身没有影响
StringBuffer stringBuffer2 = new StringBuffer();
stringBuffer2.append(str);
// 方式三 通过toString方法 返回的是一个String对象
StringBuffer stringBuffer3 = new StringBuffer("hello");
String string = stringBuffer3.toString();
String string2 = new String(string);
//
}
}
StringBuffer
常见类
StringBuffer是Java中一个用于操作字符串的类。StringBuffer的常见用法有:
- 追加字符串
可以使用StringBuffer的append()方法追加任意类型的数据到字符串末尾。
例如:
codeStringBuffer sb = new StringBuffer();
sb.append("Hello ");
sb.append("World");
System.out.println(sb.toString());// 输出Hello World
- 插入字符串
可以使用StringBuffer的insert()方法在指定索引位置插入字符串。
例如:
codeStringBuffer sb = new StringBuffer("Hello");
sb.insert(5," Java");
System.out.println(sb.toString());// 输出Hello Java
- 替换字符串
可以使用StringBuffer的replace()方法替换指定区间内的字符串。
例如:
codeStringBuffer sb = new StringBuffer("Hello");
sb.replace(0,5,"Hi");
System.out.println(sb.toString());// 输出Hi
- 删除字符串
可以使用StringBuffer的delete()方法删除指定区间内的字符串。
例如:
codeStringBuffer sb = new StringBuffer("Hello");
sb.delete(0,3);
System.out.println(sb.toString());// 输出lo
- 反转字符串
可以使用StringBuffer的reverse()方法反转字符串。
例如:
codeStringBuffer sb = new StringBuffer("Hello");
sb.reverse();
System.out.println(sb.toString());// 输出olleH
这些是StringBuffer的一些常见用法。相比String,StringBuffer可以高效地对字符串进行修改操作。
StringBuilder
1)一个可变的字符序列。此类提供一个与StringBuffer兼容的API,但不保证同步(StringBuilder不是线程安全)。该类被设计用作StringBuffer的一个简易替换,用在字符串缓冲区被单个线程使用的时候。如果可能,建议优先采用该类,因为在大多数实现中,它比StringBuffer要快。
2)在StringBuilder上的主要操作是append和insert方法,可重载这些方法, 以接受任意类型的数据。
StringBuilder继承AbstractStringBuilder 类
实现了Serializable , 说明StringBuilder对象是可以串行化(对象可以网络传输,可以保存到文件)
StringBuilder是final类,不能被继承
StringBuilder对象字符序列仍然是存放在其父类AbstractStringBuilder的 char[] vaLue ;
因此,
StringBuilder的方法,没有做互斥的处理,即没有synchronized关键字,因此在单线程的情况下使用StringBuilder
String、StringBuffer 和StringBuilder的比较
StringBuilder和StringBuffer非常类似,均代表可变的字符序列,而且方法也一样 String: 不可变字符序列,效率低,但是复用率高。 StringBuffer:可变字符序列、效率较高(增删)、线程安全,看源码 StringBuilder:可变字符序列、效率最高、线程不安全 String使用注意说明: string s=" a"; //创建了一个字符串 s+="b"; //实际上原来的"a"字符串对象已经丢弃了,现在又产生了一个字符串s+"b" (也就是" ab").如果多次执行这些改变串内容的操作,会导致大量副本字符串对象存留在内存中,降低效率。如果这样的操作放到循环中,会极大影响程序的性能=>结论:如果我们对String做大量修改,不要使用String
使用的原则,结论:
1.如果字符串存在大量的修改操作,一般使用StringBuffer
或StringBuilder
2.如果字符串存在大量的修改操作,并在单线程的情况,使用StringBuilder
3.如果字符串存在大量的修改操作,并在多线程的情况,使用StringBuffer
4.如果我们字符串很少修改,被多个对象引用,使用String, 比如配置信息等
Math类
Math类包含用于执行基本数学运算的方法,如初等指数、对数、平方根和三角函数。
Java Math类是java.lang包下提供各种数学运算功能的一个类。Math类中的常用方法有:
- abs():求绝对值
int absValue = Math.abs(-10); // absValue为10
- ceil():向上取整
double ceilValue = Math.ceil(10.1); // ceilValue 为11.0
- floor():向下取整
double floorValue = Math.floor(10.9); // floorValue 为10.0
- round():四舍五入
long roundValue = Math.round(10.4); // roundValue 为10
- max():求两值中的最大值
int maxValue = Math.max(100, 200); // maxValue 为200
- min():求两值中的最小值
int minValue = Math.min(100, 200); // minValue 为100
- pow():求幂
double powValue = Math.pow(2, 3); // powValue 为8.0
- sqrt(): 求平方根
double sqrtValue = Math.sqrt(100); // sqrtValue 为10.0
- random():产生随机数
double randomValue = Math.random(); // randomValue 为0.0到1.0之间的随机数
这些是Java Math类中常用的一些静态方法。通过Math可以方便地进行数学计算。
Arrays
Arrays里面包含了一系列静态方法,用于管理或操作数组(比如排序和搜索)
这里是一些Arrays类中常用的方法:
- toString(int[] a) - 将数组转换为字符串
- sort(int[] a) - 对数组进行排序
- binarySearch(int[] a, int key) - 对排序后的数组进行二分查找
- copyOf(int[] a, int newLength) - 复制数组
- fill(int[] a, int val) - 用指定值填充数组
- equals(int[] a, int[] b) - 判断两个数组是否相等
- asList(int[] a) - 将数组转换为List
- copyOfRange(int[] a, int from, int to) - 复制数组的某个范围
- deepToString(Object[] a) - 将多维数组转换为字符串
- deepEquals(Object[] a1, Object[] a2) - 判断多维数组是否相等
- parallelSort(int[] a) - 对数组进行并行排序
- setAll(int[] a, IntFunction generator) - 使用函数设置数组值
- parallelPrefix(int[] a, BinaryOperator op) - 对数组进行并行前缀计算
- spliterator(int[] a) - 获取数组的spliterator
这些是Arrays类中非常有用的方法,可以方便我们操作数组。
自定义排序
package org.example;
import java.util.Arrays;
import java.util.Comparator;
public class ArraysSortCustom {
public static void main(String[] args) {
Integer[] integer = { 1, 20, 50, 30 };
bubble(integer, 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(integer));
}
public static void bubble(Integer[] integer) {
for (int i = 0; i < integer.length - 1; i++) {
for (int j = 0; j < integer.length - 1 - i; j++) {
if (integer[j] > integer[j + 1]) {
int temp = integer[j];
integer[j] = integer[j + 1];
integer[j + 1] = temp;
}
}
}
}
public static void bubble(Integer[] integer, Comparator c) {
for (int i = 0; i < integer.length - 1; i++) {
for (int j = 0; j < integer.length - 1 - i; j++) {
if (c.compare(integer[j], integer[j + 1]) > 0) {
int temp = integer[j];
integer[j] = integer[j + 1];
integer[j + 1] = temp;
}
}
}
}
}
案例
package org.example;
import java.util.Arrays;
import java.util.Comparator;
public class ArraysSortCustom {
public static void main(String[] args) {
Book[] books = new Book[4];
books[0] = new Book("Java", 10);
books[1] = new Book("Python", 60);
books[2] = new Book("C++", 5);
books[3] = new Book("C", 40);
// Arrays.sort(books, (o1, o2) -> o2.getPrice() - o1.getPrice());
Arrays.sort(books, new Comparator() {
@Override
public int compare(Object o1, Object o2) {
Book book1 = (Book) o1;
Book book2 = (Book) o2;
return book2.getPrice() - book1.getPrice();
}
});
System.out.println(Arrays.toString(books));
}
}
class Book {
private String name;
private Integer price;
public Book(String name, Integer price) {
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getPrice() {
return price;
}
public void setPrice(Integer price) {
this.price = price;
}
@Override
public String toString() {
return "Book [name=" + name + ", price=" + price + "]";
}
}
System
这里有一些Java System类常用的方法:
- currentTimeMillis() - 返回当前时间(以毫秒为单位)
- arraycopy() - 复制数组的一部分到另一个数组
- gc() - 运行垃圾回收器
- exit() - 退出当前运行的Java虚拟机
- getProperty() - 获取系统属性的值
- setProperty() - 设置系统属性的值
- getenv() - 获取环境变量的值
- nanoTime() - 返回高分辨时间(纳秒)
- console() - 返回与当前Java虚拟机相关的控制台
- currentTimeMillis()与nanoTime()常用于计时和基准测试。
- getProperty()和setProperty()用于获取和设置系统属性。
- exit()可以直接关闭虚拟机。
- gc()可以手动提醒JVM进行垃圾回收。
- console()可以获取控制台输入输出流。
System类中还有一些其他常用的方法,比如load(), loadLibrary()等。这些就是Java System类中比较常用的一些静态方法。
BigInteger & BigDecimal
BigInteger适合保存比较大的整型 BigDecimal适合保存精度更高的浮点型(小数)
BigInteger 在 Java 中主要用于大整数的运算,可以表示任意大小的整数,适用于需要大数值精度的场景。
BigInteger 的常见用法包括:
- 创建 BigInteger 对象
可以直接通过构造函数创建:
BigInteger bi1 = new BigInteger("123456789");
也可以使用静态的 valueOf()
方法创建:
BigInteger bi2 = BigInteger.valueOf(123456789);
- 进行算术运算
BigInteger 支持常见的加、减、乘、除等算术运算,通过调用实例方法完成:
BigInteger sum = bi1.add(bi2);
BigInteger diff = bi1.subtract(bi2);
- 比较大小
可以使用 compareTo()
方法比较两个 BigInteger 的大小:
int cmp = bi1.compareTo(bi2);
- 转换为其他数值类型
可以使用 intValue()
、longValue()
等方法转换为基本类型:
int intVal = bi1.intValue();
long longVal = bi1.longValue();
- 格式化输出
可以使用 toString()
方法格式化为字符串输出:
String str = bi1.toString();
需要注意 BigInteger 是不可变对象,运算不会改变原对象的值,而是产生新的对象。
BigInteger 可以表示任意大小的整数,适合高精度运算场景。
package org.example.BigInterger;
import java.math.BigInteger;
public class BigInteger_ {
public static void main(String[] args) {
BigInteger bi = new BigInteger("12345678901234567890");
BigInteger b = new BigInteger("9");
BigInteger a = bi.add(b);
System.out.println(a);
}
}
BigDecimal 在 Java 中主要用于高精度计算,适用于需要准确计算和避免浮点数误差的场景。
BigDecimal 的常见用法包括:
- 创建 BigDecimal 对象
可以通过 BigDecimal 构造函数创建,通常需要指定一个字符串或 double 值:
BigDecimal bd1 = new BigDecimal("123.456");
BigDecimal bd2 = new BigDecimal(123.456);
- 进行算术运算
通过 BigDecimal 的 add()
、subtract()
、multiply()
、divide()
等方法进行各种运算。运算结果也是 BigDecimal 对象。
BigDecimal result = bd1.add(bd2);
- 比较大小
可以使用 compareTo()
方法比较两个 BigDecimal 的大小。
int cmp = bd1.compareTo(bd2);
- 四舍五入
可以使用 setScale()
方法设置小数位数,多余的小数位会自动四舍五入。
BigDecimal bd3 = bd1.setScale(2, RoundingMode.HALF_UP);
- 格式化输出
可以使用 toString()
方法格式化输出。
String str = bd3.toString(); // "123.46"
需要注意 BigDecimal 对象是不可变的,大多数方法都会返回一个新的 BigDecimal 对象,不会修改原对象。
日期类
Date
Date:精确到毫秒,代表特定的瞬间 SimpleDateFormat:格式和解析日期的类 SimpleDateFormat格式化和解析日期的具体类。它允许进行格式化(日期->文本)、解析(文本->日期)和规范化.
Date 类在 Java 中用于表示日期和时间,但有一些特点需要注意:
- Date 表示的时间是自 1970年1月1日 00:00:00 GMT 开始经过的毫秒数。
- Date 中的年份是从 1900 开始的,月份从 0 开始计数。
- Date 类存在线程安全问题,是非线程安全的。
- Date 的大多数方法已经废弃,不推荐使用。
Date 的常见用法:
- 获取当前时间系统时间:
Date date = new Date();
- 通过指定毫秒数创建 Date:
Date date2 = new Date(1646870400000L);
- 获取日期信息:
int year = date.getYear();
int month = date.getMonth();
int day = date.getDate();
- 比较日期先后:
Date date1 = new Date();
Date date2 = new Date(date1.getTime() + 86400);
if(date1.before(date2)) {
// ...
}
- 格式化日期
可以通过 SimpleDateFormat 格式化和解析日期。
package org.example.Date;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Date01 {
public static void main(String[] args) {
Date d = new Date();
System.out.println(d);
// 格式转换
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String format = simpleDateFormat.format(d);
System.out.println(format);
}
}
Date 类存在缺陷,在 JDK 1.1 引入了 Calendar 和 DateFormat 类,在 JDK 1.8 后推荐使用 LocalDate、LocalTime、LocalDateTime 等新 API。
Calendar
Calendar 类在 Java 中主要用来完成日期和时间的运算和格式化,相比于 Date 类有几个特点:
- Calendar 表示的时间精确到毫秒,可以用于更复杂的日期和时间计算。
- Calendar 是抽象类,通常使用它的子类 GregorianCalendar 来创建实例。
- Calendar 是线程安全的,可以被多个线程共享。
- Calendar 支持不同时区。
Calendar 的常见用法包括:
- 创建 Calendar 实例,默认是当前日期时间:
Calendar c = Calendar.getInstance();
- 获取日期时间信息:
int year = c.get(Calendar.YEAR);
int month = c.get(Calendar.MONTH) + 1; //月份从0开始
int day = c.get(Calendar.DAY_OF_MONTH);
- 修改日期时间信息:
c.set(Calendar.YEAR, 2022);
c.set(Calendar.MONTH, 11); //11表示12月
- 进行日期时间计算:
//日期+1天
c.add(Calendar.DAY_OF_MONTH, 1);
//日期-3个月
c.add(Calendar.MONTH, -3);
- 比较日期先后顺序:
Calendar c1 = Calendar.getInstance();
Calendar c2 = Calendar.getInstance();
if (c1.before(c2)) {
// ...
}
- 格式化日期时间:
可以使用 SimpleDateFormat 格式化 Calendar 对象。
Calendar 克服了 Date 的很多缺点,但在 JDK 1.8 后也推荐使用更简洁的 LocalDateTime。
Calendar类之后被弃用了。而Calendar也存在问题是:
1)可变性:像日期和时间这样的类应该是不可变的。
2)偏移性: Date中的年份是从1900开始的, 而月份都从0开始。
3)格式化:格式化只对Date有用,Calendar则不行。
4)此外,它们也不是线程安全的;不能处理闰秒等(每隔2天,多出1s)
LocalDateTime
LocalDateTime 是 Java 8 中加入的新日期时间 API,与旧的 Date 和 Calendar 相比有以下优点:
- 不可变对象,线程安全。
- 语义更清晰,方法用法更简单。
- 不包含时区信息,可以避免时区处理的复杂性。
- 提供更丰富的方法来操作日期时间。
- 日期时间计算更方便、安全。
LocalDateTime 的常见用法:
- 获取当前日期时间:
LocalDateTime now = LocalDateTime.now();
- 从指定日期时间创建:
LocalDateTime dt = LocalDateTime.of(2022, 3, 8, 15, 20, 30);
- 获取详细信息:
int year = dt.getYear();
Month month = dt.getMonth();
int day = dt.getDayOfMonth();
- 日期时间运算:
LocalDateTime dt2 = dt.plusDays(3); //3天后
LocalDateTime dt3 = dt.minusWeeks(2); //2周前
- 比较日期先后:
if(dt1.isBefore(dt2)) {
// ...
}
- 格式化:
String strDt = dt.format(DateTimeFormatter.ISO_DATE_TIME);
LocalDateTime 极大地简化了日期时间的操作,是先进的日期时间 API。
DateTimeFormatter 是 Java 8 中日期时间格式化的工具类。它可以用来格式化和解析 LocalDateTime、LocalDate 等新日期时间 API。
DateTimeFormatter 的使用包括:
- 获取系统默认格式化器:
DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM);
- 获取预定义的格式化器:
DateTimeFormatter formatter = DateTimeFormatter.BASIC_ISO_DATE;
- 自定义格式化器:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
- 格式化日期时间:
LocalDateTime dt = LocalDateTime.now();
String str = dt.format(formatter);
- 解析字符串为日期时间:
LocalDateTime dt = LocalDateTime.parse(str, formatter);
DateTimeFormatter 预定义了多种常用的格式化器,也可以自定义格式化模式。
相比 SimpleDateFormat,DateTimeFormatter 是线程安全的,可以明确指定时区,而且与新日期时间 API 整合更好。