一、数学计算相关
1.1 Math类
java.lang包
- double Math.PI:圆周率
- double Math.random():返回[0,1 ) 范围的小数
- double Math.sqrt(参数x):返回x的平方根
- 基本数据类型 Math.abs(参数x):返回x的绝对值,这个方法有重载形式,支持多种参数类型。
- double Math.ceil(x):对x向上取整
- double Math.floor(x):对x向下取整
- double Math.round(x):类似于四舍五入(值先+0.5再向下取整)
- double Math.pow(x, y):求x的y次方,x,y可以是整数可以是小数
- double Math.max(x,y):求x,y的最大值
- double Math.min(x,y):求x,y的最小值
1.2 BigInteger和BigDecimal类
java.math包
- BigInteger:用于表示任意大小的整数,它不受int,long这个范围的限制。
- BigDecimal:用于表示任意精度的小数,它不受float,double这个范围和精度的限制。
问:int,Integer,BigInteger的区别?
(1)int是基本数据类型,Integer,BigInteger是引用数据类型
(2)Integer是int的包装类,可以与int之间进行自动装箱和自动拆箱,可以互相自由转换。
int和BigInteger不能自由转换,需要通过方法来完成转换。
(3)当int和Integer表示不了的数字范围可以用BigInteger。
(4)int支持丰富的运算符。Integer,BigInteger要完成计算,需要调用方法。
package com.mytest.math;
import org.junit.Test;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
public class TestBig {
@Test
public void test1(){
// long a = 863214563214563214589321456325632521452L;//超出long范围
BigInteger a = new BigInteger("863214563214563214589321456325632521452");
BigInteger b = new BigInteger("896954562145215245244253215323296214586214521452");
//凡是对象要完成xx功能,就是通过调用方法
System.out.println("和:" + a.add(b));
System.out.println("差:" + a.subtract(b));
System.out.println("乘积:" + a.multiply(b));
System.out.println("商:" + a.divide(b));
System.out.println("余数:" + a.remainder(b));
}
@Test
public void test2(){
BigDecimal a = new BigDecimal("896954562145215245244253215323296214586214521452.0");
BigDecimal b = new BigDecimal("86214522.395251");
//凡是对象要完成xx功能,就是通过调用方法
System.out.println("和:" + a.add(b));
System.out.println("差:" + a.subtract(b));
System.out.println("乘积:" + a.multiply(b));
//System.out.println("商:" + a.divide(b));//除不尽
System.out.println("商:" + a.divide(b,1000, RoundingMode.CEILING));
//这里的1000代表保留到小数点后1000位
//这里的RoundingMode.CEILING代表第1001位的怎么处理,CEILING代表进位
System.out.println("余数:" + a.remainder(b));
}
}
1.3 产生随机数
- double Math.random()
- java.util.Random 类有很多nextXxx的方法,用于产生各种类型的随机数值。
[a,b)范围的整数
package com.mytest.math;
import org.junit.Test;
import java.util.Random;
public class TestRandom {
@Test
public void test1(){
double d = Math.random();//[0,1)
//[a,b)范围的整数:[10,50)
int a = 10;
int b = 50;
int num = (int) (Math.random() * (b - a) + a);
System.out.println("num = " + num);
}
@Test
public void test2(){
Random r = new Random();
double a = r.nextDouble();
boolean b = r.nextBoolean();
int c = r.nextInt();//int范围的任意整数
int d = r.nextInt(100);//[0,100)
int e = r.nextInt(10,50);//[10,50) 这个方法的版本比较新
System.out.println("a = " + a);// 0.9671156811567097
System.out.println("b = " + b);//true
System.out.println("c = " + c);//-327530929
System.out.println("d = " + d);//52
System.out.println("e = " + e);//48
}
}
二、日期时间类
在Java中日期时间API大的改动,主要经历了3代。
2.1 第1代
第1代:java.util.Date
缺点:
- 不支持不同时区的日期时间,也不友好,因为无法根据不同地区的用户习惯显示日期时间值。
- 线程安全问题
- 日期对象可变性
- 第1代:格式化工具类SimpleDateFormat
2.2 第2代
java.util.Calendar(日历类):解决了时区的问题
java.util.TimeZone:时区
java.util.Locale:地区和语言环境
缺点:
- 很难用
- 不支持SimpleDateFormat
- 日期时间对象可变
- 线程安全问题
2.3 第3代
JDK8引入了第3代的日期时间API。主要集中在java.time及其子包中,挑选一部分讲一下。
解决了对象不可变的问题,使用方便性的问题。第3代也是线程安全的。
2.3.1 本地的日期时间类(重要)
- LocalDate:本地日期
- LocalTime:本地时间
- LocalDateTime:本地日期时间
//今天的日期
LocalDate today = LocalDate.now();
//现在时间
LocalTime now = LocalTime.now();
//现在日期+时间
LocalDateTime dateTime = LocalDateTime.now();
2.3.2 日期或时间间隔
- Period:日期间隔
- Duration:时间间隔
LocalDate today = LocalDate.now();
LocalDate birthday = LocalDate.of(1990,8,16);
Period p = Period.between(birthday, today );
System.out.println(p);//P34Y3M28D 34年 3个月 28天
LocalTime now = LocalTime.now();
LocalTime end =LocalTime.of(12,0,0);
Duration d = Duration.between(now, end);
System.out.println(d);//PT28M50.8431153S
2.3.3 其他时区的日期时间
- ZonedDateTime:不同时区的日期时间
- ZoneID:时区
ZoneId id = ZoneId.of("America/Los_Angeles");
ZonedDateTime time = ZonedDateTime.now(id);
System.out.println(time);
//2024-12-13T19:33:07.531241200-08:00[America/Los_Angeles]
2.3.4 格式化
- DateTimeFormatter:代替第1代SimpleDateFormat,对第3代日期时间对象进行格式化。
LocalDateTime now = LocalDateTime.now();
//2024年12月14日 10时54分10秒
//DateTimeFormatter与SimpleDateFormat
//自定义模板
DateTimeFormatter dt = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH时mm分ss秒");
String str = dt.format(now);
System.out.println(str);
//2024年12月14日 11时36分00秒
三、数组工具类(重要)
3.1 Arrays工具类
Arrays工具类提供了各种静态方法,来为各种类型的一维数组服务。
3.2 System.arraycopy方法
- 可以生成新数组
- 可以对原数组进行操作(删除原数组中的某个元素、添加新元素)
package com.mytest.array;
import org.junit.Test;
import java.util.Arrays;
public class TestSystemArraycopy {
@Test
public void test1(){
int[] nums = {1,2,3,4,5};
int[] arr = new int[10];
//想要实现将nums的5个元素,复制到arr数组中 arr[0]~arr[4]
System.arraycopy(nums, 0, arr, 0, 5);
/*
从原数组复制元素到目标数组
第1个参数:原数组
第2个参数:要复制的元素的最左边的下标
第3个参数:目标数组
第4个参数:目标数组要存储新元素最左边的下标
第5个参数:一共几个元素
*/
System.out.println(Arrays.toString(arr));
}
}
四、字符串(重要)
4.1 字符串拼接工具类(了解)
StringJoiner工具类用于拼接字符串。
//拼接 hello,world,java这些单词为一个字符串,拼接时想要指定前缀,后缀,中间的连接符
StringJoiner joiner =new StringJoiner("-","[","]");
joiner.add("hello");
joiner.add("world");
joiner.add("java");
String str = joiner.toString();
System.out.println(str);//[hello-world-java]
4.2 可变字符序列/字符串缓冲区
StringBuffer和StringBuilder。
它们的内部有一个数组,用于存储一组字符,随着字符数量的增加,内部数组会自动扩容。默认数组的长度是16(默认扩容规则是:数组的长度 * 2 + 2)。
- 增
- append
- insert
- 删
- delete(start, end)
- deleteCharAt(下标)
- 改
- replace
- setCharAt
- setLength (1.改短:其余后续字符丢弃,2.改长:补空字符)
- reverse
- 查
- length
- indexOf (查找字符出现的位置下标)
- lastIndexOf (查找字符最后出现的位置下标)
StringBuffer和StringBuilder的区别?
StringBuffer:古老的,线程安全的,效率较低。
StringBuilder:较新的,线程不安全,效率较高。单线程情况下,优先使用它。
4.3 不可变字符序列
String类的方法:
4.3.1 系列1:基础方法
- .toUpperCase() :转大写
- .toLowerCase() :转小写
- .trim() :去掉前后空白符
- .isEmpty() :判断是否没有任何字符,即 ""
- .isBlank() :没有有效字符,只有空字符(空格,\t,\n 等)
- .equals() : 比较字符串的内容
- .equalsIgnoreCase() :忽略大小写比较(它是String类自己扩展的,不是Object类)
- .compareTo() :比较大小(String类实现了Comparable接口)
- .compareToIgnoreCase() :忽略大小写比较大小(此方法是String类自己扩展的,不是Comparable接口)
4.3.2 系列2:与char[]和byte[]有关
String str = "hello";
//可以转为char[]
char[] array = str.toCharArray();
System.out.println(Arrays.toString(array));
//[h, e, l, l, o]
//---------------------------------------------
char[] arr = {'a','b','c','d'};
//把char[]转为字符串
String str = new String(arr);
String str2 = String.valueOf(arr);
System.out.println(str);//abcd
System.out.println(str2);//abcd
String的对象,在JVM内存中是以Unicode字符集,UTF-16和Latin1(ISO8859-1)的编码方式。
- String的对象只有 ASCII码表范围的字符,就使用Latin1(ISO8859-1)的编码方式
- String的对象包含其他字符,例如汉字,就使用UTF-16的编码方式。
4.3.3 系列3:其他方法
String str = "hello.java";
- str.startsWith("hello");//true
- str.endsWith(".java");//true
- str.indexOf("o");//4
- str.lastIndexOf("a");//9
- str.contains("a");//true
- str.substring(star, end);
- str.replace("o","a"); //"hella.java" //所有替换
- str.replaceFirst("o","a"); //替换一次
- str.replaceAll("o","a"); //所有替换
- str.matches("[a-zA-Z]+");
4.4 String类的原理(面试重灾区)
4.4.1 String类的特点
问:String类能不能被继承?
String不能被继承,因为它是final
问:String类的对象可变吗?
不可变
问:String类的对象如何做到不可变的?
String的内部使用value数组来存储一组字符,JDK9之前是char[],JDK9之后byte[],它们都有final修饰。意味着这个数组不能修改地址,即不能扩容(因为扩容会创建新数组)。
这个数组是private,意味着在String类的外部不能直接操作这个value数组,需要通过String提供的各种方法来使用和修改这个value数组。在String类中所有涉及到修改value数组元素的方法,都是返回新的String对象。
问:String底层是如何存储一串字符的?
JDK9之前是char[],JDK9之后byte[]。
问:为什么要从char[]换为byte[]数组?
1个byte占1个字节,1个char占2个字节。
那么程序中大部分字符串都是英文字母组成的,这些字母其实用1个字节就可以存储了,从char改为byte可以节省一半内存。
问:对于汉字等,怎么办呢?
String会自由选择,如果字符串中都是ASCII码表范围的字符,那么1个字符用1个字节,coder是0,采用Latin1编码方式。
如果字符串中包含ASCII码表以外的字符,例如汉字,那么每一个字符都用2个字节,coder是1,采用UTF16编码方式。
问:字符串对象为什么要设计为不可变?
因为字符串对象不可变,才能被共享。
@Test
public void test2(){
String s1 = "hello";
String s2 = "hello";
System.out.println(s1 == s2);//true
//因为这里"hello"被共享了,它是字符串常量,s1和s2使用同一个"hello"对象
}
问:哪些字符串对象可以被共享呢?
- 直接""引起来的对象
- 字符串对象.intern()的结果
问:String s1 = new String("hello");有几个字符串对象
答:2个
问:两种拼接用那种 + 和 concat
答:先用 + (能合并就合并了,可以共享)