当前位置: 首页 > news >正文

包装类、日期等常用类型

第十三天

包装类、日期等常用类型

1.包装类简介

java语言是面向对象的语言,但是其中的八大基本数据类型不符合面向对象的特征。因此java为了弥补这样的缺点,为这八种基本数据类型专门设计了八种符合面向对象特征的的类型,这八种具有面向对象特征的类型,统称为包装类。

基本**数据类型**包装类型
byteByte
shortShort
intInteger
longLong
floatFloat
doubleDouble
booleanBoolean
charCharacter

2.装箱与拆箱

  • 装箱boxing : 由基本数据类型转型为包装类型。

    • 调用包装类的构造器,进行装箱

    • 调用valueOf()静态方法,进行装箱

  • 拆箱 unboxing: 由包装类型转型为基本数据类型。

    • 调用xxxValue()非静态方法,进行拆箱

3.自动装箱与自动拆箱

为了方便获取包装类对象,从jdk1.5以后,提供了一个自动装箱的操作,也提供了一个包装类到基本数据类的自动拆箱操作。

  • 自动装箱 : 直接使用一个基本数据类型的变量或字面值给一个包装类型的引用进行赋值即可

  • 自动拆箱 : 直接使用一个包装类型的引用给一个基本数据类型的变量进行赋值即可

4.包装类常量池

对于装箱操作后的包装类的对象,jvm在堆中,维护了一个常量池,该常量池适用于调用了valueOf()方法产生的包装类对象,以及自动装箱的包装类对象。不适用于new关键字创建的包装类对象。

Byte, Short, Integer, Long 这 4 种包装类默认创建了数值 [-128, 127] 的相应类型的缓存数据,

Character 创建了数值在 [0, 127] 范围的缓存数据,

Boolean 直接返回 true 或 false。

Double和Float两个包装类并没有提供常量池

/*** 针对于装箱操作后的包装类的对象的常量池*     Integer: -128~127*/
public class _03Box {public static void main(String[] args) {int num = 127;Integer i1 =  Integer.valueOf(num);  //装箱操作Integer i2 =  Integer.valueOf(num);//使用 == 来判断是否是同一个对象System.out.println(i1==i2);  //true,同一个对象
​
​// Double和Float两个包装类并没有提供常量池double d1 = 3.14;Double d2 = Double.valueOf(d1);Double d3 = Double.valueOf(d1);System.out.println(d2==d3);
​boolean f = true;Boolean f1 = Boolean.valueOf(f);Boolean f2 = Boolean.valueOf(f);System.out.println(f1==f2);
​char c1 = 97;  // 'a'Character c2 = Character.valueOf(c1);Character c3 = Character.valueOf(c1);System.out.println(c2==c3); //true}
}
/**
​*    Integer.parseInt();*    Integer.toBinaryString();  转成二进制*    Integer.toHexString();    转成16进制*    Integer.toOctalString()   转成8进制**    public static int parseInt(String str):*    public static Integer valueOf(String str):*    上述两个方法都用Integer类名调用,*    作用相似:都是将字符串转成整形,一个是转成int类型,一个是转成Integer类型*/

5.BigDecimal/BigInteger

因为使用八大基本数据类型做运算时,尤其是浮点数的运算时,容易精度不准确,所以java语言提供了BigDecimal这个类来完善这类运算,可以非常精确,可以精确到小数点后无数位。BigDecimal 通常支持任意位数的小数部分,用来对超过16位有效位的数进行精确的运算,(float可以精确到7左右,double是15位左右)

BigDecimal(int val) 创建一个具有参数所指定整数值的对象。

BigDecimal(double val) 创建一个具有参数所指定双精度值的对象。不推荐使用,因为存在精度丢失问题

BigDecimal(long val) 创建一个具有参数所指定长整数值的对象。

BigDecimal(String val) 创建一个具有参数所指定以字符串表示的数值的对象。 推荐使用

6.为什么不能用浮点数表示金额?

因为不是所有的小数都能用二进制表示(扩展知识中介绍为啥不能表示),所以,为了解决这个问题,IEEE提出了一种使用近似值表示小数的方式,并且引入了精度的概念。这就是我们所熟知的浮点数。

所以,浮点数只是近似值,并不是精确值,所以不能用来表示金额。否则会有精度丢失。比如0.1+0.2 != 0.3.

7.BigDecimal(double)和BigDecimal(String)有什么区别?

因为double是不精确的,所以使用一个不精确的数字来创建BigDecimal,得到的数字也是不精确的。如0.1这个数字,double只能表示他的近似值。

而对于BigDecimal(String) ,当我们使用new BigDecimal("0.1")创建一个BigDecimal 的时候,其实创建出来的值正好就是等于0.1的。

BigDecimal实际上一个BigDecimal是通过一个"无标度值"和一个"标度"来表示一个数的。

无标度值(Unscaled Value):这是一个整数,表示BigDecimal的实际数值。 标度(Scale):这是一个整数,表示小数点后的位数。 BigDecimal的实际数值计算公式为:unscaledValue × 10^(-scale)。

假设有一个BigDecimal表示的数值是123.45,那么无标度值(Unscaled Value)是12345。标度(Scale)是2。因为123.45 = 12345 × 10^(-2)。

8.为什么不能用BigDecimal的equals方法做等值比较?

因为BigDecimal的equals方法和compareTo并不一样,equals方法会比较两部分内容,分别是值(value)和标度(scale),而对于0.1和0.10这两个数字,他们的值虽然一样,但是精度是不一样的,所以在使用equals比较的时候会返回false。

9.无限精度的坑

BigDecimal 并不代表无限精度,当在两个数除不尽的时候,就会出现无限精度的坑,如下所示:

public static void main(String[] args){BigDecimal b1 = new BigDecimal("1.0");BigDecimal b2 = new BigDecimal("3.0");b1.divide(b2);
}
​
Exception in thread "main" java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.at java.math.BigDecimal.divide(BigDecimal.java:1693)at com.demo.controller.Test.main(Test.java:29)

大致意思就是,如果在除法(divide)运算过程中,如果商是一个无限小数(如 0.333…),而操作的结果预期是一个精确的数字,那么将会抛出ArithmeticException异常。

此种情况,只需要在使用 divide方法时指定结果的精度即可:

public static void main(String[] args){BigDecimal b1 = new BigDecimal("1.0");BigDecimal b2 = new BigDecimal("3.0");System.out.println(b1.divide(b2,2, RoundingMode.HALF_UP));//0.33
}

在使用BigDecimal进行(所有)运算时,尽量指定精度和舍入模式。

10.传统的日期处理类型 方法

Date日期类型

1)构造器

  • Date() :获取当前系统时间

  • Date(long time):设置一个距离固定点的指定毫秒数的时间点。

2)方法

  • long getTime()

  • void setTime(long time)

  • String toString() 格式: Thu May 24 19:32:14 CST 2018

SimpleDateFormat类型

1)构造器

  • SimpleDateFormat()

  • SimpleDateFormat(String pattern):指定一个日期格式符号来构造对象

2)方法

  • final String format(Date date) DateàString

  • Date parse(String source) throws ParseException

3)日期模式匹配字符

字符含义案例
yyyyy年—2018年;yy-18年
MMM月—05月;M月—5月
ddd日—06日;d日—6日
E星期E-星期日(Sun)
a上下午(AM、PM)a—下午(PM)
H24小时制a h时--------下午 10时 HH:mm:ss------12:21:34 hh(a):mm:ss------12(PM):21:34
h12小时制
m分钟
s

Calendar类型

1)getInstance方法

Calendar提供了一个类方法getInstance,以获取此类型的一个通用的对象

此方法返回一个Calendar对象,其日历字段已经由当前日期和时间初始化

2)日期与时间分量方法

  • Calendar提供的get方法与一些常量合用可以获取日期及时间分量

  • Calendar提供的set方法与一些常量合用可以设置日期及时间分量

  • 常量

    • static int YEAR 指定年份的字段数字

    • static int MONTH 指定月份的字段数字,0为一月

    • static int DATE 指示一个月份中的第几天

    • static int DAY_OF_WEEK 指定一个星期中的某天,1为星期日

    • static int WEEK_OF_MONTH 指定一个月中的第几周

    • static int WEEK_OF_YEAR 指定一年中的第几周

3)其他方法

  • getActualMaximum方法

    • int getActualMaximum(int field)

    • 作用:指定一个时间常量,返回指定日历分量可能拥有的最大值。

    • 注意:要保证年月日的日数字小于等于28

  • add方法

    • void add(int field , int mount)

    • 作用:指定一个时间常量,在此时间分量上增加指定的数值,若为负值,则是减去指定的数值。

  • getTime与setTime

    • Date getTime()

    • 作用:返回一个Date类型来描述日期

    • void setTime(Date d)

    • 作用:用Calendar表示Date所描述的日期

Date类型的不足

  1. 时区问题: Date 类不处理时区信息,它只表示一个时间点,通常默认为 GMT(格林威治标准时间)。这导致了很多时区相关的问题,因为日期和时间需要根据时区进行转换和显示。

  2. 线程不安全性: Date 类是可变的,这意味着你可以修改它的值。由于 Java 中的日期和时间操作通常需要是线程安全的,这种可变性可能导致并发问题。

LocalDateTime类简介

java.time.LocalDateTime 类是 Java 8 引入的日期时间类,它解决了许多java.util.Date 类存在的问题,并提供了更好的方式来处理日期和时间信息。以下是关于 LocalDateTime 为什么更好的一些原因:

  1. 线程安全性: java.time.LocalDateTime 是不可变的,这意味着一旦创建了对象,它的值不能被修改。这保证了在多线程环境中使用时不会出现并发问题,与 java.util.Date 的可变性形成鲜明对比。

  2. 时区支持: LocalDateTime 提供了更好的时区支持。它存储日期和时间信息,但不包含时区信息。这允许你在需要时将日期时间信息与特定时区相关联,而不会像 java.util.Date 那样受限于默认时区(通常是 GMT)。你可以使用 ZoneId 来将 LocalDateTime 转换为特定时区的时间

  3. 更丰富的功能: java.time 包中提供了一整套用于日期时间操作的类和方法,使日期时间处理更加方便和功能丰富。你可以轻松进行日期的加减、格式化、比较等操作,而无需手动编写复杂的代码。

  4. 清晰的命名: java.time 类使用了更直观和清晰的命名,不再存在像 java.util.Date 中那样的命名混乱,例如 getYear()getMonth() 方法的问题。

LocalDateTime常用操作

1.日期加减

使用 Date 进行日期加减操作通常需要使用 Calendar 类,而使用 LocalDateTime 更简单,例如:

// Date 加减
Date currentDate = new Date();
Calendar calendar = Calendar.getInstance();
calendar.setTime(currentDate);
calendar.add(Calendar.DAY_OF_MONTH, 1); // 增加一天
Date tomorrow = calendar.getTime();
​
// LocalDateTime 加减
LocalDateTime currentDateTime = LocalDateTime.now();
LocalDateTime nextDay = currentDateTime.plusDays(1); // 增加一天

2. 格式化和解析

使用 Date 进行格式化和解析通常需要使用 SimpleDateFormat,而 LocalDateTime 内置了格式化和解析功能:

// Date 格式化和解析
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateStr = dateFormat.format(currentDate);
Date parsedDate = dateFormat.parse(dateStr);
​
// LocalDateTime 格式化和解析
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String dateTimeStr = currentDateTime.format(formatter);
LocalDateTime parsedDateTime = LocalDateTime.parse(dateTimeStr, formatter);

3.转换

你可以在 DateLocalDateTime 之间进行相互转换,例如:

// Date 转换为 LocalDateTime
Date date = new Date();
Instant instant = date.toInstant();
LocalDateTime localDateTime = instant.atZone(ZoneId.systemDefault()).toLocalDateTime();
​
// LocalDateTime 转换为 Date
LocalDateTime localDateTime = LocalDateTime.now();
ZonedDateTime zonedDateTime = localDateTime.atZone(ZoneId.systemDefault());
Date date = Date.from(zonedDateTime.toInstant());

这里需要注意的是,转换时需要考虑时区的影响,因为 Date 不包含时区信息,而 LocalDateTime 存储的是本地时间。所以,转换时需要确定时区信息以保持一致性。

总之,LocalDateTime 提供了更简单和直观的日期时间操作,同时也可以与 Date 进行转换,以兼容传统的日期时间处理方式。然而,使用 LocalDateTime 更推荐,尤其在新的 Java 8+ 应用中,因为它更强大、更安全,同时提供了更多的功能。

http://www.dtcms.com/a/312103.html

相关文章:

  • C语言数据结构(5)双向链表
  • 深入剖析Nacos:云原生架构的基石
  • Python编程基础与实践:Python基础数据类型入门
  • 中国工程院郑裕国院士确认出席:2025第五届生物发酵营养源高峰论坛生物发酵展
  • CMake基础使用指南
  • QtC++ 调用 tesseract开源库 搭配 Opencv 实现文字识别:从tesseract库基本介绍到实际应用实现
  • 【华为OD机试】计算图形面积
  • 关于Egret引擎的一些思考
  • 单位长度上的RC参数
  • 【补题】Codeforces Round 715 (Div. 1) B. Almost Sorted
  • linux中pthread_t 的值与top -Hp中线程id值的区别
  • 装 饰 器 模 式
  • 深入 Go 底层原理(七):逃逸分析
  • C++ 11 模板萃取
  • 丑数-优先队列/三指针/动态规划
  • Linux 动静态库的制作和使用
  • 深度剖析PyTorch torch.compile的性能曲线与优化临界点
  • SpringBoot 01 IOC
  • PyTorch 张量核心操作——比较、排序与数据校验
  • java实现运行SQL脚本完成数据迁移
  • 通俗易懂解释Java8 HashMap
  • Rust进阶-part1-智能指针概述-box指针
  • 【多模态】DPO学习笔记
  • 嵌入式文件系统
  • Java中Lambda 表达式的解释
  • PCB铜浆塞孔工艺流程
  • 如何快速解决PDF解密新方法?
  • 使用C++实现日志(1)
  • 疏老师-python训练营-Day33 MLP神经网络的训练
  • AbstractExecutorService:Java并发核心模板解析