基本数据类型和包装类
这是我参与新手入门的第2篇文章
Java 是 一种强类型语言。这就意味着必须为每一个变量声明一种类型: 在 Java 中,一共有 8
种基本类型( primitive type ),其中有 4 种整型、2 种浮点类型、 1 种用于表示 Unicode 编码的字符
单元的字符类型 char 和 1 种用于表示真值的 boolean 类型。
整型
整型用于表示没有小数部分的数值, 它允许是负数。Java 提供了 4 种整型
类型 | 存储需求 | 取值范围 |
---|---|---|
byte | 1字节 | -128~127(-2^7 ~ 2^7 – 1) |
short | 2字节 | -32768~32767 (-2^15 ~ 2^15 – 1) |
int | 4字节 | -2 147 483 648 – 2 147 483 647 (正好超过 20 亿)(-2^31 ~ 2^31 – 1) |
long | 8字节 | -2^63 ~ 2^63 – 1 |
浮点型
浮点类型用于表示有小数部分的数值。在 Java 中有两种浮点类型
类型 | 存储需求 | 符号位S | 指数位E | 尾数位M |
---|---|---|---|---|
float | 4字节 | 1bit | 8bit | 23bit |
double | 8字节 | 1bit | 11bit | 52bit |
- 符号位:0表示正数,1表示负数;
- 指数位:值范围为[2^-127, 2^128].
- 尾数位:形式为1.M或0.M。其中当E=0时,取1.M,称为正规形式,当E!= 0时,取0.M,称为非正规形式。
- 尾数代表的是2的负数次方,使用二进制的科学计数法近似表示十进制科学计数法。对于float来说,尾数最小值2^-23只能近似表示10^-7,所以只能精确表示6、7位小数。对于double来说,尾数最小值2^-52只能近似表示10^-16,只能精确表示15、16位小数。
定义
定义float类型,数值后面必须加后缀F或者f。没有后缀的浮点数值默认是double类型,也可以加D或者d。
float f1 = 3.14F;
float f2 = 3.14f;
double d = 3.14;
double d1 = 3.14D;
double d2 = 3.14d;
复制代码
char类型
Java中char使用Unicode字符集,占2个字节,16位,用来表示单个字符。
定义
char c1 = 'a'; //任意单个字符,加单引号。
char c2 = '汉'; //任意单个中文字,加单引号。
char c3 = 126; //整数。0~65535。十进制、八进制、十六进制均可。输出字符编码表中对应的字符。
char c4 = '\u26c5'; // 范围从\u0000 到 \uffff
System.out.println(c1); // a
System.out.println(c2); // 汉
System.out.println(c3); // ~
System.out.println(c4); // ⛅
复制代码
boolean类型
boolean (布尔)类型有两个值:false 和 true, 用来判定逻辑条件 整型值和布尔值之间不能进行相互转换。
boolean到底占几个字节?
《Java虚拟机规范》一书中的描述:虽然定义了boolean这种数据类型,但是只对它提供了非常有限的支持。在Java虚拟机中没有任何供boolean值专用的字节码指令,Java语言表达式所操作的boolean值,在编译之后都使用Java虚拟机中的int数据类型来代替,而boolean数组将会被编码成Java虚拟机的byte数组,每个元素boolean元素占8位”。这样我们可以得出boolean类型占了单独使用是4个字节,在数组中又是1个字节。
类型转换和不同类型运算
类型转换
6 个实心箭头,表示无信息丢失的转换;有 3 个虚箭头, 表示可能有精度损失的转换。如果反过来,long要转成int,就需要使用强制类型转换(cast)
byte b = 1;
short s = 2;
int i = 3;
long l = 1000;
float f = 1.1f;
double d = 3.1415926;
s = b;
i = (int) l;
f = i;
f = (float) d;
复制代码
不同类型运算
- 如果两个操作数中有一个是 double 类型, 另一个操作数就会转换为 double 类型。
- 否则,如果其中一个操作数是 float 类型,另一个操作数将会转换为 float 类型。
- 否则, 如果其中一个操作数是 long 类型, 另一个操作数将会转换为 long 类型。
- 否则, 两个操作数都将被转换为 int 类型。
- 在JAVA中,对char类型字符运行时,直接当做ASCII表对应的整数来对待。
byte b = 1;
short s = 2;
int i = 3;
long l = 1000;
float f = 1.1f;
double d = 3.1415926;
char c = '中';
double d2 = b + d; // 4.1415926
float f2 = s + f; // 3.1
long l2 = i + l; // 1003
int i2 = c + i; // 20016
char c2 = (char) (c + i); // 丰
复制代码
包装类型
有时, 需要将 int 这样的基本类型转换为对象。 所有的基本类型都有一个与之对应的类。对象包装器类是不可变的,即一旦构造了包装器,就不允许更改包装在其中的值。同时, 对象包装器类还是 final , 因此不能定义它们的子类。
基本数据类型与包装类型对应关系
基本类型 | 包装类型 |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
char | Character |
boolean | Boolean |
自动装箱和拆箱
装箱就是自动将基本数据类型转换为包装器类型;拆箱就是自动将包装器类型转换为基本数据类型。在算术表达式中也能够自动地装箱和拆箱。
Integer i1 = 3; //自动自动装箱,编译器将这一句翻译成了 Integer i = Integer.valueOf(3);
int i2 = i1; // 自动拆箱,编译器将这一句翻译成 int i2 = i1.intValue();
复制代码
初始值
- 整型初始值是0
- 浮点型初始值是0.0
- char初始值是空格
- boolean初始值是false
- 包装类型全是null
class Obj{
short s;
byte b;
int i;
long l;
float f;
double d;
char c;
boolean bool;
Short so;
Byte bo;
Integer io;
Long lo;
Float fo;
Double dou;
Character co;
Boolean boolo;
}
Obj{s=0, b=0, i=0, l=0, f=0.0, d=0.0, c= , bool=false, so=null, bo=null, io=null, lo=null, fo=null, dou=null, co=null, boolo=null}
复制代码
大小比较
Integer i1 = 1;
Integer i2 = 1;
Integer i3 = 128;
Integer i4 = 128;
System.out.println(i1 > i2); // false
System.out.println(i1 == i2); // true
System.out.println(i1.compareTo(i2)); // 0
System.out.println(i3 == i4); // false
System.out.println(i3.equals(i4)); // true
复制代码
- 使用>,<,>=,<=等进行比较时,包装类自动拆箱然后比较
- 包装类的大小比较使用compareTo方法,小于返回-1,等于返回0,大于返回1
- 包装类使用==比较的是对象地址,equals比较对象值
- Java 基本类型的包装类的大部分都实现了常量池技术,即 Byte,Short,Integer,Long,Character,Boolean;前面 4 种包装类默认创建了数值[-128,127] 的相应类型的缓存数据,Character创建了数值在[0,127]范围的缓存数据,Boolean 直接返回True Or False。如果超出对应范围仍然会去创建新的对象。
/**
* Integer 缓存相关代码
*/
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
复制代码
计算
包装类参与计算时会自动拆箱后进行计算,计算后的结果装箱时,如果在常量池中,不会创建新对象。如果不在常量池中就会创建新对象。
Integer i1 = 1;
Integer i2 = 1;
Integer i11 = 2;
Integer i3 = 127;
Integer i33 = i3 + 1;
Integer i4 = 127;
Integer i44 = i4 + 1;
Integer i5 = 128;
Integer i6 = i5 - i1;
System.out.println(i11 == i1 + i2); // true
System.out.println(i1 + 1 == i2 + 1); // true
System.out.println(i3 == i4); // true
System.out.println(i3 + 1 == i4 + 1); // true
System.out.println(i33 == i44); // false
System.out.println(i3 == i6); // true
复制代码
基本数据类型与包装类型比较
- 在Java中,一切皆对象,但八大基本类型却不是对象。
- 基本类型的优势:数据存储相对简单,运算效率比较高。
- 包装类的优势:有的容器,比如集合的元素必须是对象类型,满足了java一切皆是对象的思想。
- 声明方式的不同,基本类型无需通过new关键字来创建,而封装类型需new关键字。
- 存储方式及位置的不同,基本类型是直接存储变量的值保存在堆栈中能高效的存取,封装类型需要通过引用指向实例,具体的实例保存在堆中。
- 初始值的不同,封装类型的初始值为null,基本类型的的初始值视具体的类型而定,比如int类型的初始值为0,boolean类型为false。
- 使用方式的不同:如与集合类合作使用时只能使用包装类型。