在编程的这个世界当中,要是选择了错误的数据类型,那么就有可能致使内存出现浪费的情况,还可能造成计算精度的丢失,甚至会引发系统崩溃的状况。Java身为一门强类型语言,它的八大基本数据类型以及引用类型恰当使用与否,径直就决定了程序的性能以及稳定性。本篇文章将会深深地去解析这些数据类型的内在机制,以此来帮助你构建出更加可靠的代码。
byte类型是8位有符号整数,它采用二进制补码表示,其取值范围为-128到127,它占据1字节内存空间,在大型数组中,byte能显著节省内存,比如存储100万个像素点的灰度图像数据时,使用byte数组比int数组节省3MB内存,网络协议解析、文件流处理等场景也常依赖byte的紧凑特性。
在数据范围内,short类型属于16位有符号整数,其范围处于-32768至32767之间,它占用2字节空间,这相当于int类型的一半。在包括嵌入式系统以及游戏开发场景中,当存在需要存储大量小范围数值的情况,像屏幕坐标、角色属性这类,short能够有效降低内存占用。不过需要留意的是,Java在进行算术运算时会隐式地将short提升为int,这有可能造成微妙的类型转换陷阱。
用于表示整数的int类型,是一种32位有符号整数,其值域大约为正负21亿,它是Java里最常被使用的整数类型,Java虚拟机默认视所有整数字面量为int类型,在循环计数里它很常见,于数组索引方面它也很普遍,在常规数学计算当中它同样无处不在,int的运算效率是最高的,由于32位与CPU通用寄存器的宽度在本质上相匹配,所以它是绝大多数业务场景的首选。
取值范围极为广阔的64位有符号整数是long类型,比如时间戳毫秒数、数据库ID、文件大小统计这些需要处理超过21亿数值的情况,就必须得用long,定义long类型变量的时候,数值字面量要加上“L”后缀,不然编译器会把它当成int处理然后报错,在保证大数据处理和高性能计算领域数据不溢出的关键防线就是long。
Float类型属于32位单精度浮点数,此类型遵循IEEE 754标准,它会占用4字节内存,在科学计算以及图形处理这类需要存储大量浮点数组的场景当中,能够节省大约一半内存,然而float有效位数仅仅约为6至7位十进制数,在进行连续累加或者比较的时候极易产生累积误差,所以不适合用于金融计算或者高精度科学实验。
public class PrimitiveTypeTest {
public static void main(String[] args) {
// byte
System.out.println("基本类型:byte 二进制位数:" + Byte.SIZE);
System.out.println("包装类:java.lang.Byte");
System.out.println("最小值:Byte.MIN_VALUE=" + Byte.MIN_VALUE);
System.out.println("最大值:Byte.MAX_VALUE=" + Byte.MAX_VALUE);
System.out.println();
// short
System.out.println("基本类型:short 二进制位数:" + Short.SIZE);
System.out.println("包装类:java.lang.Short");
System.out.println("最小值:Short.MIN_VALUE=" + Short.MIN_VALUE);
System.out.println("最大值:Short.MAX_VALUE=" + Short.MAX_VALUE);
System.out.println();
// int
System.out.println("基本类型:int 二进制位数:" + Integer.SIZE);
System.out.println("包装类:java.lang.Integer");
System.out.println("最小值:Integer.MIN_VALUE=" + Integer.MIN_VALUE);
System.out.println("最大值:Integer.MAX_VALUE=" + Integer.MAX_VALUE);
System.out.println();
// long
System.out.println("基本类型:long 二进制位数:" + Long.SIZE);
System.out.println("包装类:java.lang.Long");
System.out.println("最小值:Long.MIN_VALUE=" + Long.MIN_VALUE);
System.out.println("最大值:Long.MAX_VALUE=" + Long.MAX_VALUE);
System.out.println();
// float
System.out.println("基本类型:float 二进制位数:" + Float.SIZE);
System.out.println("包装类:java.lang.Float");
System.out.println("最小值:Float.MIN_VALUE=" + Float.MIN_VALUE);
System.out.println("最大值:Float.MAX_VALUE=" + Float.MAX_VALUE);
System.out.println();
// double
System.out.println("基本类型:double 二进制位数:" + Double.SIZE);
System.out.println("包装类:java.lang.Double");
System.out.println("最小值:Double.MIN_VALUE=" + Double.MIN_VALUE);
System.out.println("最大值:Double.MAX_VALUE=" + Double.MAX_VALUE);
System.out.println();
// char
System.out.println("基本类型:char 二进制位数:" + Character.SIZE);
System.out.println("包装类:java.lang.Character");
// 以数值形式而不是字符形式将Character.MIN_VALUE输出到控制台
System.out.println("最小值:Character.MIN_VALUE="
+ (int) Character.MIN_VALUE);
// 以数值形式而不是字符形式将Character.MAX_VALUE输出到控制台
System.out.println("最大值:Character.MAX_VALUE="
+ (int) Character.MAX_VALUE);
}
}
64位双精度浮点数类型为double,它同样照旧遵循IEEE 754标准,它是Java默认的浮点类型,其有效位数差不多约为15至16位,能够覆盖绝大多数工程计算需求,可是,不管是float还是double,都没办法精确表示十进制小数,比如0.1在二进制里是无限循环小数,在涉及货币计算时必须用到BigDecimal类,不然就会出现0.3减去0.2不等于0.1这种诡异的现象。
基本类型:byte 二进制位数:8
包装类:java.lang.Byte
最小值:Byte.MIN_VALUE=-128
最大值:Byte.MAX_VALUE=127
基本类型:short 二进制位数:16
包装类:java.lang.Short
最小值:Short.MIN_VALUE=-32768
最大值:Short.MAX_VALUE=32767
基本类型:int 二进制位数:32
包装类:java.lang.Integer
最小值:Integer.MIN_VALUE=-2147483648
最大值:Integer.MAX_VALUE=2147483647
基本类型:long 二进制位数:64
包装类:java.lang.Long
最小值:Long.MIN_VALUE=-9223372036854775808
最大值:Long.MAX_VALUE=9223372036854775807
基本类型:float 二进制位数:32
包装类:java.lang.Float
最小值:Float.MIN_VALUE=1.4E-45
最大值:Float.MAX_VALUE=3.4028235E38
基本类型:double 二进制位数:64
包装类:java.lang.Double
最小值:Double.MIN_VALUE=4.9E-324
最大值:Double.MAX_VALUE=1.7976931348623157E308
基本类型:char 二进制位数:16
包装类:java.lang.Character
最小值:Character.MIN_VALUE=0
最大值:Character.MAX_VALUE=65535
布林类型仅呈现true或者false这两个状态,从理论上来说仅仅占据1位信息,然而Java虚拟机规范并未明确地去定义其内存大小,一般情况下实现为1字节或者4字节。它身为条件判断的核心部分,掌控着程序的分支以及循环。布尔变量无法与其他数值类型开展隐式转换,这样的严格性规避了C语言中将0看作false、非0看作true所引发的语义模糊问题。
char类型属于16位Unicode字符,其取值范围是从'\u0000'开始直至'\uffff'。它不但能够存储英文字母,还有数字,并且还可以表示汉字、emoji等全球大部分文字。然而在处理增补字符时,比如某些生僻汉字,单个char没办法完整表示,这时需要使用int,或者采用两个char组成的代理对。字符数据在文本解析场景中扮演基础角色,在字符串处理场景中也扮演基础角色,在编码转换等场景中同样扮演基础角色。
Site site = new Site("Runoob")
final double PI = 3.1415927;
具有引用性质的类型所指向的是内存里的对象,并非直接去存储数据,类、接口、数组以及枚举均属于这种具有引用性质的类型,它们的默认值是null,当时声明String str ="Hello"的时候,str是存于栈内存的引用变量,而真正的字符串对象存放于堆内存当中,理解引用传递跟值传递的区别,乃是避免空指针异常以及对象修改混乱的前提条件。
String str = "Runoob";
类属于Java里头最特殊的引用类型,它呀被final修饰,这就意味着字符串对象一旦被创建之后就不可以被变更啦,每次只要做起对字符串的拼接、替换操作的时候,实际上是生成了新的String对象,要是频繁地去操作字符串,那就应该使用StringBuilder或者StringBuffer,StringBuffer是线程安全的,适合多线程的环境,StringBuilder的速度更快,是单线程场景的首选。
String str2=new String("Runoob");
自动类型转换是按照“小范围转大范围”这个原则来进行的,byte、short、char在参与运算之时会自动提升成为int,这样做能够防止中间结果出现溢出的情况,就好比两个byte变量之间相加,其结果必须要使用int来接收,然而把double赋值给float是属于降级操作的,一定要使用强制类型转换,并且还可能会丢失精度。
在兼容类型之间,强制类型转换是适用的。当把long转换为int之情形下,高32位会被直接截断掉,如此一来,就有可能致使数值完全发生改变。在将double转换为int的时候,小数部分会被舍弃掉,而并非进行四舍五入操作。在转换之前,不得不通过对目标类型的取值范围予以判断,以此来规避数据失真所带来的风险。
public class RunoobTest{
public static void main(String[] args){
StringBuilder sb = new StringBuilder(10);
sb.append("Runoob..");
System.out.println(sb);
sb.append("!");
System.out.println(sb);
sb.insert(8, "Java");
System.out.println(sb);
sb.delete(5,8);
System.out.println(sb);
}
}
具备final关键字修饰的常量于初始化之后是不能够再次进行赋值操作的。常量的命名一般情形下都是整个全部大写,并且使用下划线去分隔各个单词。处于编译期的常量(基本类型或者是String类型)会被编译器直接拿来替换成字面值,以此达到代码体积优化之目的。合理地运用常量能够提升代码的可维护性,防止魔法数字所引发的理解障碍。
Runoob..
Runoob..!
Runoob..Java!
RunooJava!
存储固定长度同类型元素的容器是数组,推荐使用int[] arr的声明风格,清晰表明arr是int数组类型,Java中的数组是对象,拥有length属性,创建数组后,基本类型元素有默认初始值,如int为0,引用类型默认值为null,多维数组本质是数组的嵌套,在内存中并非连续存储。
于Java编程里头,数据类型的挑选直接对程序的内存占用产生影响,还关乎运算精度以及执行效率。你有没有因为自己对于数据类型的选择不合适从而引发bug的亲身经历呢?欢迎在评论区去分享你的故事。
public class Test{
public static void main(String[] args){
StringBuffer sBuffer = new StringBuffer("菜鸟教程官网:");
sBuffer.append("www");
sBuffer.append(".runoob");
sBuffer.append(".com");
System.out.println(sBuffer);
}
}
菜鸟教程官网:www.runoob.com