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 数组中存储的是指向数值的指针,而不是数值本身。

相关推荐
小璐资源网2 小时前
排序算法概览:十大排序算法一览
数据结构·算法·排序算法
sycmancia2 小时前
C++——智能指针类模板
开发语言·c++
躲在没风的地方2 小时前
异常执行顺序
java·运维·服务器·spring boot
王夏奇2 小时前
Python-对excel文件操作的总览
开发语言·python·excel
knighthood20012 小时前
ROS1中source xxx.bash失效
开发语言·bash
骇客野人2 小时前
python爬虫例子,且处理反爬的网站也能爬
开发语言·爬虫·python
没有bug.的程序员2 小时前
黑客僵尸网络的降维打击:Spring Cloud Gateway 自定义限流剿杀 Sentinel 内存黑洞
java·网络·spring·gateway·sentinel
Allen_LVyingbo2 小时前
PostgreSQL动态分区裁剪技术:查询性能优化解析(2026年版)
数据库·算法·观察者模式·postgresql·性能优化·架构
予枫的编程笔记2 小时前
【面试专栏|Java并发编程】ConcurrentHashMap并发原理详解:JDK7 vs JDK8 核心对比
java·并发编程·hashmap·java面试·集合框架·jdk8·jdk7