常用API(Runtime类 BigDecimal类 Date类 SimpleDateFormat类 Calendar类)
一、Runtime类
我们学习一个Java的运行时类,叫Runtime类。这个类可以用来获取JVM的一些信息,也可以用这个类去执行其他的程序。
Runtime类提供的常见方法
| 方法名 | 说明 |
|---|---|
| public static Runtime getRuntime() | 返回与当前Java应用程序关联的运行时对象 |
| public void exit(int status) | 终止当前运行的虚拟机 |
| public int availableProcessors() | 返回Java虚拟机可用的处理器数。 |
| public long totalMemory() | 返回Java虚拟机中的内存总量 |
| public long freeMemory() | 返回Java虚拟机中的可用内存 |
| public Process exec(String command) | 启动某个程序,并返回代表该程序的对象 |
话不多少,上代码。
/** * 目标:了解下Runtime的几个常见方法。 */ public class RuntimeTest { public static void main(String[] args) throws IOException, InterruptedException { // 1、public static Runtime getRuntime() 返回与当前Java应用程序关联的运行时对象。 Runtime r = Runtime.getRuntime(); // 2、public void exit(int status) 终止当前运行的虚拟机,该参数用作状态代码; // 按照惯例,非零状态代码表示异常终止。 // r.exit(0); // 3、public int availableProcessors(): 获取虚拟机能够使用的处理器数。 System.out.println(r.availableProcessors()); // 16 // 4、public long totalMemory() 返回Java虚拟机中的内存总量。 // 1024 = 1K 1024 * 1024 = 1M System.out.println(r.totalMemory()/1024.0/1024.0 + "MB"); // 5、public long freeMemory() 返回Java虚拟机中的可用内存量 System.out.println(r.freeMemory()/1024.0/1024.0 + "MB"); // 6、public Process exec(String command) 启动某个程序,并返回代表该程序的对象。 Process p = r.exec("D:\\Software\\Tencent\\TIM\\Bin\\TIM.exe"); Thread.sleep(10000); // 让程序在这里暂停5s后继续往下走!! p.destroy(); // 销毁!关闭程序! } }二、BigDecimal类(重点)
各位同学,接下来我们学习的这个类叫BigDecimal,至于它是干什么用的,我们先不说。我们先看一段代码,看这个代码有什么问题?再说BigDeimal这个类是干什么用的,这样会更好理解一些。
public class Test { public static void main(String[] args) { // 浮点型运算时, 直接+ - * / 可能会出现运算结果失真 System.out.println(0.1 + 0.2); System.out.println(1.0 - 0.32); System.out.println(1.015 * 100); System.out.println(1.301 / 100); } }运行以上代码,我们会发现,结果并和我们想看到的不太一样。如下图所示
为了解决计算精度损失的问题,Java给我们提供了BigDecimal类,它提供了一些方法可以对数据进行四则运算,而且不丢失精度,同时还可以保留指定的小数位。
BigDecima的常见构造器
| 构造器 | 说明 |
|---|---|
| public BigDecimal(double val) 注意:不推荐使用这个 | 将 double转换为 BigDecimal |
| public BigDecimal(String val) | 把String转成BigDecimal |
底层计算的原理: 在BigDecimal内部,它使用一个整数数组来存储数值的每一位。通常情况下,数组的每个元素表示一组十进制数的位数,例如,数组的第一个元素表示最低位,第二个元素表示十位,以此类推。每个数组元素都是一个32位整数,即可以存储0到2^32-1之间的数值。 在进行数值的运算时,BigDecimal会根据操作的类型和需要的精度,对两个数值进行相应的运算,例如加法、减法、乘法和除法。运算的过程中,它会对两个数值的符号进行处理,并按照数学规则进行运算。对于除法运算,BigDecimal会通过精确的算法进行计算,避免了浮点数除法可能产生的精度损失。
BigDecima的常用方法
| 方法名 | 说明 |
|---|---|
| public static BigDecimal valueOf(double val) | 转换一个 double成 BigDecimal |
| public BigDecimal add(BigDecimal b) | 加法 |
| public BigDecimal subtract(BigDecimal b) | 减法 |
| public BigDecimal multiply(BigDecimal b) | 乘法 |
| public BigDecimal divide(BigDecimal b) | 除法 |
| public BigDecimal divide (另一个BigDecimal对象,精确几位,舍入模式) | 除法、可以控制精确到小数几位 |
| public double doubleValue() | 将BigDecimal转换为double |
下面看代码,演示一下
public class BigDecimalTest { public static void main(String[] args) { // 浮点型运算时, 直接+ - * / 可能会出现运算结果失真 double a = 0.1; double b = 0.2; System.out.println(a + b); //0.30000000000000004 此时会导致精度失真 System.out.println("-----------------------"); /** * 如何解决精度失真问题? 使用BigDecimal可以解决 */ // BigDecimal a1 = new BigDecimal(Double.toString(a)); // BigDecimal b1 = new BigDecimal(Double.toString(b)); /** * 简单写法: * 推荐用以下方式:把小数转换成字符串再得到BigDecimal对象来使用(更简洁) */ BigDecimal a1 = BigDecimal.valueOf(a); BigDecimal b1 = BigDecimal.valueOf(b); System.out.println(a1.add(b1)); // 加 System.out.println(a1.subtract(b1)); // 减 System.out.println(a1.multiply(b1)); // 乘 System.out.println(a1.divide(b1)); // 除 // 除法还可以设置精度保留几位 BigDecimal d1 = BigDecimal.valueOf(0.1); BigDecimal d2 = BigDecimal.valueOf(0.3); BigDecimal d3 = d1.divide(d2, 2, RoundingMode.HALF_UP); // 0.33 System.out.println(d3); System.out.println("-----------------------"); // 把BigDecimal对象又转换成double类型的数据 double v = d1.doubleValue(); System.out.println(v); } }三、Date类
接下来,我们学习一下Date类,Java中是由这个类的对象用来表示日期或者时间。
Date对象记录的时间是用毫秒值来表示的。Java语言规定,1970年1月1日0时0分0秒认为是时间的起点,此时记作0,那么1000(1秒=1000毫秒)就表示1970年1月1日0时0分1秒,依次内推。
下面是Date类的构造方法,和常见的成员方法,利用这些API写代码尝试一下
public class DateTest { public static void main(String[] args) { // 目标:掌握Date日期类的使用。 // 1、创建一个Date的对象:代表系统当前时间信息的。 Date d1 = new Date(); System.out.println(d1); // 2、拿到时间毫秒值。 long time = d1.getTime(); System.out.println(time); // 3、把时间毫秒值转换成日期对象: 2s之后的时间是多少。 time += 2 * 1000; Date d2 = new Date(time); System.out.println(d2); // 4、直接把日期对象的时间通过setTime方法进行修改 Date d3 = new Date(); d3.setTime(time); System.out.println(d3); } }四、SimpleDateFormat类
各位同学,前面我们打印Date对象时,发现打印输出的日期格式我们并不喜欢,是不是?你们喜欢那种格式呢?是不是像下面页面中这种格式啊?接下来我们学习的SimpleDateFormat类就可以转换Date对象表示日期时间的显示格式。
我们把Date对象转换为指定格式的日期字符串这个操作,叫做日期格式化,
反过来把指定格式的日期符串转换为Date对象的操作,叫做日期解析。
接下来,我们先演示一下日期格式化,需要用到如下的几个方法
注意:创建SimpleDateFormat对象时,在构造方法的参数位置传递日期格式,而日期格式是由一些特定的字母拼接而来的。我们需要记住常用的几种日期/时间格式
字母 表示含义 yyyy 年 MM 月 dd 日 HH 时 mm 分 ss 秒 SSS 毫秒 EEE 星期几 a 上午/下午 "2022年12月12日" 的格式是 "yyyy年MM月dd日" "2022-12-12 12:12:12" 的格式是 "yyyy-MM-dd HH:mm:ss" 按照上面的格式可以任意拼接,但是字母不能写错
最后,上代码演示一下
public class SimpleDateFormatTest1 { public static void main(String[] args) throws ParseException { // 目标:掌握SimpleDateFormat的使用。 // 1、准备一些时间 Date date = new Date(); System.out.println(date); // 获取毫秒值 long time = date.getTime(); System.out.println(time); // 2、格式化日期对象,和时间 毫秒值。 SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss EEE a"); String rs1 = sdf.format(date); System.out.println(rs1); // 毫秒值进行时间格式化 String rs2 = sdf.format(time); System.out.println(rs2); System.out.println("----------------------------------------------"); // 目标:掌握SimpleDateFormat解析字符串时间 成为日期对象。 String dateStr = "1999-12-1 12:12:11"; // 1、创建简单日期格式化对象 , 指定的时间格式必须与被解析的时间格式一模一样,否则程序会出bug. SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Date d2 = sdf2.parse(dateStr); System.out.println(d2); } }![]()
public class SimpleDateFormatDemo { public static void main(String[] args) throws ParseException { // 目标:完成秒杀案例。 // 1、把开始时间、结束时间、小贾下单时间、小皮下单时间拿到程序中来。 String start = "2023年11月11日 0:0:0"; String end = "2023年11月11日 0:10:0"; String xj = "2023年11月11日 0:01:18"; String xp = "2023年11月11日 0:10:57"; // 2、把字符串的时间解析成日期对象。 SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss"); Date startDt = sdf.parse(start); Date endDt = sdf.parse(end); Date xjDt = sdf.parse(xj); Date xpDt = sdf.parse(xp); // 3、开始判断小皮和小贾是否秒杀成功了。 // 把日期对象转换成时间毫秒值来判断 long startTime = startDt.getTime(); long endTime = endDt.getTime(); long xjTime = xjDt.getTime(); long xpTime = xpDt.getTime(); if(xjTime >= startTime && xjTime <= endTime){ System.out.println("小贾您秒杀成功了~~"); }else { System.out.println("小贾您秒杀失败了~~"); } if(xpTime >= startTime && xpTime <= endTime){ System.out.println("小皮您秒杀成功了~~"); }else { System.out.println("小皮您秒杀失败了~~"); } } }五、Calendar类
学完Date类和SimpleDateFormat类之后,我们再学习一个和日期相关的类,它是Calendar类。Calendar类表示日历,它提供了一些比Date类更好用的方法。
为什么要使用Calendar类?
需求:将2023年09月10日 增加一个月 实现步骤: 1. 定义字符串记住: 2023年09月10日 2. 把字符串时间解析成Date日期对象 3. 通过Date日期对象获取2023年9月10日的毫秒值 4. 增加一个月的毫秒值:1000 * 60 * 60 * 24 * 30 5. 再格式化时间毫秒值得到结果:2023年10月10日
用Date类就不太好做,而用Calendar就特别方便。因为Calendar类提供了方法可以直接对日历中的年、月、日、时、分、秒等进行运算。
Calendar日历类的常见方法
| 方法名 | 说明 |
|---|---|
| public static Calendar getInstance() | 获取当前日历对象 |
| public int get(int field) | 获取日历中的某个信息。 |
| public final Date getTime() | 获取日期对象。 |
| public long getTimeInMillis() | 获取时间毫秒值 |
| public void set(int field,int value) | 修改日历的某个信息。 |
| public void add(int field,int amount) | 为某个信息增加/减少指定的值 |
注意:calendar是可变对象,一旦修改后其对象本身表示的时间将产生变化。
public class CalendarTest { public static void main(String[] args) { // 目标:掌握Calendar的使用和特点。 // 1、得到系统此刻时间对应的日历对象。 Calendar now = Calendar.getInstance(); // 打印系统此刻时间的全部信息 System.out.println(now); // 2、获取日历中的某个信息 // 获取年 int year = now.get(Calendar.YEAR); System.out.println(year); // 获取月 int month = now.get(Calendar.MONTH) + 1; System.out.println(month); // 获取日 int days = now.get(Calendar.DAY_OF_MONTH); System.out.println(days); // 3、拿到日历中记录的日期对象。 Date date = now.getTime(); System.out.println(date); // 4、拿到时间毫秒值 long time = now.getTimeInMillis(); System.out.println(time); // 5、修改日历中的某个信息 now.set(Calendar.MONTH, 11); // 修改月份成为 11 月份。 now.set(Calendar.DAY_OF_YEAR, 125); // 修改成一年中的第 125 天。 System.out.println(now); // 6、为某个信息增加或者减少多少 now.add(Calendar.DAY_OF_YEAR, 100); now.add(Calendar.DAY_OF_YEAR, -10); now.add(Calendar.DAY_OF_MONTH, 6); now.add(Calendar.HOUR, 12); System.out.println(now); } }六、为什么JDK8要新增日期类
/** * 目标:搞清楚为什么要用JDK 8开始新增的时间类。 */ public class Test { public static void main(String[] args) { // 传统的时间类(Date、SimpleDateFormat、Calendar)存在如下问题: // 1、设计不合理,使用不方便,很多都被淘汰了。 Date d = new Date(); System.out.println(d.getYear()); // 获取的是125, 而不是现在的2025年 System.out.println(d.getYear() + 1900); // Calendar也不是很合理, 因为需要去记住日历的每个字段信息 Calendar c = Calendar.getInstance(); int year = c.get(Calendar.YEAR); System.out.println(year); /** * 2、都是可变对象,修改后会丢失最开始的时间信息。 * 比如: * Calendar.set()方法, 重新设置后当前的日期就获取不到了 * Date.setTime(time)方法, 重新设置后之前的信息就获取不到了 */ /** * 3、线程不安全。(后边知识会学习) * 了解下: 比如有很多用户会一起用时间对象, 如果其中一个人把时间修改了, * 另一个人也把时间进行了修改, 最终获取的时间是以哪个人为主, 就会产生冲突. */ /** * 4、不能精确到纳秒,只能精确到毫秒。 * 1秒 = 1000毫秒 * 1毫秒 = 1000微妙 * 1微妙 = 1000纳秒 */ } }