数据类型
Java 的数据类型分为:布尔(boolean)类型、字符类型和数值类型,其中数值类型又可以细分为:整数类型 和 浮点类型;
基本 类型 | 包装类 | 字节数 | 位数 | 最小值 | 最大值 | 默认值 |
---|---|---|---|---|---|---|
byte | Byte | 1 | 8 | -2^7(-128) | 2^7 - 1(127) | (byte)0 |
short | Short | 2 | 16 | -2^15 | 2^15 - 1 | (short)0 |
int | Integer | 4 | 32 | -2^31 | 2^31 - 1 | 0 |
long | Long | 8 | 64 | -2^63 | 2^63 - 1 | 0L |
float | Float | 4 | 32 | 1.4E - 4 (2^-149) | 3.4028235E38 (2^128 - 1) | 0.0f |
double | Double | 8 | 64 | 4.9E - 324 (2^-1074) | 1.7976931348623157E308(2^1024-1) | 0.0d |
char | Character | 2 | 16 | \u0000 | \uFFFF | '/uoooo'(null) |
boolean | Boolean | 1 | 8 | 0(false) | 1(true) | false |
基本数据类型声明
byte byteData;
short shortData;
int intData;
long longData;
float floatData;
double doubleData;
char charData;
boolean booleanData;
byte
一个byte类型整数在内存里占8位,表数范围是 -128(-2^7)
~ 127(2^7-1)
。
特点:空间占用小,仅为 int 类型的1/4
byte a = -128;
byte b = 127;
short
一个 short 类型整数在内存里占 16 位,表数范围是 -32768(-2^15)
~ 32767(2^15-1)
。
特点:空间占用较小,仅为 int 类型的 1/2
short a = -32768;
short b = 32767;
int
一个 int 类型整数在内存里占 32 位,取值范围是 -2147483648(-2^31)
~ 2147483647(2^31-1)
。
特点:int 是最常用的整数类型,默认情况下,给一个整数,默认就是 int 类型,如果数值比较小,然后用 byte 或者 short 赋值,系统就会整数当作 byte 或者 short 来处理;
int min = -2147483648;
Integer max = 2147483647;
System.out.println(min);
System.out.println(max);
System.out.println(Integer.MIN_VALUE);
System.out.println(Integer.MAX_VALUE);
输出:
-2147483648
2147483647
-2147483648
2147483647
long
一个 long 类型整数在内存里占64位,表数范围是 -9223372036854774808(-2^63)
~ 9223372036854774807(2^63-1)
。
默认情况下,系统会将数值当作 int 来处理,当数超过了 int 的表示范围,系统并不会自动转换为 long 型,因此,如果需要一个 long 类型的数值,可以在数值后面添加一个l或者L后缀(l容易和1混淆,所以一般都使用L作为后缀)
long min = -9223372036854774808L;
Long max = 9223372036854775807L;
System.out.println(min);
System.out.println(max);
System.out.println(Long.MIN_VALUE);
System.out.println(Long.MAX_VALUE);
输出:
-9223372036854774808
9223372036854775807
-9223372036854774808
9223372036854775807
浮点数
Java使用IEEE 754浮点标准存储实数。支持两种浮点类型,分别是:float型、double型。
浮点表示法,分为三大部分:
第一部分用来存储符号位(sign)占用1位,用来表示正负数;
第二部分用来存储指数(exponent);
第三部分用来存储尾数(mantissa)。
float
float 用来表示单精度浮点数,内存分配 4 个字节,占 32 位,取值范围在 2^-149
~ 2^128 - 1
;指数占用 8 位,位数占用 23 位,用来表示小数,不足位数补 0;
Java 定义float类型时,可以在数值类型后面添加f或F后缀;
float min = 1.4E-45F;
Float max = 3.4028235E38F;
System.out.println(min);
System.out.println(max);
System.out.println(Float.MIN_VALUE);
System.out.println(Float.MAX_VALUE);
输出:
1.4E-45
3.4028235E38
1.4E-45
3.4028235E38
double
double 用来表示双精度浮点数,内存分配 8 个字节,占 64 位,取值范围在 2^-1074
~ 2^1024-1
;指数占用 11 位,位数占用 52 位,用来表示小数,不足位数补 0;
double min = 4.9E-324D;
Double max = 1.7976931348623157E308D;
System.out.println(min);
System.out.println(max);
System.out.println(Double.MIN_VALUE);
System.out.println(Double.MAX_VALUE);
输出:
4.9E-324
1.7976931348623157E308
4.9E-324
1.7976931348623157E308
char
字符型数据类型;用于存放单个字符。定义的时候使用单引号(' '
)表示;char在 Java 中是 16 位,因为 Java 用的是 Unicode ,因此一个 16 位的编码所能产生的字符只有65536个。
char a = '\u4e00'; // 一
System.out.println(a); // 一
char[] b = {'\u4e00', '\u884c', '\u004a', '\u0061', '\u0076', '\u0061'}; // 一行Java 的Unicode 编码
System.out.println(b); // 一行Java
System.out.println(new String(b)); // 一行Java
输出:
一
一行Java
一行Java
boolean
boolean 是只具有两个值的的数据类型,用来表示逻辑判断的真与假;Java 中 boolean 的值为 true 或 false
boolean t = Boolean.TRUE;
Boolean f = Boolean.FALSE;
System.out.println(t);
System.out.println(f);
System.out.println(1 > 2);
System.out.println(1 > 0);
输出:
true
false
false
true
基本类型转换
Java 的7种不同数据类型的值之间,是可以进行转换的;实际开发过程中,这种转换也经常会遇到;
在 Java 程序中,类型转换的方式有两种:
- 自动类型转换
- 强制类型转换
自动类型转换
上面我们学习过不同的数据类型,每种不同类型的值所表示的范围是不一样的,如果将一个表示范围小的值赋给一个表示范围更大的类型,系统就能直接进行自动转换;
好比将一个小号杯子中的水倒入到一个大杯中,小杯中的水都能够正常装入到大的杯子,也不会洒出来;
以下是支持自动转换的顺序:
基本数据类型的自动转换
javabyte a = 10; int b = a; long c = a; System.out.println(b); // 10 System.out.println(c); // 10
字符串类型的自动转换
示例可以看出,当一个基本数据类型和一个String类型相加时,系统会将基本数据类型自动转换为字符串类型进行拼接;
javabyte a = 10; int b = a; String d = "一行Java" + b; System.out.println(b); // 10 System.out.println(d); // 一行Java10
强制类型转换
如果将上面自动类型转换的顺序反过来,也就相当于将大杯中的水往小杯中倒时,就需要进行强制转换;如果本身的值超过了转后类型的取值范围,就会产生溢出,造成数据丢失;
基本数据类型的强转
javaint a1 = 50; // int 的值没有超出byte的取值范围,强转之后,不会出现数据丢失 byte b1 = (byte) a1; System.out.println(b1); // 50 // 以下是超出取值范围的情况 // 转换之后符号位为负数的情况 int a2 = 500; byte b2 = (byte) a2; System.out.println(b2); // -12 // 转换之后符号位为正数的情况 int a3 = 865; byte b3 = (byte) a3; System.out.println(b3); // 97
以下是
500
和865
的强转过程:字符串转换
上面介绍自动转换时,基本数据类型和字符串类型拼接的时候,会自动将基本数据类型转换为字符串类型,但字符串类型是没办法强制转换为基本数据类型;
java// 以下代码是会报错的 int a = (int)"1";
因此,只能借助基础类型包装类中的
valueOf
方法,将字符串转换为基础数据类型javaSystem.out.println(Byte.valueOf("10")); //10 System.out.println(Short.valueOf("100")); //100 System.out.println(Integer.valueOf("1000")); //1000 System.out.println(Long.valueOf("100000000000000000")); //100000000000000000 System.out.println(Float.valueOf("1.23")); //1.23 System.out.println(Double.valueOf("4.56")); //4.56 System.out.println(Boolean.valueOf("true")); //true
如果出现不符合转换要求的字符串或者超过取值范围的字符串,就会报转换错误:
javaSystem.out.println(Byte.valueOf("一行Java")); // 异常如下 Exception in thread "main" java.lang.NumberFormatException: For input string: "一行Java" at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:65) at java.base/java.lang.Integer.parseInt(Integer.java:652) at java.base/java.lang.Byte.parseByte(Byte.java:152) at java.base/java.lang.Byte.valueOf(Byte.java:208) at java.base/java.lang.Byte.valueOf(Byte.java:234) at main.DataType.main(DataType.java:12)
javaSystem.out.println(Byte.valueOf("1000")); // 异常如下 Exception in thread "main" java.lang.NumberFormatException: Value out of range. Value:"1000" Radix:10 at java.base/java.lang.Byte.parseByte(Byte.java:154) at java.base/java.lang.Byte.valueOf(Byte.java:208) at java.base/java.lang.Byte.valueOf(Byte.java:234) at main.DataType.main(DataType.java:12)
表达式的类型提升
当出现多个类型的值参与运算时,会出现类型的提升的情况
当byte、short、char 参与运算时,会自动将类型提升为 int
以下示例中将
byte
的a加2时,a被提升为了 int,将计算结果再赋值给 byte 类型的a时,就会报错了javabyte a = 2; // 由于运算的过程中,a被自动提升为int,计算出来的结果也就是int类型 // 再将一个int类型的值赋值给byte类型的a,就会报错 a = a + 2; // 如果想不报错,只能做强制类型转换,或者用int接收 a = (byte)(a + 2); // 或者 int b = a + 2;
算术表达式的所有类型将自动提升为参与表达式的最高类型,类型提升顺序请参考
当表达式中有多个数据类型时,会将低类型的数据提升为最高类型的数据进行运算;
以下示例,由于最高类型是float,将所有元素全部提升为 float 参与运算,得到的结果也就是 float 类型
javabyte a = 1; int b = 2; float c = 3.1F; float d = a + b + c; System.out.println(d); // 6.1
以下示例,哪怕
3/2
正确结果应该是double类型的 1.5 ,但由于表达式中最高类型为 int,使得数据强转丢失,导致计算出来的结果为 int 类型的1
javaint a = 3; int b = a/2; //1
基础类型和包装类型的区别
基础数据类型都会对应一个包装类,那他们之间有些什么区别呢?
- 包装类是对象,拥有方法和字段,对象的调用都是通过引用对象的地址;基本类型不是
- 包装类型是引用的传递;基本类型是值的传递
- 声明方式不同:
- 基本数据类型不需要new关键字,直接赋值,如:
int a = 10;
; - 包装类型需要new在堆内存中进行new来分配内存空间,如:
Integer a = new Integer(10);
- 基本数据类型不需要new关键字,直接赋值,如:
- 存储位置不同:
- 基本数据类型直接将值保存在值栈中;
- 包装类型是把对象放在堆中,然后通过对象的引用来调用他们
- 初始值不同:
- 基础数据类型会赋对应类型的初始值,
如:int初始值为:0
boolean的初始值为:false
double初始值为:0.0
- 包装类型的初始值为null
- 基础数据类型会赋对应类型的初始值,
- 使用方式不同:
- 基本数据类型直接赋值使用就好;
- 包装类型一般可以放在集合中使用,如 Collection集合中List、Set,以及Map键值对存储。
什么是装箱和拆箱?
装箱
就是自动将基本数据类型转换为包装器类型;原理是调用包装类的valueOf方法,如:
Integer.valueOf(1)
、Boolean.valueOf(true)
...拆箱
就是自动将包装器类型转换为基本数据类型;原理是是调用包装类的xxxValue方法(xxx表示类型),如:
javapublic boolean booleanValue() { return value; }