Java基础:数据类型

目录

数据类型

[8 种基本数据类型](#8 种基本数据类型)

[int 和 long 互相转换](#int 和 long 互相转换)

[用 bigDecimal 而不是 double](#用 bigDecimal 而不是 double)

装箱与拆箱

[128 陷阱](#128 陷阱)

[Integer 缓存](#Integer 缓存)


数据类型

8 种基本数据类型

浮点数默认为 double(float 型数值在末尾加上 f 或 F),整数默认为 int(long 型在末尾加上 l 或 L)。

int 和 long 互相转换

long 的范围比 int 大,int 转为 long 是安全的,但 long 转为 int 有可能导致溢出。

  • int 转 long 安全;
java 复制代码
 int intValue = 10;
 long longValue = intValue; // 自动转换,安全
  • long 转 int 有可能溢出。
java 复制代码
 long longValue = 100L;
 int intValue = (int) longValue; // 强制类型转换,可能会有数据丢失或溢出

将 long 转为 int 时,如果 longValue 的值超过了 int 类型的范围,结果将会是截断后的低位部分。

用 bigDecimal 而不是 double

计算机中主要采用二进制的科学计数法来存储和表示浮点数,遵循 IEEE 754。将实数表示为

这种格式(符号位、尾数、阶码),不仅能用统一形式表示极大或极小的数,而且还能节省内存空间并提高计算效率。

下图用 float 和 double 举例,仅仅 double 的阶位就远超过 long 类型所能表示的范围。

double 会出现精度丢失的问题,double 执行的是二进制浮点运算,二进制有些情况下不能准确地表示一个小数,就像十进制不能准确的表示1/3 (1/3 = 0.3333...),也就是说二进制表示小数的时候只能表示"若干 1/(2^n) 的组合"。由于若干个 1/(2^n) 无法表示 0.1,所以 double 无法表示 0.1 等浮点数。

而 Decimal 是精确计算, 所以一般牵扯到金钱的计算 , 都使用 Decimal。

java 复制代码
 public class BigDecimalExample {
   public static void main(String[] args) {
   BigDecimal num1 = new BigDecimal("0.1");
   BigDecimal num2 = new BigDecimal("0.2");
 ​
   BigDecimal sum = num1.add(num2);
   BigDecimal product = num1.multiply(num2);
 ​
   System.out.println("Sum: " + sum); // 0.3
   System.out.println("Product: " + product); // 0.02
  }
 }

使用 BigDecimal 可以确保精确的十进制数值计算,避免了使用 double 可能出现的舍入误差。需要注意的是,在创建 BigDecimal 对象时,应该使用字符串作为参数,而不是直接使用浮点数值,以避免浮点数精度丢失。

装箱与拆箱

Java 是面向对象的,但基本数据类型不是对象,包装类使得基本数据类型具备对象的特性

装箱 :基本数据类型转换为包装类。自动装箱有两种情况,包括赋值时方法调用 时。Integer.valueOf(数值)

  • 赋值时自动装箱:
java 复制代码
 Integer i = 10; // 自动装箱
  • 方法调用时自动装箱:
java 复制代码
 public static Integer show(Integer iParam) {
   System.out.println("i : " + iParam);
   return iParam;
 }
 ​
 show(3); // 自动装箱

拆箱 :包装类转化为基本数据类型。对象.intValue()

经典题

java 复制代码
 public static void main(String[] args) {
   int a = 10;
   int b = 10;
 
   Integer a1 = 10;
   Integer b1 = 10;
 
   Integer a2 = new Integer(10);
   Integer b2 = new Integer(10);
 
   System.out.println(a == b);
   System.out.println(a1 == b1);
   System.out.println(a2 == b2);
   System.out.println(a1 == a);
   System.out.println(a1.equals(a));
   System.out.println(a1 == a2);
   System.out.println(a == a2);
 }
代码表达式 运行结果 核心物理逻辑
a == b true 基本类型值比较int 存储在栈帧的局部变量表中,比较的是字面量数值。
a1 == b1 true IntegerCache 机制 :自动装箱调用 Integer.valueOf(10)。由于 10 在 [-128, 127] 缓存范围内,a1b1 指向堆中同一个缓存对象。
a2 == b2 false 显式堆分配new 关键字绕过缓存,在堆内存中强制开辟两个独立的空间,其引用地址不同。
a1 == a true 自动拆箱 :当包装类与基本类型进行 == 运算时,包装类 a1 会自动调用 intValue(),转化为基本类型后进行值比较。
a1.equals(a) true 比较数值内容equals 被重写,比较的是对象内部包裹的 int 数值。
a1 == a2 false 引用比较a1 指向常量池缓存对象,a2 指向 new 出来的堆对象,地址不一致。
a == a2 true 自动拆箱 :同 a1 == aa2 拆箱为基本类型 10,与 a 进行数值比较。

128 陷阱

由于 Integer 缓存范围为 -128 到 127,当使用 == 比较该范围外的对象(如 128)时,会因创建新对象 导致地址不一致返回 false,而范围内则为 true

解决方案

比较 Integer 对象时,应使用重写后的 .equals() 方法而不是 == 操作符。

Integer 缓存

源码分析

java 复制代码
 private static class IntegerCache {
   static final int low = -128;
   static final int high;
   static final Integer[] cache;
   static Integer[] archivedCache;
 ​
   static {
   // high value may be configured by property
   int h = 127;
   String integerCacheHighPropValue =
   VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
   if (integerCacheHighPropValue != null) {
   try {
   h = Math.max(parseInt(integerCacheHighPropValue), 127);
   // Maximum array size is Integer.MAX_VALUE
   h = Math.min(h, Integer.MAX_VALUE - (-low) -1);
  } catch( NumberFormatException nfe) {
   // If the property cannot be parsed into an int, ignore it.
  }
  }
   high = h;
 ​
   // Load IntegerCache.archivedCache from archive, if possible
   CDS.initializeFromArchive(IntegerCache.class);
   int size = (high - low) + 1;
 ​
   // Use the archived cache if it exists and is large enough
   if (archivedCache == null || size > archivedCache.length) {
   Integer[] c = new Integer[size];
   int j = low;
   for(int i = 0; i < c.length; i++) {
   c[i] = new Integer(j++);
  }
   archivedCache = c;
  }
   cache = archivedCache;
   // range [-128, 127] must be interned (JLS7 5.1.7)
   assert IntegerCache.high >= 127;
  }
 ​
   private IntegerCache() {}
 }
 ​
 @IntrinsicCandidate
 public static Integer valueOf(int i) {
   if (i >= IntegerCache.low && i <= IntegerCache.high)
   return IntegerCache.cache[i + (-IntegerCache.low)];
   return new Integer(i);
 }

Java 的 Integer 类内部实现了一个静态缓存池 ,用于存储特定范围内的整数值对应的 Integer 对象,只在装箱时生效,new 时不生效

默认情况下,这个范围是 -128 至 127。当通过 Integer.valueOf(int) 方法创建一个在这个范围内的整数对象时,并不会每次都生成新的对象实例,而是复用缓存中的现有对象

可见 c 数组中存储的是指向数值的指针,而不是数值本身。

相关推荐
楚国的小隐士21 小时前
为什么说Rust是对自闭症谱系人士友好的编程语言?
java·rust·编程·对比·自闭症·自闭症谱系障碍·神经多样性
AI成长日志21 小时前
【笔面试算法学习专栏】双指针专题·简单难度两题精讲:167.两数之和II、283.移动零
学习·算法·面试
@insist12321 小时前
网络工程师-生成树协议(STP/RSTP/MSTP)核心原理与应用
服务器·开发语言·网络工程师·软考·软件水平考试
旖-旎1 天前
分治(库存管理|||)(4)
c++·算法·leetcode·排序算法·快速选择算法
青稞社区.1 天前
ICLR‘26 Oral | 当 LLM Agent 在多轮推理中迷失时:T3 如何让强化学习重新学会主动推理
人工智能·算法·agi
春花秋月夏海冬雪1 天前
代码随想录刷题 - 贪心Part1
java·算法·贪心·代码随想录
野生技术架构师1 天前
2026年牛客网最新Java面试题总结
java·开发语言
环黄金线HHJX.1 天前
Tuan符号系统重塑智能开发
开发语言·人工智能·算法·编辑器
dog2501 天前
对数的大脑应对指数的世界
开发语言·php
Mr_Xuhhh1 天前
深入理解Java抽象类与接口:从概念到实战
java·开发语言