8 种基本数据类型:byte 1,short 2,int 4,long 8,float 4,dobule 8,char 2,boolean 1
对应的包装类型:Byte,Short,Interger,Long,Float,Double,Character,Boolean
对应占用的字节:1,2,4,8,4,8,2,1
注意:short 是 2 字节
想想字节和取值范围的关系。
需要注意的是,这个范围是针对有符号的整数类型。
如果使用【无符号】的整数类型(如 Java 中的 unsigned int),则范围将从 0 到 2^32 - 1,即约为 0 到 4,294,967,295。
五大区别:
用途:
存储方式:
static
修饰 )存放在 Java 虚拟机的堆中。占用空间:
相比于包装类型(对象类型),基本数据类型占用的空间往往非常小。
默认值:
成员变量包装类型的默认值是 null
,
基本类型有默认值,但不固定。
- byte:0
- short:0
- int:0
- long:0L
- float:0.0f
- double:0.0d
- char:‘\u0000’
- boolean:false
比较方式:
==
比较的是值。==
比较的是对象的内存地址。所有整型包装类对象之间值的比较,全部使用 equals()
方法。另一种说法是:包装类型的常量池技术。
Java
基本数据类型的包装类型大部分都用到了缓存机制来提升性能(除了浮点型)。即会默认创建相应类型的缓存数据。
例如:Byte
,Short
,Interger
,Long
这 4 种包装类默认创建了数值 [-128,127] 的相应类型的缓存数据,Character
创建了数值在 [0,127] 范围的缓存数据,Boolean
直接返回 True
or False
。
当使用自动装箱的方式将一个基本数据类型的值转换为包装类型时,如果这个值在缓存范围内,那么就直接返回缓存中的对象,否则就创建一个新的对象。
由于包装类型的值是存储在堆内存中的,因此在进行大量的数值计算时,使用包装类型会比直接使用基本数据类型更加耗时和占用内存。为了提高程序的性能和效率,Java 提供了包装类型的缓存机制。
在 Java 中,包装类型是将基本数据类型(如 int、double 等)封装成对象的一种机制。
Java 中引入包装类型的主要原因是为了提供一些额外的功能和灵活性,这些功能在基本数据类型上不可用。
以下是一些包装类型的常见用途:
toString()
方法将包装类型转换为字符串,而基本数据类型不能。总之,包装类型可以使 Java 代码更加灵活和易于维护。它们可以使基本数据类型具有对象特性,并提供了许多基本数据类型上不可用的功能。此外,Java 中的包装类型还可以用于处理空值和进行类型转换,这些在基本数据类型上是不可能实现的。
装箱就是将基本类型用它们对应的引用类型包装起来,原理是调用了包装类的 valueOf()
方法;
拆箱是将包装类型转换为基本数据类型,相应的调用的是 xxxValue()
方法,比如 intValue()
方法。
eg:
Integer i = 10
等价于Integer i = Integer.valueOf(10)
– 装箱int n = i
等价于int n = i.intValue()
– 拆箱
原理:
基本类型与相应的包装类型用 ==
号比较会怎么样?
Integer a = new Integer(10);
Integer b = new Integer(10);
System.out.println(a == b); // 输出 false,因为比较的是引用
int c = 10;
System.out.println(a == c); // 输出 true,因为自动拆箱后比较的是值
浮点数运算精度丢失代码演示:
float a = 2.0f - 1.9f;
float b = 1.8f - 1.7f;
System.out.println(a); // 0.100000024
System.out.println(b); // 0.099999905
System.out.println(a == b); // false
这是因为计算机在表示一个数字时,宽度是有限的,无限循环的小数存储在计算机时,只能被截断,所以就会导致小数精度发生损失的情况。
使用 BigDecimal
可以实现对浮点数的运算,并且不会造成精度丢失。
通常情况下,大部分需要浮点数精确运算结果的业务场景(比如涉及到钱的场景)都是通过 BigDecimal
来做的。
BigDecimal a = new BigDecimal("1.0");
BigDecimal b = new BigDecimal("0.9");
BigDecimal c = new BigDecimal("0.8");
BigDecimal x = a.subtract(b); // sub 减法
BigDecimal y = b.subtract(c);
System.out.println(x); /* 0.1 */
System.out.println(y); /* 0.1 */
System.out.println(Objects.equals(x, y)); /* true */
基本数值类型都有一个表达范围,如果超过这个范围就会有数值溢出的风险。
在 Java 中,64 位(8字节) long 整型是最大的整数类型。
如果需要表示超过 long 整型的数据,可以使用 Java 提供的 BigInteger
类。
import java.math.BigInteger;
public class BigIntegerDemo {
public static void main(String[] args) {
BigInteger a = new BigInteger("12345678901234567890");
BigInteger b = new BigInteger("98765432109876543210");
BigInteger c = a.add(b);
System.out.println(c);
}
}
BigInteger
类的加、减、乘、除等运算都是通过调用方法来实现的,而不是像基本数据类型那样使用运算符。BigInteger
内部使用 int[]
数组来存储任意大小的整形数据。在 Java 中,除了基本数据类型和 void
类型以外,其它所有类型都是引用类型。
void
类型是一种特殊的类型,它表示没有返回值的方法或表达式的类型。void
类型不属于基本数据类型,也不属于引用类型,而是一种独立的类型。常见的引用类型包括:
MyClass obj = new MyClass(); // 使用 new 关键字创建 MyClass 类的对象,并将对象赋值给 obj 变量
此时,obj 变量存储的是对象的内存地址,即对象的引用。因此,通过 obj 变量可以访问对象的属性和方法。
NPE 问题就是:空指针异常(NullPointerException,NPE)问题。
在 Java 中,自动拆箱是将包装类型自动转换为相应的基本数据类型的过程,而如果包装类型为null,自动拆箱就会引发空指针异常(NullPointerException,NPE)。
这是因为基本数据类型不支持为 null 值,因此在尝试使用为 null 的包装类型时,Java 会尝试将其转换为基本数据类型,从而引发 NPE 异常。
以下是一个简单的示例,展示了自动拆箱引发 NP E问题的情况:
Integer num = null;
int i = num; // 自动拆箱,将null转换为int类型,引发NPE异常
为了避免自动拆箱引发的 NPE 问题,可以使用条件语句或显式拆箱来检查包装类型是否为 null。例如,可以使用以下代码检查包装类型是否为 null:
Integer num = null;
// 条件语句
int i = (num != null) ? num : 0;
使用显式拆箱的代码如下:
Integer num = null;
// 显示拆箱
int i = num != null ? num.intValue() : 0;
可以看出来,两者代码差不多,在这里其实 num
等价于 num.intValue()
。
最后这个代码没加括号是因为:在 Java 中,三目运算符(?:
)的优先级比赋值运算符(=
)高,而比相等运算符(==
)和不等运算符(!=
)低。因此,num != null
会先执行,代码可以不加括号而直接编写。