JavaSE-Adventure (I) : Java Data Type
CONTENTS
基本数据类型 (primitive type) & 包装数据类型 (wrapped type)
- 基本数据类型
- 整数类型:
- byte(1 byte), short(2 bytes), int(4 bytes), long(8 bytes)
- 浮点类型:
- float(4 bytes), double(8 bytes)
- 字符类型:
- char(2 bytes)
- 布尔类型:
- boolean(1 byte)
- 整数类型:
- 包装数据类型:
- 整数类型:
- Byte, Short, Integer, Long
- 浮点类型:
- Float, Double
- 字符类型:
- Character
- 布尔类型:
- Boolean
- 整数类型:
自动装箱/拆箱 (auto boxing/unboxing)
Auto Boxing
Integer i = 10;
L1
LINENUMBER 8 L1
ALOAD 0
BIPUSH 10
INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;
PUTFIELD AutoBoxTest.i : Ljava/lang/Integer;
根据字节码可以看出, 字面量 10 赋值给 Integer 实际会调用Integer 的静态方法:Integer.valueOf (I);
Auto Unboxing
int n = Integer.valueOf(10);
L2
LINENUMBER 9 L2
ALOAD 0
ALOAD 0
GETFIELD AutoBoxTest.i : Ljava/lang/Integer;
INVOKEVIRTUAL java/lang/Integer.intValue ()I
PUTFIELD AutoBoxTest.n : I
从字节码能看出, 拆箱实际是调用了 xx.intValue()
常见问题
-
当封装类与基础类型进行 ==、+、-、*、/ 运算时,封装类会进行拆箱,拆箱结果与基础类型对比值;
-
而两个封装类进行 == 运算时,与其它的对象的比较一样,对比两个对象的地址,也即判断是否两个引用是否指向同一个对象
范例一:
Integer integer400 = 400;
int int400 = 400;
System.out.println(integer400 == int400); // true
== 运算, integer400 拆箱, 结果为true
范例二:
Integer integer100 = 100;
int int100 = 100;
System.out.println(integer100.equals(int100)); // true
根据方法参数列表的类型自动选择 装箱or拆箱, 结果为int装箱, true
范例三:
Integer integer100 = null;
int int100 = integer100; // NullPointerException
编译期不会报错
运行时:NullPointerException
问题:int int100 = integer100;
integer100 自动拆箱时,null.intValue()
包装数据类型常量池技术
// 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 = 33;
Integer i2 = 33;
System.out.println(i1 == i2);// 输出 true
Integer i1 = 40; // auto boxing
Integer i2 = new Integer(40); // store heap
System.out.println(i1==i2); // false
缓存 (cache)
整数类型缓存:
Integer:
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
Short:
public static Short valueOf(short s) {
final int offset = 128;
int sAsInt = s;
if (sAsInt >= -128 && sAsInt <= 127) { // must cache
return ShortCache.cache[sAsInt + offset];
}
return new Short(s);
}
Byte:
public static Byte valueOf(byte b) {
final int offset = 128;
return ByteCache.cache[(int)b + offset];
}
Long:
public static Long valueOf(long l) {
final int offset = 128;
if (l >= -128 && l <= 127) { // will cache
return LongCache.cache[(int)l + offset];
}
return new Long(l);
}
Character 缓存:
public static Character valueOf(char c) {
if (c <= 127) { // must cache
return CharacterCache.cache[(int)c];
}
return new Character(c);
}
扩展:字符、字符集、字符编码
字符(Character)
字符是各种文字和符号的总称,包括各国家文字、标点符号、图形符号、数字等。
字符集(Character set)
字符集是一个系统支持的所有抽象字符的集合。通常以二维表的形式存在,二维表的内容和大小是由使用者的语言而定。如ASCII,GBxxx,Unicode等。
字符编码(Character encoding)
字符编码是把字符集中的字符编码为特定的二进制数,以便在计算机中存储。每个字符集中的字符都对应一个唯一的二进制编码。
字符集和字符编码一般都是成对出现的,如ASCII、IOS-8859-1、GB2312、GBK,都是即表示了字符集又表示了对应的字符编码。Unicode比较特殊,有多种字符编码(UTF-8,UTF-16等)
ASCII字符集&编码
ASCII码为单字节,用7位二进制数表示,由于计算机1个字节是8位二进制数,所以最高位为0,即00000000-01111111或0x00-0x7F。
GB2312字符集&编码
GB 2312中对所收汉字进行了“分区”处理,每区含有94个汉字/符号。这种表示方式也称为区位码。
01–09区为特殊符号。
16–55区为一级汉字,按拼音排序。
56–87区为二级汉字,按部首/笔画排序。
举例来说,“啊”字是GB 2312之中的第一个汉字,它的区位码就是1601。
10–15区及88–94区则未有编码。
编码格式:
在使用GB 2312的程序通常采用EUC储存方法,以便兼容于ASCII。
每个汉字及符号以两个字节来表示。第一个字节称为“高位字节”,第二个字节称为“低位字节”。
“高位字节”使用了0xA1–0xF7(把01–87区的区号加上0xA0),“低位字节”使用了0xA1–0xFE(把01–94加上0xA0)。 由于一级汉字从16区起始,汉字区的“高位字节”的范围是0xB0–0xF7,“低位字节”的范围是0xA1–0xFE,占用的码位是72*94=6768。其中有5个空位是D7FA–D7FE。
GBK字符集&编码
GBK 亦采用双字节表示,总体编码范围为8140-FEFE,首字节在81-FE 之间,尾字节在40-FE 之间,剔除 xx7F一条线。
GBK向下完全兼容GB2312-80编码。支持GB2312-80编码不支持的部分中文姓,中文繁体,日文假名,还包括希腊字母以及俄语字母等字母。不过这种编码不支持韩国字,也是其在实际使用中与unicode编码相比欠缺的部分。
GB 18030字符集&编码
此标准内的单字节编码部分、双字节编码部分,和四字节编码部分收录的中日韩统一表意文字扩展A区汉字,为强制性标准。其他部分则属于规模性标准。在中华人民共和国境内所有软件产品,都需要支持这个同时包含单字节、双字节和四字节编码的规格。
GB 18030主要有以下特点:
- 和UTF-8一样都采用多字节编码,每个字可以由1个、2个或4个字节组成。
- 编码空间庞大,最多可定义161万个字元。
- 支持中国国内少数民族的文字,不需要动用造字区。
- 汉字收录范围包含繁体汉字以及日韩汉字。
编码方式:
单字节,其值从0x00到0x7F。
双字节,第一个字节的值从0x81到0xFE,第二个字节的值从0x40到0xFE(不包括0x7F)。
四字节,第一个字节的值从0x81到0xFE,第二个字节的值从0x30到0x39,第三个字节从0x81到0xFE,第四个字节从0x30到0x39。
Unicode字符集&编码
UTF-8
UTF-8的特点是对不同范围的字符使用不同长度的编码。
上表表示如何从一个从Unicode 转化到UTF-8 , 对于前0x7F的字符,UTF-8编码和ASCII码是一一对应的。如果一个字符在000800-00FFFF 之间,那转化到UTF-8 需要用三字节模板,使用16个码位,每个x 就是一个码位。
Java 与 字符: 内码与外码
内码:程序内部使用的字符编码,如java的char,所以java的char是2字节16位;
外码:程序外部交互时使用的字符编码,如class文件。
参考:
字符与编码:https://blog.csdn.net/kuji86/article/details/108783783
Java 与 编码:https://segmentfault.com/a/1190000023345905