本文简述Java中基本类型的一些知识点,属于个人学习总结,能力有限,还望各位大神多多指点。
Abstract
There are two types of data in Java:
- primitive types: boolean, char, byte, short, int, long, float, and double.
- reference types: class, interface, and array.
We only discuss primitive types here.
Java有两种数据类型:
- 原生类型:boolean、char、byte、short、int、long、float和double。
- 引用类型:class、interface和array。
在这里我们只讨论原生类型。
Primitive types are not Java Objects, but each of them has a wrapper class. When a wrapper class instance is required, but relative primity type is provided, the primitive type can be converted to its wrapper class instance. This is called auto-boxing. A wrapper class instance can be converted to relative primitive type automatically when necessary, this is called auto-unboxing.
原生类型不是Java对象,但是他们都有各自的封装类。在需要的时候,原生类型和其包装类之间可以自动转换。
public class Test {
private static void testInt2Integer(Integer i) {
System.out.println(i);
}
private static void testInteger2Int(int i) {
System.out.println(i);
}
public static void main(String[] args) {
int i = 10;
Integer iObj = Integer.valueOf(20);
// 10
testInt2Integer(i);
// 20
testInteger2Int(iObj);
}
}
integers
char, byte, short, int, long are all integers actually. All integer literals can be represented as hexadecimal, decimal, octal, or binary. In addition, underscore _ can be added between digits for ease of reading, especially for values that have many digits.
char、byte、short、int、long都是整型,所有整型的值都可以表示为16进制、10进制、8进制和2进制。另外两个数字间可以添加下划线以便于阅读,尤其是对很长的值。添加下划线对数值没有任何影响,仅仅是为了人类阅读方便而已。
public class Test {
public static void main(String[] args) {
// hexadecimal representation starts with 0x or 0X. I prefer to use lowercase x and uppercase digits A ~ F.
byte b1 = 0x1F;
byte b2 = 0X1f;
// decimal representation doesn't have prefix and postfix.
short s1 = -123;
// octal representation starts with 0
int i1 = 07777;
// binary representation starts with 0b or 0B. I prefer to use lowercase b
// long literal has postfix l or L. I prefer to use uppercase L.
long l1 = 0b010101L;
long l2 = 0B010101l;
// It's better to add the postfix always. Because when postfix is omitted, actually it's casting an int to long.
// So, if an int can't hold the long value, compile error happens.
long l3 = 1234567890; // not recommended
long l4 = 12345678900L; // OK
long l5 = 12345678900; // compile error: The literal 12345678900 of type int is out of range
// add underscores
char c1 = 0x1_F;
char c2 = 12___34;
char c3 = 0_777;
char c4 = 0b1_111_111_111;
}
}
char
char represents Unicode code point in the Basic Multilingual Plane. Its value is 16-bit unsigned integer that encoded with UTF-16, and default value is the null code point (’\u0000’).
char用于表示Unicode中BMP码位,其值是16位无符号整型,采用UTF-16编码,其默认值为\u0000。
public class Test {
public static void main(String[] args) {
// Create char by Unicode escape
char c1 = '\u0041';
// Create char directly
char c2 = 'A';
// Create char by code point
char c3 = 65;
// Create Character object
Character cObj1 = Character.valueOf(c1);
}
}
更多信息可参考博文:https://blog.youkuaiyun.com/u011079896/article/details/89423756
int
int is 32-bit signed two’s-complement integer, and default value is zero.
int是32为有符号整型,默认值为0。
如何将String转换成int或Integer?
public class Test {
public static void main(String[] args) {
// get int from String in decimal format
int i1 = Integer.parseInt("123");
// get int from String in any valid radix
int i2 = Integer.parseInt("-123", 5);
// get Integer instance from String in decimal format
Integer iObj1 = Integer.valueOf("123");
// get Integer instance from String in any valid radix
Integer iObj2 = Integer.valueOf("-123", 5);
// get Integer instance from String in hexadecimal format
Integer iObj3 = Integer.decode("0x1F");
Integer iObj4 = Integer.decode("-0x1F");
// get Integer instance from String in hexadecimal format, but start with #.
// I don't know why it support this format.
// But one possible scenario is to parse color value.
Integer iObj5 = Integer.decode("#FF00FF");
// get Integer instance from String in octal format
Integer iObj6 = Integer.decode("-077");
Integer iObj7 = Integer.decode("123");
// there is no way to get integer instance from String in binary format
// so, I write one
Integer iObj8 = decode("0b11111111");
System.out.println(iObj8);
}
private static Integer decode(String str) {
if (str == null) {
throw new NumberFormatException("null");
}
if (str.length() > 2 && "0b".equalsIgnoreCase(str.substring(0, 2))) {
return Integer.parseInt(str.substring(2), 2);
} else if (str.length() > 3 && "0b".equalsIgnoreCase(str.substring(1, 3))) {
return Integer.parseInt(str.substring(0, 1) + str.substring(3), 2);
} else {
return Integer.decode(str);
}
}
}
Integer中一些位操作有关的方法。
public class Test {
public static void main(String[] args) {
int i = 0x12345678;
// 00010010001101000101011001111000
printInt(i);
// 01111000010101100011010000010010
printInt(Integer.reverseBytes(i));
// 00011110011010100010110001001000
printInt(Integer.reverse(i));
// 00010000000000000000000000000000
printInt(Integer.highestOneBit(i));
// 00000000000000000000000000001000
printInt(Integer.lowestOneBit(i));
// 01001000110100010101100111100000
printInt(Integer.rotateLeft(i, 2));
// 00000100100011010001010110011110
printInt(Integer.rotateRight(i, 2));
// 13
System.out.println(Integer.bitCount(i));
// 3
System.out.println(Integer.numberOfLeadingZeros(i));
// 3
System.out.println(Integer.numberOfTrailingZeros(i));
// 1
System.out.println(Integer.signum(i));
}
private static void printInt(int i) {
String s = Integer.toBinaryString(i);
System.out.println("0".repeat(32 - s.length()) + s);
}
}
byte
byte is 8-bit signed two’s-complement integer, and default value is zero.
byte是8位有符号整型,默认值为0。
将String转换成byte或Byte的方法是完全基于Integer中的实现,因此内部逻辑相同,不再赘述。
short
short is 16-bit signed two’s-complement integer, and default value is zero.
short是16位有符号整型,默认值为0。
将String转换成short或Short的方法是完全基于Integer中的实现,因此内部逻辑相同,不再赘述。
long
long is 64-bit signed two’s-complement integer, and default value is zero.
long是32位有符号整型,默认值为0。
将String转换成long或Long的方法与Integer中的实现类似,不再赘述。
floating point numbers
float and double are floating point numbers. They can be represented as scientific notation in hexadecimal, scientific notation in decimal and decimal. In addition, underscore _ can be added between digits for ease of reading, especially for values that have many digits.
float和double是浮点型,它们可以被表示成十进制,十进制科学记数法和十六进制科学记数法,但是不能单独表示成十六进制。另外下划线可以用于数字之间增加可读性。
public class Test {
public static void main(String[] args) {
// In decimal format.
// Postfix f/F indicates that it's float literal, and it can't be omitted.
// I'd like to use lowercase prefix and uppercase postfix.
float f1 = -1.234F;
// Scientific notation in decimal format.
float f2 = 1.234e5F;
// Scientific notation in hexadecimal format. Because e/E is digit in hexadecimal, so, use p/P in scientific notation.
float f3 = 0x1.FFp2F;
float f4 = 0X1.ffp2f;
// In decimal format.
// Postfix d/D indicates that it's double literal, and it can be omitted.
double d1 = -1.234D;
double d2 = -1.234;
// Scientific notation in decimal format.
double d3 = 1.234e5;
double d4 = 1.234E-5;
// Scientific notation in hexadecimal format.
double d5 = 0x1.FFp2D;
double d6 = 0X1.ffp2d;
float f5 = 0xA.FF_FFp2F;
double d7 = -3.2_34D;
}
}
在Float和Double中还定义了一些常量如NaN表示其不是一个数字,POSITIVE_INFINITY表示正无穷,NEGATIVE_INFINITY表示负无穷,等等。但是考虑到float和double的精度有限,在需要高精度的应用中,绝对不可以使用这两种类型,如金融类应用,天文类应用等。
boolean
boolean只有两个值:true和false。
将String解析成boolean时,只有“true”及其不区分大小写的变形会被解析成true,其它所有值都是false。
public class Test {
public static void main(String[] args) {
// true
System.out.println(Boolean.parseBoolean("TRue"));
// false
System.out.println(Boolean.parseBoolean(null));
// false
System.out.println(Boolean.parseBoolean(""));
// false
System.out.println(Boolean.parseBoolean("false"));
// false
System.out.println(Boolean.parseBoolean("something"));
}
}
前面介绍的数据类型都有定义其在内存中的长度,如int是32位。boolean占多少位?
关于这个问题,Java Language Specification中没有定义,因为在JVM中压根儿没有boolean这个数据类型,它实际上是被当作int处理的,通常情况下1表示true,0表示false。那有人说这就说明boolean也占了32位呗。可boolean[]又是当作byte[]处理的,而不是int[]。所以大家就不要纠结boolean到底占了多少位了,不同的JVM实现可能有不同的处理。大家也不要担心大量使用boolean会不会导致内存占用过高,除非你的内存使用量非常紧张,要按照bit来计算,如果真是那样,就不要用Java了。
boxing and unboxing
前面提到原生类型都有对应的包装类,在需要的时候会自动转换。这个功能和通用编程(Generics)关系比较大,在Geneircs中类型参数只能使用引用类型,不能使用原生数据类型。
那有人说是不是所有地方都用包装类,不用原生类型,这样就不再需要转换,性能会提高。其实不是的,一个原生类型的资源占用远低于其包装类,所以通常情况下还是应该尽可能使用原生类型。不排除某些业务逻辑下包装类的性能更高一些,具体问题具体分析吧。
一个有趣的例子
public class Test {
public static void main(String[] args) {
Integer iObj1 = 1;
Integer iObj2 = 1;
// true
System.out.println(iObj1 == iObj2);
Integer iObj3 = 130;
Integer iObj4 = 130;
// false
System.out.println(iObj3 == iObj4);
// true
System.out.println(iObj3.equals(iObj4));
int i1 = 130;
int i2 = 130;
// true
System.out.println(i1 == i2);
}
}
我们知道,==是用于比较内存地址,而equals方法则要看具体的实现逻辑了。
对于Integer来说,byte范围内的值,即-128~127,会被缓存起来,因此iObj1和iObj2实际上指向同一段内存,所以返回true。而iObj3和iObj4的值没有被缓存,因此是两个不同的对象,所以返回false。
所以在做对象比较的时候,切记要使用equals方法。
备注
本文所有代码在JDK 11上测试通过。
本文主要探讨Java中的原始数据类型,包括boolean、char、byte、short、int、long、float和double,以及它们的包装类之间的自动装箱和拆箱。文章详细介绍了各种类型的特点,如int是32位带符号的二补数整数,默认值为0;char表示Unicode基本多文种平面的代码点,是16位无符号整型。此外,还提到了浮点数的表示方式和boolean类型的特性。
2683

被折叠的 条评论
为什么被折叠?



