Java基本数据类型一览表
原生类型 | 占位数 | 是否有符号位 | 最小值 | 最大值 | 默认值 | 包装类 | 备注 |
---|---|---|---|---|---|---|---|
boolean | 1 | 无 | —— | —— | false | Boolean | boolean类型是孤独的皇后,她无法和其他类型转换 |
byte | 8 | 有 | -2^7=-128=Byte.MIN_VALUE | 2^7-1=127=Byte.MAX_VALUE | 0 | Byte | IO流中经常使用 |
char | 16 | 无 | ‘\u0000’=0=Character.MIN_VALUE | ‘\uFFFF’=2^15*2-1=65535=Character.MAX_VALUE | ‘\u0000’ | Character | |
short | 16 | 有 | -2^15=Short.MIN_VALUE | 2^15-1=Short.MAX_VALUE | 0 | Short | 历史遗留类型,不再被使用 |
int | 32 | 有 | -2^31=Integer.MIN_VALUE | 2^31-1=Integer.MAX_VALUE | 0 | Integer | |
long | 64 | 有 | -2^63=Long.MIN_VALUE | 2^63-1=Long.MAX_VALUE | 0 | Long | 在int无法存储的情况下使用 |
float | 32 | 有 | 1.4E-45f=Float.MIN_VALUE | 3.4028235E38=Float.MAX_VALUE | 0.0f | Float | 在对内存要求高对精度要求不高时使用 |
double | 64 | 有 | 4.9E-324=Double.MIN_VALUE | 1.7976931348623157E308==Double.MAX_VALUE | 0.0d | Double |
表说明:
1.nEm表示n*10的m次方,nE-m表示n*10的m次方分之一。
2.Java核心技术卷一是说:“Java没有任何无符号类型”是错的,事实上boolean和char确实是无符号类型。
3.Java核心技术卷一上标明了float类型的取值范围是±3.40282347E38明显写错了。
字符相关知识
代码单元就是char类型的数值范围,0-65535都是代码单元。
代码点就是超出65535的代码单元,这时由于char类型的最大值限制,导致char无法表示一个大于65535的字符。
为解决这个问题,开发JavaAPI的攻城狮就将大于65535的字符统一用两个代码单元(0-65535)表示,并且规定,这两个代码单元是好基友,是一个整体,我们就叫它们代码点好了!
为了将所有字符都有统一的名字,API的攻城狮也是蛮拼的,攻城狮们干脆再规定,0-65535的代码单元也可以叫代码点!
以下为代码单元和代码点的操作代码:
char[] c = Character.toChars(65536);
String str = new String(c);
System.out.println("我是一个代码点,不信你看: " + str.codePointCount(0, str.length()));// 1
System.out.println("我是这个代码点数值为:" + str.codePointAt(0));
System.out.println("我是两个代码单元,不信你看: " + str.length());
System.out.println("我是第一个代码单元:" + (int) str.charAt(0));
System.out.println("我是第一个代码单元:" + (int) str.charAt(1));
String test = "A" + str + "B";
for (int i = 0; i < test.length(); i++) {
System.out.println("遍历字符串的代码单元是这样干的:" + (int) test.charAt(i));
}
for (int i = 0; i < test.length(); i++) {
int codePoint = test.codePointAt(i);
System.out.println("遍历字符串的代码点是这样干的:" + codePoint);
if (Character.isSupplementaryCodePoint(codePoint)) {
i++;
}
}
为什么不建议使用char?
String c1=””;//数学上的整数集符号,这个符号无法用char表示,因为它超出65535了,所以只能采用是两个char(代码单元)表示。
String str=c1+”A”;
char c2=str.chartAt(1);
结果c2不是你想要的’A’,而是的后半个字符(代码单元)。
代码单元代码点相关的详细资料请查看:
Java如何存储负数
1.如何存储负数
Java是采用”2的补码”(简称补码)存储负数的。
如8位的数字00000001表示正数1,11111111示负数1。
2.补码
补码是基于有符号位的(基于置符号位的),正数的补码等于数字本身(这句话要这样理解:并不是正数的补码等于本身,而是正数不需要计算它的补码,正数计算的补码是给负数用的,所以规定正数的补码等于本身)。
3.”2的补码”
“2的补码”是将一个数的反码+1。
4.反码
反码就是将数字的二进制位全部取反,0变成1,1变成0,正数的反码等于数字本身(这句话要这样理解:并不是正数的反码等于本身,而是正数不需要计算它的反码,正数计算的反码是给负数用的,所以规定正数的反码等于本身)。
如00000001的反码就是11111110。
5.”1的补码”
“1的补码”不用细究它,因为”1的补码”的结果和反码一致,只是它采用的不是”二进制位全部取反“的操作方式。我们不用管它是怎么算的,直接将它理解成反码就对了。
6.置符号位
数字置符号位是二进制中表示正负的方法,一个数字的最高位就是符号位,如果符号位为0表示正,如果符号位为1表示负。
7.直观表示法
直观便于理解的表示二进制负数的形式是置符号位,不需要采用补码。
如8位的数字00000001表示正数1,10000001示负数1。
8.为什么采用补码表示负数
之所以采用补码表示负数,而不是直接采用直观便于理解的置符号位,是因为在计算机中直观表示在做负数运算是不能得到正确的结果,而补码却可以做到。
如:
数00000001(数字1的直观表示法)
+10000001(数字-1的直观表示法)
=10000010(数字-2的直观表示法)
很明显1+(-1)=0而不是-2啊!!!
而采用补码方式却可以得到正确的结果:
数00000001(数字1的补码表示法)
+11111111(数字-1的补码表示法)
注意此时只有8位,超过8位会溢出,所以:
=00000000(数字0的补码表示法)
基本类型转换
1.boolean与其他任何类型都不兼容。
2.小类型向大类型转换时,如果小类型不是char类型,那么就执行无符号扩展,如果小类型是char那么永远执行无符号扩展。
有符号扩展:
byte b=”00000001”;
short s=b;//此时s的值为0000000000000001
byte b=”11111111”;//11111111是byte类型-1的补码形式
short s=b;//此时s的值为1111111111111111,1111111111111111是short类型-1的补码形式。
无符号扩展:
char c=”1111111111111111”;
int i=c;//此时i的值为00000000000000001111111111111111。
char c=”0000000000000001”;
int i=c;//此时i的值为00000000000000000000000000000001。
3.大类型向小类型转换时需要强制转换。
浮点类型相关知识
1.浮点类型的存储范围很大
float虽然和int占位一样,但float能存储的值比int大太多,可以参见Integer.MAX_VALUE和Float.MAX_VALUE,不但如此,float比long都大很多,另外double又比float更大。 所以,long存放不了的数字可以存放在float,float放不下的数字可以放入double中。
2.浮点类型无法完全精确表示小数
float和double在计算时都不是完全精确的,float能精确到6位或7位小数,double能精确到15位小数。
超出范围的小数会被四舍五入。
例如:
System.out.println(1.0f/0.3f);
System.out.println(2.0f/0.3f);
System.out.println(1.0d/0.3d);
System.out.println(2.0d/0.3d);
打印:
3.3333333
6.6666665
3.3333333333333335
6.666666666666667
3.二进制无法精确表示一些可以在10进制精确表示的小数
二进制无法精确表示十进制中的一些数,就像十进制无法精确表示1/3一样,二进制无法精确表示0.1等等各种小数。
(以下是复制的)
二进制表示小数的时候只能够表示能够用1/(2^n)的和的任意组合。
例如:
0.5能够表示,因为它可以表示成为1/2。
0.75也能够表示,因为它可以表示成为1/2+1/(2^2)。
0.875也能够表示,因为它可以表示成为1/2+1/(2^2)+1/(2^3)。
0.1不能够精确表示,因为它不能够表示成为1/(2^n)的和的形式。
4.浮点类型在计算时容易出现偏差
原因有两点:
1.因为浮点类型的精度都是固定的,超出范围的精度会被四舍五入。
2.因为二进制无法精确表示十进制中的一些数,所以你会看到很奇怪的结果,如:
System.out.println(1.0-0.93);
System.out.println(1.0-0.7);
System.out.println(1.1-1.0);
打印:
0.06999999999999995//计算机无法表达0.07
0.30000000000000004//计算机无法表达0.3
0.10000000000000009//计算机无法表达0.1
要想使用完全精确的计算请使用BigDecimal,并且是BigDecimal(String val)这个构造方法。
5.不要使用==判断两个浮点数的大小
对于浮点类型之间的大小判断,不应该使用==,而只能使用>、<、>=、<=,愿意上面第4点已经说了。
示例:
float f1=1.345f;
float f2=1.123f;
System.out.println(f1+f2-f2==f1);//打印false
了解浮点数详细信息请查看:你的小数点去哪了
二进制浮点数和十进制浮点数相互转换
十进制转二进制:
整数部分,看图:
小数部分,看图:
二进制转十进制:
二进制转十进制比较简单,将二进制的所有面值乘以2的“字面值对应的权系”次方相加,语言不太好表达,看公式:
n1*(2^m2)+n2*(2^m2)+n3*(2^m3)+…
例如:
1101.01=1*2(2^3) +1*2(2^2)+0*(2^1)+1*(2^0)+0*(2^-1)+1*(2^-2)=8+4+0+1+0+0.25=13.25。