-
Java 中有八种内置的基本数据类型,他们分别是 byte、short、int、long、float、double、char 和 boolean,其中,byte、short、int 和 long 都是用来表示整数,float 和 double 是用来表示浮点数的,那它们之间有什么区别和联系呢?除了这八种基本类型(primitive type)外,其余的类型都是引用类型(reference type)。但是包装类型(wrapper class) Integer 和 Long 也可以用来表示整数,那它们与 int 和 long 又有什么区别和联系呢?这八种基本类型之间的运算关系又是怎样的呢? 一、基本类型 基本类型的表示范围 八种基本类型中,char 类型是用来表示字符的,boolean 类型是用来表示布尔值的,除此之外的 6 种都是用来表示数字的。byte、short、int 和 long 是用来表示整数的,float 和 double 是用来表示浮点数的。下面是每一种类型能表示的范围: 基本类型 位数 最小值 最大值 byte 8 -128 (-2^7) 127 (2^7-1) short 16 -32,768 (-2^15) 32,767 (2^15-1) int 32 -2,147,483,648 (-2^31) 2,147,483,647 (2^31-1) long 64 -9,223,372,036,854,775,808 (-2^63) 9,223,372,036,854,775,807 (2^63-1) float 32 1.4E-45 (0x0.000002P-126) 3.4028235E38 (0x1.fffffeP+127) double 64 4.9E-324 (0x0.0000000000001P-1022) 1.7976931348623157E308 (0x1.fffffffffffffP+1023) char 16 \u0000 (0) \uFFFF (65,535) boolean 1 false true 定义变量时超过对应数据类型最大的表示范围的话将报错。位数越大,单个该数据类型的变量所占用的内存就越多。 每一种类型的最大最小值都保存在了其对应包装类型的属性中,如 Integer.MAX_VALUE 的值为 2147483647,关于包装类型,下面会做详细说明。 类型的默认值 每一种类型都有一个默认值,除基本类型外,其他的类型的默认值都是 null,因为它们都是引用类型。整数默认为 int 类型,浮点数默认为 double 类型。 类型 默认值 byte 0 short 0 int 0 long 0L float 0.0f double 0.0 char '\u0000' boolean false String、Integer 等引用类型 null 当我们定义静态的基本类型变量时,它们将采用默认值: public class Test { static byte b; static short s; static int i; static long l; static float f; static double d; static char c; static boolean bool; static String str; public static void main(String[] args) { System.out.println("byte " + b); // byte 0 System.out.println("short " + s); // short 0 System.out.println("long " + l); // long 0 System.out.println("int " + i); // int 0 System.out.println("float " + f); // float 0.0 System.out.println("double " + d); // double 0.0 System.out.println("char " + c); // char '\u0000' (这个显示不出来) System.out.println("boolean " + bool); // boolean false System.out.println("String " + str); // String null } } 类型之间的转换 类型之间的转换有自动类型转换和强制类型转换两种。自动类型转换也称隐式转换,是编译器自动进行的,强制类型转换称为显式转换,是写代码时显式地完成的。 自动类型转换(隐式转换) 在八种基本数据类型中,除开 boolean 类型,其他的七种都是可以互相进行运算的(如加减法运算)。不同的类型在进行运算的时候,低位的数据类型会向高位的转化,最后的计算结果将是整个运算过程中数据类型位数最大的,这就是自动类型转换。 int a = 1; long b = 2; int c = a + b; // Error long c = a + b; // Right 但要注意一点,比 int 类型数据小的数据类型在做运算的时候,会转换成 int 类型然后再做运算,尽管计算结果能被 byte 或 short 类型表示: short c = 1, d = 2; short e = c + d; // Error int e = c + d; // Right 自动类型转换的规则可以总结为如下: 若有一个变量是 double 类型,则另一个也会被隐式转换为 double 类型;否则,若有一个变量是 float 类型,则另一个也会被隐式转换为 float 类型;否则,若有一个变量是 long 类型,则另一个也会被隐式转换为 long 类型;否则,若有一个变量是 int 类型,则另一个也会被隐式转换为 int 类型。特别的,boolean 类型无法转换(包括自动类型转换和强制类型转换) 即,自动类型转换优先级为:double > float > long > int > short = char = byte (boolean 不可转换) 注意:在 short、byte 和 char 之间不会发生自动类型转换,它们运算时都会先转换成 int 类型,结果最终也是 int 类型,所以前面说,比 int 还小的类型在运算时会被自动转换为 int 类型。 强制类型转换(显式转换) 强制类型转换就是在程序中显式地将一个变量从某一类型强制转换成另一类型。从小位类型到大位类型的转换是向上转换,一般这是没有问题的,但反过来,从大位类型转换到小位类型,即向下转换,是有可能发生数据溢出或者精度损失的。 int a = 32768; float b = 3.1415926f; System.out.println((long)a); // Right // Output: 1 System.out.println((short)a); // overflow // Output: -32768 System.out.println((int)b); // loss of accuracy // Output: 3 数据溢出和精度损失 这里关于数据溢出和精度损失做一些简单的说明。 数据溢出 数据溢出之后变量也还是有值的,程序也不会报错,那溢出后的值是如何计算出来的?这实际上和数据存储的规则有关,涉及到原码、反码和补码等知识,这里不会详细说明这个规则,我们只需要一张图便能知道溢出后的值是如何计算得到的。 数据溢出解释图(以 short 类型为例) 举个例子,int 类型变量值为 131073,在强制类型转换为 short 类型后值就变为了 1。我们可以这样理解,上面的图是 short 类型变量所有的取值,从 0 开始,131073 一个一个去对应,到 32768 时发生数据溢出,变成了 -32768,继续顺时针旋转去对应每个数,最会对应两圈多两个数,然后 131073 对应到第三圈的第二个数字 1,因此,强制类型转换数据溢出后的结果为 1。 注意:131073 = 65536 * 2 + 1 int a = 131073; System.out.println((short)a); // Output: 1 精度损失 在数据存储长度比较长的数据转换为数据存储长度较短的类型时,就可能会发生精度损失,因为要把长数据变成短数据只能将数据后面多余的部分截断才行。因为转换方式采用的是截断多余的,因此我们可以认为当浮点型数据转换为整型数据时是做了一个向零取整的操作(直接舍去小数)。 float a = 3.14f, b = -3.14f; System.out.println((int)a); // Output: 3 System.out.println((int)b); // Output: -3 隐含强制类型转换 除了前面提到的两种,还有一种隐含的强制类型转换,一个整数数字(int 表示范围之内的)会被隐含地转换成 int 类型,一个浮点数字会被隐含地转换成 double 类型。这也解释了为什么前面说整数默认是 int 类型,浮点数的默认类型是 double 类型了。所以,以后在用 float 类型时一定要在后面加上字母 f 或 F,long 类型后面要加上字母 l 或者 L。 二、包装类型 基本数据类型并不是对象,但为了编程的方便,Java 还是引入了它们,也就是前面提到的八个基本类型,但要将其作为对象来操作的话,还是要用这八个基本类型对应的包装类型(wrapper class)。这个包装类型就是 Java 对基本类型的封装,使其能作为对象使用,它们与其他的类型并没有什么太多的区别,都是引用类型(reference type)。 基本类型 包装类型 byte Byte short Short int Integer long Long float Float double Double char Character boolean Boolean 在 Java5 的时候引入了自动装箱/拆箱机制,使得基本类型和对应的包装类型之间可以相互转换。 基本类型和包装类型的区别 基本类型和包装类型在使用时所表示的值是一样的,表示的范围也是对应的,当 int 类型在转换为 Integer 类型的时候,实际上是调用了 Integer 的 valueOf 方法: Integer a = 1; Integer a = Integer.valueOf(1); // the two are equivalent 下面我们列出基本类型和包装类型的一些区别: 基本类型不是对象,而包装类型是对象(有属性和方法); 基本类型不需要实例化,而包装类型需要实例化; 基本类型是直接存储的值,而包装类型是对实例对象的引用; 基本类型有特殊的默认值(如 int 的默认值是 0),而包装类型都是 null; 基本类型所占用的内存比较少,包装类型占用内存较大; 同一基本类型相同值的不同变量的内存地址一样,但实例化得到的同一包装类型相同值的不同变量的内存地址不一样; 基本类型的运算是直接进行的,而包装类型的运算要先拆箱为基本类型才能进行运算。 对象有属性和方法,前面提到的 Integer.MAX_VALUE 就是包装类型的一个属性,上面提到的 Integer.valueOf() 就是一个方法,而基本类型 int 是没有这些的。 基本类型的值都是直接储存的,所以同一个基本类型、相同值的不同变量的地址是一样的: int a = 1, b = 1; System.out.println(a == b); // Output: true 包装类型都是对象实例化的引用,一般每个对象都拥有不同的内存空间,它们的内存地址也就不一样: Integer a = new Integer(100); Integer b = new Integer(100); System.out.println(a == b); // Output: false valueOf 方法的缓存机制 如果一个 Integer 实例对象是由基本类型转换而来的,值处于 -128 ~ 127 之间时,之前的代码输出结果就为 true 。是因为转换时调用的 valueOf 方法有一个缓存机制。 这个判断范围 -128 ~ 127 是默认的,可以在 JVM 提供的配置 (-XX:AutoBoxCacheMax) 进行修改。 为什么要有这个缓存机制?这是因为处于这个区间的值比较小,而且又比较常用,因此编译器就提前将其缓存了,需要时就直接从缓存里拿,既能提高速度,又能在同样值的包装类型较多的时候节省内存。所以,两个值在 -128 ~ 127 之间,且由基本类型 int 转换而来的 Integer 就是同一个对象。这对于包装类型 Byte、Short 和 Long 也是一样的。 Integer a = 100, b = 100; System.out.println(a == b); // Output: true Integer c = 128, d = 128; System.out.println(c == d); // Output: false 与此类似的还有包装类型 Boolean,它一共就只有两种可能,true 和 false,因此也被提前缓存了。包装类型 Character 在 '\u0000' ~ '\u007F' 之间的值(0 ~ 127)也是被提前缓存了。不过包装类型 Float 和 Double 的 valueOf 方法就没有这个缓存机制了。 基本类型和包装类型的联系 为什么包装类型叫做“包装类型”呢?顾名思义,就是对基本类型的一个封装,从名字里我们就能知道,基本类型和包装类型之间的实际上有个装箱与拆箱的关系。 直接由基本类型 int 转化而来的 Integer 对象是对 int 类型的装箱操作,而由 Integer 对象转换来的 int 类型变量就是对 Integer 对象的拆箱操作。 Integer a = 1; // 装箱 Integer a = Integer.valueOf(1); // 等价形式 int b = a; // 拆箱 int b = a.intValue(); // 等价形式 实例化生成的 Integer 类型变量与基本类型转化而来的 integer 类型变量尽管值相同,但内存地址并不相同(非 new 生成的 Integer 对象指向 Java 常量池中的对象),不是同一个对象,所以在比较的时候输出 false。但是当二者与基本类型相同值的变量去比较时却都输出 true。 Integer a = 1; Integer b = new Integer(1); System.out.println(a == b); // Output: false int c = 1; System.out.println(c == a); // Output: true System.out.println(c == b); // Output: true 这是因为包装类型 Integer 与基本类型在比较的时候会自动拆箱为 int 类型,然后再去比较,这样所得到的结果就是一样的,因此输出 true。 ———————————————— 原文链接:https://blog.csdn.net/weixin_62651706/article/details/130742296
-
处理场景:通过文本框获取用户输入的数字数据,可是得到的都是字符串,如果想要对这些字符串的数字进行运算,必须妖精字符串转化成数字, 在Java中提供了相应的解决的对象 基本数据类型包装类:Java将基本数据类型值封装成了对象。封装成对象有什么好处?——这样可以提供更多操作基本数值的功能 一般我们对数值的基本操作就是通过运算符来进行运算但是如果我们想要获得一个数值的二进制,这个就是对数值的更多操作,这些功能封装到对象中 基本数据类型:byte short int long float double boolean char 对应的类 :Byte Short Integer Long Float Double Boolean Character 特点:(以整数Integer为例) 1.类中包含了对数值操作的多种功能 2.基本数据类型包装类型最重要的特点及作用:提供了数值与字符串相互转化的方法(重点解析) 1.怎么将字符串转化为基本数值(不是按照进制转化而是直接从表面转化)。结果就应该是基本数值,参数为字符串 ”1234“————1234 "a1234"——出现传入数据类型异常 static int parseInt(String s) 将字符串参数解析为带符号的十进制整数。 各种基本数据的解析方法: xxx parseXxx(String s); character() 没有解析方法。 在parseInt(); 方法使用时会抛出一个异常,NumberFormatException 传入的数据错误,这是一个运行时异常,可以声明(提供一个解决办法),也可以不声明,让程序直接停止并抛出异常。 2.parseInt() 的一个重载形式:将字符串按照所需的进制转化为十进制 static int parseInt(String s, int radix) 将字符串参数解析为第二个参数指定的基数中的有符号整数。 函数的功能是将 String s 这个字符串按照 radix 所规定的进制,转换成整数。要求:字符串的书写必须符合进制的要求。 例如:paresInt("5959",2); 这样的语句就会抛出异常,因为二进制只能由1 0 组合。16进制以上所含的字母也要符合要求。 3.将十进制转化为其他进制 static String toBinaryString(int i) 在基数2中返回整数参数的字符串表示形式为无符号整数。 static String toHexString(int i) 返回整数参数的字符串表示形式,作为16位中的无符号整数。 static String toOctalString(int i) 在基数8中返回整数参数的字符串表示形式为无符号整数。 如何将数字转化为字符串 String.value(int i); Integer.toString(int i); 代码: package Wrapper; public class WrapperDemo1 { public static void main(String[] args){ /* /基本数据类型包装类 1.提供操作数据的多种功能 2.重点功能:数值和字符串的相互转化进制的转化********** */ System.out.println(Integer.MAX_VALUE);//整数的最大值 System.out.println(Integer.MIN_VALUE );//整数的最小值 //将字符串转化为数值 System.out.println(Integer.parseInt("123456"));//将字符串直接转化为十进制 System.out.println(Integer.parseInt("10101",2));//将字符串按照要求对的进制转化为十进制 //将十进制转化为其他进制 System.out.println(Integer.toBinaryString(12));//转化为二进制 System.out.println(Integer.toHexString(16));//转化为8进制 System.out.println(Integer.toOctalString(15) );//转化为16进制 //将数值转化为字符串 System.out.println(Integer.toString(484848)); System.out.println(String.valueOf(23.23)); } } 运行结果: 2147483647 -2147483648 123456 21 1100 10 17 484848 23.23 ————————————————基本数值和对象之间的转化—————————————————— //基本数值怎么变成包装对象 //构造函数 Integer in= new Integer(4);//将数值4 变成了包装好的对象 Integer i= new Integer("4");//也是创建数值4的对象(字符串被转化成了对象) //静态方法 Integer ii = Integer.valueOf(4); //包装好的对象怎么转化成数值(方法肯定是非静态的,要通过对象调用) int num=i.intValue(); System.out.println(num); ————————————自动拆箱装箱———————————————————————————— 在之前的书写中: int i=4; 只是定义了基本的数据,可以非常方便的进行运算 Integer i= Integer(4); 定义了一个对象,可以提供了很多对数据的操作,但是就进行基本的运算就显得有一点麻烦,因此找一个折中的办法 因此在JDK1.5 以后,有了yi一个包装类的新特性 Integer i = 4; 左边是一个引用型变量,右边是一个对象(新特性,简化书写)——自动将4封装——自动装箱 /// Integer.valueOf(4); valueOf(); 源代码: public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); } 其实在最底层,还是使用的new Integer(int i); 这样的书写,一是使书写更加的简便,二是是使用更加的方便灵活,可以同时,实现调用操作对象的功能,运算也变得十分方便 a=a+5; 将右边的a 由对象转化成了数值,自动拆箱a.intValue()+5,在完成加法运算后又自动封箱(全自动) a=Integer.valueOf().(i.intValue()+5);//在1.5以下的版本中的书写 1.5以后的的这一新的特性在使用的时候,代码的书写上是给使用带来了极大的方便,但是一定要清楚他的原理 关于拆箱封箱的一些细节: //基本数据包装类中的一些细节 Integer num1= new Integer(3); Integer num2= new Integer(3); System.out.println(num1==num2);//false System.out.println(num1.equals(num2));//true //equals 是Object 类中的方法,但是在Integer 中重写了这个方法,建立了自己的比较规则:在对象不为null 时。只要对象包含的int 类型的数值是相等的,那么这两个对象就是相等的 Integer i1 = 127; Integer i2 = 127; Integer i3 = 128; Integer i4 = 128; System.out.println("i1==i2? "+(i1==i2));//ture System.out.println("i1==i2? "+i1.equals(i2));//true System.out.println("i3==i4? "+(i3==i4));//false System.out.println("i3==i4? "+i3.equals(i4));//true equals 是Object 类中的方法,但是在Integer 中重写了这个方法,建立了自己的比较规则:在对象不为null 时。只要对象包含的int 类型的数值是相等的,那么这两个对象就是相等的 在1.5 以后的自动拆箱和封装定义中,如果数值在byte (-128------127)的范围内,不会创建新的对象空间而是使用原来已有的空间——也就是说,当数值在-128 到 127 之间时。两个引用型变量指向的是同一个对象 ————————————————综合练习—————————————————————————————————— ”23 9 -4 18 100 7“ 要求将这串数字按照从大到小排序 思路:1.只要有排序就要有数组,数组中就要有元素 2.元素都在字符串里,要想获得字符串里的内容,就需要创建字符串对象 3.从字符串获取到数值后存储到一个int 数组中进行排序 4.将排序后的数组变成字符串 先定义字符串:String strs = ”23 9 -4 18 100 7“ 1.获取字符串中的数字。通过空格进行indexOf 的索引,找到位置,substring 截取。思路上就可以了,但是这个方法看起来就显得很麻烦,可以直接用split(分割的标记) String[] strs = nums.split(" "); 但是这样分割出来是字符串数组,是无法进行大小比较的,要比较还是要转化成整数才可以。————将字符串数组转化成整数数组 代码: package String; import java.util.Arrays; /* 基本数据包装类:整型 Integer 练习 ”23 9 -4 18 100 7“ 要求将这串数字按照从小到大排序 思路: 1.先定义字符串 2.要排序就需要数组 3.按照空格为分割依据,分成字符串数组,但是无法比较 4.将字符串数组转化为整型数组 5.将整型数组进行比较 6.最后在转化为字符串 */ public class IntegerDemo { //将字符串数组转化为整型数组 private static int[] toIntArray(String[] strs){ int[] nums = new int[strs.length]; for(int i =0 ;i<strs.length;i++){ nums[i] = Integer.parseInt(strs[i]); } return nums; }//1.自己写排序 private static void sortArray(int[] nums){ for(int i=0;i<nums.length-1;i++){ for(int j=i+1;j<nums.length;j++){ if(nums[i]>nums[j]){ int temp=nums[i]; nums[i]=nums[j]; nums[j]=temp; } } } } //将整形数组转化为字符串 private static String toString(int[] nums){ StringBuffer str = new StringBuffer(); for(int i=0;i<nums.length;i++){ if(i!=nums.length-1){ str.append(nums[i]+" "); } else{ str.append(nums[i]); } } return str.toString(); } private static String sortIntArrayString(String str){ //1.转化为字符串数组 final String SPACE = " "; String[] strs = str.split(SPACE); //2.将字符串数组转化为整型数组 int[] nums =toIntArray(strs); //3.将整型数组排序 //调用函数排序 Arrays.sort(nums); sortArray(nums); //转化为字符串 str= toString(nums); return str; } public static void main(String[] args){ String str ="23 9 -4 18 100 7"; str =sortIntArrayString(str); System.out.println("str = "+str); } } //学习了 String String Buffer StringBuilder 基本数据类型包装类 ———————————————— 原文链接:https://blog.csdn.net/Stitch__/article/details/82142444
-
JAVA中的基本实际原则就是“一切皆对象”。而基本数据类型很显然不是对象,因此可以采用基本数据类型进行包装。 JAVA给出了一组包装类,分别为Byte、Short、Integer、Long、Float、Double、Character、Boolean,对应不同的基本数据类型。 上面的包装类又可以分为两种子类型: 对象型包装类(Object直接子类):Character、Boolean 数值型包装类(Number直接子类):Byte、Short、Integer、Long、Float、Double Number是一个抽象类,其中一共定义了6个操作方法,分别是intValue/doubleValue/floatValue/byteValue/shortValue/longValue。 装箱与拆箱 基本数据类型和包装类之间的转换可以通过以下方法定义: 装箱操作:将基本数据类型变为包装类,每个包装类的构造方法都可以接收各自数据类型的变量 拆箱操作:从包装类中取出被包装的数据,利用从Number类中继承而来的一系列xxxValue方法完成 public class Demo { public static void main(String args[]) { Integer obj = new Integer(10); int num = obj.intValue(); System.out.println(num); } } 简单地说,装箱就是有参构造,拆箱就是调用xxxValue方法获得内部数据。除了int外,double也是一样的操作。而boolean虽然是Object的子类,但也有同样的操作。 自动装箱和自动拆箱 自动装箱和自动拆箱是指上述的操作都是自动进行的,无需进行构造操作。 public class Demo { public static void main(String args[]) { Integer obj = 10; int num = obj; System.out.println(obj); ++obj; System.out.println(obj); } } 结果为: 10 11 从上面的代码看,基本数据类型和包装类之间的转换是自动的,并不需要显式进行装箱和拆箱操作。 再看一段代码: public class Demo { public static void main(String args[]) { Integer obj1 = 10; Integer obj2 = 10; Integer obj3 = new Integer(10); System.out.println(obj1 == obj2); System.out.println(obj1 == obj3); System.out.println(obj2 == obj3); System.out.println(obj2.equals(obj3)); } } 结果为: true false false true 从上面的结果可以看出,自动装箱会保存对象到对象池中,而构造装箱则是会重新开辟新的堆内存空间。因此为了保证对象的有效比较,最好使用equals方法进行比较。 Object 既然知道基本数据类型和和包装类的转换操作,实际上也就可以利用Object来进行统一操作了。所有的引用数据类型都可以利用Object类来接收,而由于存在自动装箱机制,那么基本数据类型同样可以使用Object接收。 public class Demo { public static void main(String args[]) { Object obj = 10; int tmp = (Integer)obj; System.out.println(obj); System.out.println(tmp); System.out.println(tmp * 2); } } 结果为: 10 10 20 从上面的代码可以看出,可以使用Object接收基本数据,并可以直接打印输出,但并不能直接对Object类对象进行基本数据的计算,此时需要向下转型为Integer类型,才能够进行自动拆箱,并进行数据计算。 数据类型转换 而包装类中还存在数据类型转换的操作,在包装类中还提供了将String类数据转换为基本数据的方法,比如: Integer类:public static int parseInt(String s) Double类:public static double parseDouble(String s) Boolean类:public static boolean parseBoolean(String s) 实际上,在给出的8种基本数据类型的包装类中,一共有7个类定义了parseXxx()的方法,可以实现将String变为基本数据类型。但是在Character类中并没有存在这样的方法,相反其对应的方法为charAt()方法。 public class Demo { public static void main(String args[]) { String str1 = "12"; String str2 = "12.3"; int var1 = Integer.parseInt(str1); double var2 = Double.parseDouble(str2); char var3 = str1.charAt(0); System.out.println(var1); System.out.println(var2); System.out.println(var3); } } 结果为: 12 12.3 1 上面的操作可以将String字符串转换为相应的数据类型,但是如果字符串中包含非数字的字符内容,转换就会出现错误。因此实际开发中,需要严格对输入字符串进行检测,防止出错。 上面只是将字符串转换为基本数据类型,同样也可以将基本数据类型转换为字符串: public class Demo { public static void main(String args[]) { int var1 = 10; double var2 = 12.3; boolean var3 = true; String str1 = "" + var1; String str2 = "" + var2; String str3 = "" + var3; String str4 = String.valueOf(var1); String str5 = String.valueOf(var2); String str6 = String.valueOf(var3); System.out.println(str1); System.out.println(str2); System.out.println(str3); System.out.println(str4); System.out.println(str5); System.out.println(str6); } } 结果为: 10 12.3 true 10 12.3 true 上面的代码提供了两种基本数据类型转换为String的操作,之前提到字符串和基本数据类型相加会转换为字符串,因此一种操作就是与空字符串进行相加,另一种操作就是使用String中的valueOf方法进行转换。 ———————————————— 原文链接:https://blog.csdn.net/SAKURASANN/article/details/124647622
-
3.3 char 与 Character 之间的转换 3.3.1 char → Character 3.3.2 Character → char 3.4 boolean 与 Boolean 之间的转换 3.4.1 boolean → Boolean 3.4.2 Boolean → boolean 3.5 包装类与 String 类型的转换 3.5.1 包装类 → String 3.5.2 String → 包装类 1 Java 的数据类型 =============================================================================== Java 的数据类型可以分为两大类,即基本数据类型和引用数据类型。 2 Java 的包装类 ============================================================================== Java 的包装类便是一种特殊的引用数据类型,因为其是与基本数据类型一一对应的。 虽然基本数据类型的效率更高,然后对于面向对象的语言 —— Java,操作对象比操作基本数据类型更为方便,并且基本数据类型有很多局限性,比如对于 int,其有时无法区分默认值 0 还是真的为 0(比如考试成绩为 0 与没有参加考试 null)。 | 基本数据类型 | 引用数据类型 | | — | — | | byte | Byte | | short | Short | | int | Integer | | long | Long | | float | Float | | double | Double | | char | Character | | boolean | Boolean | 3 装箱和拆箱 ========================================================================== 装箱指的是将基本数据类型转为包装类;拆箱指的是将包装类转为基本数据类型。 以下 Java 的代码实现基于 JDK 1.8。 3.1 int 与 Integer 之间的转换 3.1.1 int → Integer int i = 13; Integer integer = Integer.valueOf(i); 3.1.2 Integer → int Integer integer = 10; int i = integer.intValue(); 其它整数类型(byte、shot、long)的转换方式与 int 相同。 3.2 float 与 Float 之间的转换 3.2.1 float → Float float i = 13; Float fo = Float.valueOf(i); 3.2.2 Float → float Float fo = new Float(13); float i = fo.floatValue(); 3.3 char 与 Character 之间的转换 3.3.1 char → Character char i = ‘s’; Character fo = Character.valueOf(i); 3.3.2 Character → char Character character = new Character(‘s’); char c = character.charValue(); ———————————————— 原文链接:https://blog.csdn.net/shenliba/article/details/137758939
-
基本数据类型间除了boolean和char类型外,都可以相互转换 1 基本数据类型转包装类型–》装箱 int a =10 ; Integer i1 = a;//可以自动转,自动装箱 Integer a1 = new Integer(a);//手动装箱 Integer i = Integer.valueOf(a); 1 2 3 4 2 包装类型转基本数据类型–》拆箱 Integer a =10 ; int i1 = a;//可以自动转,自动拆箱 int i2 = a.intValue();//手动拆箱 1 2 3 3 把字符串转换成基本数据类型,调用包装类的parseXXX方法或者valueOf方法 String s = "1234"; int i = Integer.parseInt(s); double b = Double.parseDouble(s); boolean boo = Boolean.parseBoolean(s); 1 2 3 4 int i = Integer.valueOf(s); 1 4 把基本数据类型转换成字符串 int i =9; //方法1 String s = i+""; //方法2 String s = String.valueOf(i); //方法3 String s = Integer.toString(i); ———————————————— 原文链接:https://blog.csdn.net/ss449988/article/details/103530198
-
装箱: 基本数据类型转换成包装类 拆箱:包装类转化成基本数据类型 装箱分为自动装箱和手动装箱俩种方法。 有装箱操作也会有拆箱操作,而拆箱也会分为自动拆箱和手动拆箱。 代码如下: package box; public class BoxOne{ public static void main(String[] args) { //自动装箱操作 int a=3; Integer a1=a; //手动装箱 Integer a2=new Integer(a); //运行结果值都是 3 //自动拆箱 int a3=a2; //手动拆箱 int a4=a2.intValue(); //运行结果会发现 这俩值是一样的 } } ———————————————— 原文链接:https://blog.csdn.net/zhihu000/article/details/114391378
-
在 Java 编程中,自动装箱(Autoboxing)和自动拆箱(Unboxing)是两个重要的概念。它们使得基本数据类型与其对应的包装类之间的转换更加方便,同时也提高了代码的可读性和可维护性。本篇博客将深入探讨自动装箱和拆箱的概念、用法以及为什么它们对 Java 程序员如此重要。 什么是自动装箱和拆箱? 在理解自动装箱和拆箱之前,让我们先回顾一下 Java 中的基本数据类型和包装类之间的关系。 基本数据类型(Primitive Data Types): Java 提供了一组基本数据类型,如整数(int、byte、short、long)、浮点数(float、double)、字符(char)、布尔(boolean)等。这些基本数据类型存储简单的数值或布尔值。 包装类(Wrapper Classes): 为了使基本数据类型具备面向对象的特性,Java 提供了对应的包装类,如 Integer、Double、Character、Boolean 等。这些包装类用于将基本数据类型封装为对象,以便进行更多的操作。 自动装箱和拆箱就是 Java 编译器自动处理基本数据类型与包装类之间的转换,使程序员无需手动编写繁琐的代码。 自动装箱(Autoboxing) 自动装箱是指将基本数据类型自动转换为相应的包装类对象。这意味着,你可以将一个 int 类型的值直接赋值给 Integer 类型的变量,而无需显式创建 Integer 对象。 int primitiveInt = 42; Integer wrappedInt = primitiveInt; // 自动装箱 在上述代码中,primitiveInt 是一个基本数据类型的变量,而 wrappedInt 是一个 Integer 类型的变量。通过自动装箱,primitiveInt 的值被自动封装为 Integer 对象。 自动拆箱(Unboxing) 自动拆箱是指将包装类对象自动转换为相应的基本数据类型。这意味着,你可以直接将一个 Integer 对象赋值给 int 类型的变量,而无需显式调用 .intValue() 方法。 Integer wrappedInt = 42; int primitiveInt = wrappedInt; // 自动拆箱 在上述代码中,wrappedInt 是一个 Integer 类型的对象,通过自动拆箱,它的值被自动提取为一个基本数据类型的 int。 常见包装类的使用 当谈到Java的自动装箱和拆箱时,理解每个包装类是非常重要的,因为它们与基本数据类型之间的转换密切相关。在这一部分,我们将详细介绍Java的主要包装类以及它们的作用。 Integer 包装类 java.lang.Integer 是表示整数的包装类,它封装了基本数据类型 int。Integer 类提供了许多方法来处理整数,例如将字符串解析为整数、将整数转换为字符串等。 常用方法和示例 parseInt(String s):将字符串转换为整数。 String str = "42"; int num = Integer.parseInt(str); // num 现在包含整数 42 toString():将整数转换为字符串。 Integer num = 42; String str = num.toString(); // str 现在包含字符串 "42" Double 包装类 java.lang.Double 是表示双精度浮点数的包装类,它封装了基本数据类型 double。Double 类提供了许多方法来处理浮点数,例如将字符串解析为双精度浮点数、将双精度浮点数转换为字符串等。 常用方法和示例 parseDouble(String s):将字符串转换为双精度浮点数。 String str = "3.14"; double num = Double.parseDouble(str); // num 现在包含双精度浮点数 3.14 toString():将双精度浮点数转换为字符串。 Double num = 3.14; String str = num.toString(); // str 现在包含字符串 "3.14" Character 包装类 java.lang.Character 是表示字符的包装类,它封装了基本数据类型 char。Character 类提供了一些方法来处理字符,例如检查字符的类型、转换字符为大写或小写等。 常用方法和示例 isDigit(char ch):检查字符是否是数字。 char ch = '5'; boolean isDigit = Character.isDigit(ch); // isDigit 现在为 true toUpperCase(char ch):将字符转换为大写。 char ch = 'a'; char upper = Character.toUpperCase(ch); // upper 现在为 'A' Boolean 包装类 java.lang.Boolean 是表示布尔值的包装类,它封装了基本数据类型 boolean。Boolean 类提供了一些方法来处理布尔值,例如解析字符串为布尔值、取反等。 常用方法和示例 parseBoolean(String s):将字符串解析为布尔值。 String str = "true"; boolean bool = Boolean.parseBoolean(str); // bool 现在为 true valueOf(boolean b):将布尔值转换为 Boolean 对象。 boolean bool = true; Boolean boolObj = Boolean.valueOf(bool); // boolObj 包含布尔值 true Autoboxing 和 Unboxing 示例 下面是一些自动装箱和拆箱的示例,展示了如何在基本数据类型和包装类之间转换,这些示例演示了如何使用自动装箱和拆箱来进行基本数据类型与包装类之间的转换,使代码更加简洁和易读。: 自动装箱示例 int primitiveInt = 42; Integer wrappedInt = primitiveInt; // 自动装箱 double primitiveDouble = 3.14; Double wrappedDouble = primitiveDouble; // 自动装箱 char primitiveChar = 'A'; Character wrappedChar = primitiveChar; // 自动装箱 自动拆箱示例 Integer wrappedInt = 42; int primitiveInt = wrappedInt; // 自动拆箱 Double wrappedDouble = 3.14; double primitiveDouble = wrappedDouble; // 自动拆箱 Character wrappedChar = 'A'; char primitiveChar = wrappedChar; // 自动拆箱 自动装箱和拆箱的好处 自动装箱和拆箱带来了许多好处,让 Java 编程变得更加方便和直观: 提高可读性: 自动装箱和拆箱使得代码更加清晰和简洁,不需要频繁地进行类型转换。 减少错误: 自动装箱和拆箱减少了因类型转换错误而引发的 bug,因为编译器可以在编译时进行类型检查。 更容易使用集合类: 自动装箱和拆箱使得将基本数据类型放入集合类(如 ArrayList<Integer>)变得更加容易,而无需手动转换。 提高性能: Java 的新版本中对自动装箱和拆箱进行了性能优化,使得它们的性能更好。 自动装箱和拆箱的注意事项 虽然自动装箱和拆箱非常方便,但在使用时仍需注意一些细节: 性能考虑: 尽管 Java 的性能优化有所改进,但在高性能要求的场景中,频繁的自动装箱和拆箱操作可能会导致性能下降。在这种情况下,建议手动管理类型转换。 空指针异常: 自动拆箱可能会引发 NullPointerException,因为包装类对象可能为 null。在拆箱之前,最好进行空值检查。 Integer wrappedInt = null; int primitiveInt = wrappedInt; // 抛出 NullPointerException 不同包装类之间的比较: 尽管两个包装类对象的值相同,但它们可能不会被视为相等,因为它们是不同的对象。要进行值比较,应使用 .equals() 方法。 Integer a = new Integer(42); Integer b = new Integer(42); boolean isEqual = a.equals(b); // true 实际应用 自动装箱和拆箱在实际应用中非常常见。以下是一些常见的用例: 集合类操作: 将基本数据类型添加到集合类中,如 ArrayList<Integer>。 泛型编程: 在泛型类或方法中使用基本数据类型和包装类。 方法参数传递: 方法可以接受包装类或基本数据类型参数,使得方法更加灵活。 数据持久化: 将数据保存到数据库或文件时,常常需要将基本数据类型转换为包装类。 总结 自动装箱和拆箱是 Java 语言中一个重要的特性,它们让基本数据类型与包装类之间的转换更加便捷,提高了代码的可读性和可维护性。通过自动装箱和拆箱,Java 程序员可以更加专注于解决业务逻辑,而不必过多关注数据类型转换的细节。然而,在使用自动装箱和拆箱时,仍需谨慎考虑性能和空指针异常等方面的问题。 了解和熟练使用自动装箱和拆箱是 Java 编程的重要一环。它们可以使你的代码更加简洁和易读,同时避免了很多类型转换的烦恼。但在性能敏感的场景中,仍需慎重选择是否使用自动装箱和拆箱,以确保程序的高效运行。 希望通过本篇博客,你对 Java 自动装箱和拆箱有了更深入的理解,并能够在实际编程中灵活运用这一特性。 ———————————————— 原文链接:https://blog.csdn.net/qq_21484461/article/details/132724519
-
一、什么是 Java 包装类? Java包装类(Wrapper Class)是一种将基本数据类型封装成对象的类。在Java中,每种基本数据类型都有对应的包装类。 常见的基本数据类型和其对应的包装类如下所示: 基本数据类型 包装类 boolean java.lang.Boolean byte java.lang.Byte short java.lang.Short int java.lang.Integer long java.lang.Long float java.lang.Float double java.lang.Double char java.lang.Character 使用Java包装类,我们可以将基本数据类型转换为对象,并使用这些对象调用它们的方法。例如,可以将int类型的变量转换为Integer类型的对象,然后使用该对象调用intValue()方法获取原始的int值。 除了基本数据类型和其对应的包装类之间的转换之外,Java包装类还提供了许多其他实用功能,例如字符串转换、格式化输出、比较大小等。此外,包装类也可以与Java集合框架一起使用,使得我们能够将基本数据类型的值存储在集合中。 二、什么是自动拆箱? Java自动拆箱(Auto Unboxing)是指将包装类型(如Integer、Double等)转换为对应的基本数据类型(如int、double等)的过程,这是Java 1.5之后提供的新特性。 在Java 1.4及以前的版本中,我们必须手动调用包装类型的intValue()、doubleValue()等方法才能将其转换为基本数据类型,如下所示: Integer i = new Integer(10); // 定义一个Integer对象 int j = i.intValue(); // 调用intValue()方法将i转换为int 而在Java 1.5及以后的版本中,我们可以直接将包装类型赋值给基本数据类型变量,Java编译器会自动将包装类型转换为对应的基本数据类型,如下所示: Integer i = new Integer(10); int j = i; // 自动拆箱,将i转换为int类型 可以看到,在上面的代码中,我们省略了调用intValue()方法的步骤,直接将Integer对象赋值给了int变量。此时,Java编译器会自动将Integer对象转换为int类型,这个过程叫做自动拆箱。 需要注意的是,自动拆箱有时也可能会出现NullPointerException异常,例如以下代码: Integer i = null; int j = i; // 抛出NullPointerException异常 在这种情况下,由于i为null,无法自动拆箱为int类型,因此会抛出NullPointerException异常。 三、什么是自动装箱? Java自动装箱(Autoboxing)是指Java编译器在需要的时候,会自动将原始数据类型转换为对应的包装类类型。这种特性可以使得我们在使用包装类对象时更加方便和简洁。 例如,我们可以将一个int类型的值赋给Integer类型的变量,编译器会自动将int类型的值“装箱”成Integer类型的对象: int i = 1; Integer j = i; // 自动装箱:将int类型的i转换为对应的Integer类型 同样地,当我们需要将一个Integer对象转换为int类型的值时,编译器也会自动将Integer对象“拆箱”成int类型的值: Integer i = new Integer(1); int j = i; // 自动拆箱:将Integer对象i转换为对应的int类型 在Java 5之前,我们需要手动进行装箱和拆箱操作,例如: int i = 1; Integer j = new Integer(i); // 手动装箱 int k = j.intValue(); // 手动拆箱 由于自动装箱和拆箱是Java编译器在编译时自动完成的,因此在运行时会稍微比手动装箱和拆箱多花费一些时间和空间。但在大多数情况下,这种开销都非常小,不会对程序性能造成显著影响。 四、为什么要进行自动拆箱和装箱? Java进行自动拆箱和装箱主要是为了方便编程以及提升代码的可读性。 具体来说,自动拆箱使得我们在需要使用基本数据类型时可以直接使用对应的包装类类型,而无需手动进行转换。例如: Integer a = 10; // 自动装箱 int b = a; // 自动拆箱 上述代码中,将整型值10赋值给一个Integer类型的变量a时,发生了自动装箱;而在之后将a赋值给一个int类型的变量b时,发生了自动拆箱。 自动拆箱和装箱使代码更加简洁,也更容易阅读和理解。同时,在某些情况下,如泛型相关的操作中,自动拆箱和装箱也是必须的。 虽然自动拆箱和装箱增加了一定的开销,但在大多数情况下并不会对程序性能造成较大影响。 ———————————————— 原文链接:https://blog.csdn.net/2301_77899321/article/details/131026407
-
1、Java基本数据类型及其对应的包装器类类型 Java中共用8种基本数据类型,并为这8种基本数据类型中的每一种都提供了一个包装器类,例如int类型对应的包装器类是Integer。具体类型如下表: 2、自动装箱和自动拆箱 自动装箱:就是指自动将基本数据类型转换为包装器类型。 自动拆箱:就是指自动将包装器类型转换为基本数据类型。 Integer i = 19; // 自动装箱 int j = i; // 自动拆箱 如上第一行代码,数组19是基本数据类型(int),当赋值给包装器类型(Integer)变量时,触发自动装箱操作,创建一个Integer类型对象,并且赋值给了 i 。其底层实际执行了以下代码: Integer i = Integer.valueOf(19); 同理,第二行代码,将 i 赋值给 j,触发了自动拆箱操作,将 i 中的数据取出赋值给 j 。其底层实际执行了以下代码: int j = i.intValue(); JDK5前是手动装箱和拆箱,JDK5之后就可以自动装箱和自动拆箱了。 Object o1 = true ? new Integer(1) : new Double(2.0); // 1.0 object o2; if(true) { o2 = new Integer(1); // 1 } else { o2 = new Double(2.0); } 如上第一个三元运算符输出的结果是1.0,因为三元运算符是一个整体,所以前面的Integer受后面的Double影响。而下面的if-else是无影响的,则输出1。 Integer i = 100; // 自动装箱 String str1 = i + ""; 以上只是以i的基本数值转成了字符串,并不会影响i的数据类型。 3、双等于“==" 通过” == “ 来比较对比的是栈中的值,基本数据类型比较的值,引用数据类型比较的是堆中内存对象的地址。即判断两个对象是否相等,实际上是在判断两个局部变量存储的地址是否相同,即是否指向相同的对象。 但如下代码中比较的a1和a2却是相等的。b1和b2又是不相等的。 Integer a1 = 58; Integer a2 = 58; Integer b1 = 129; Integer b2 = 129; Integer a3 = new Integer(58); System.out.println(a1 == a2); // true System.out.println(b1 == b2); // false System.out.println(a1 == a3); // false 实际是,Integer运用了 享元设计模式 来复用对象,当通过自动装箱,即调用 valueOf() 来创建Integer对象的时候,如果要创建的Integer对象的值在 -128~127之间,就会从IntegerCache类中直接返回,否则才会调用new方法创建新的对象。即a1和a2都是指向同一个对象(享元对象),b1和b2不是同一个对象。 而Integer a3 = new Integer(58);并不会调用valueOf(),即不会使用到IntegerCache。 为什么IntegerCache只缓存 -128~127之间的整型值? 当IntegerCache类被加载的时候,缓存的享元对象会被集中一次性创建好,而整型数值太多,不能一次性被创建,否则会占用太多的内存,类加载的时间会过长,即只能缓存大部分应用来说最常用的整型值,即一个字节的大小,byte数据类型的范围。 实际,jdk提供了自定义缓存的最大值,设置方法有 方法一: -Djava.lang.Integer.IntegerCache.high = 255 方法二: -XX:AutoBoxChaheMax = 255 4、字符串类型String String s1 = "小姐姐"; String s2 = "小姐姐"; String s3 = new String("小姐姐"); System.out.println(s1 == s2); // true System.out.println(s1 == s3); // false System.out.println(s1 == s3.intern()); // true System.out.println(s3 == s3.intern()); // false String类型利用了享元设计模式来复用相同的字符串常量,JVM会专门开辟一块存储区来存储字符串常量,这块存储区叫做”字符串常量池“ Integer类中要共享的对象是在类加载的时候就会集中一次性创建好,而字符串是在第一次被使用时被存储到常量池中,当之后再使用的时候,就直接引用常量池中已经存在的即可。 当调用intern()方法时,如果池已经包含一个等于此String对象的字符串,则返回池中的字符串。否则,将此 String 对象 添加到池中,并返回此String 对象的引用,即 intern()方法 最终返回的是常量池的地址(对象)。s3是重新new了一个对象,所以s3是指向堆的,而s3.intern()是指向常量池的,所以 s3不会等于s3.intern() 。 String s1 = "hello"; s1 = "haha"; String是一个final类,代表不可变的字符序列。字符串是不可变的,一个字符串对象一旦被分配,其内容是不可变的。即以上是先创建hello对象,之后在常量池中找是否有haha对象,没有就创建haha对象,再将s1指向haha对象,共创建了两个对象。 String a = "hello" + "abc"; 以上编译器会自动优化等价为:(即总共创建了一个对象) String a = "helloabc"; String a = "hello"; // 创建a对象 String b = "abc"; // 创建b对象 // 先创建一个StringBuilder sb = new StringBuilder() // 执行 sb.append("hello"); 再执行 sb.append("abc"); 最后转成string :String c = sb.toString() String c = a + b; // 最终c指向堆中的对象 Strin d = "helloabc"; System.out.print(c == d); // false d指向常量池,c指向堆 ———————————————— 原文链接:https://blog.csdn.net/weixin_43763430/article/details/127944433
-
一、自动装箱和自动拆箱的概念 自动装箱是指Java编译器(javac)在需要将基本数据类型转换为对应的包装类时,会自动进行转换的过程。换句话说,当我们使用基本数据类型时,编译器会自动将其转换为包装类。例如,当我们将一个int类型的变量赋值给一个Integer类型的变量时,就会发生自动装箱。 自动拆箱则是自动装箱的逆过程。当我们使用包装类对象进行计算或者与基本数据类型进行比较时,编译器会自动将包装类对象转换为对应的基本数据类型。例如,当我们将一个Integer类型的变量与一个int类型的变量相加时,就会发生自动拆箱。 二、自动装箱和自动拆箱的原理 在底层,自动装箱和自动拆箱是通过Java编译器的特殊处理来实现的。当编译器发现需要自动装箱时,它会在编译阶段将代码转换为创建包装类对象的代码。同样地,当编译器发现需要自动拆箱时,它会在编译阶段将代码转换为从包装类对象中提取基本数据类型的代码。 编译器执行自动装箱和自动拆箱流程: 识别自动装箱:当编译器遇到基本数据类型和对应的包装类之间的转换时,它会识别出需要进行自动装箱的地方。例如,当我们将一个int类型的变量赋值给一个Integer类型的变量时,编译器会发现这个转换操作需要自动装箱。 插入valueOf()方法调用:一旦编译器确定需要进行自动装箱,它会将代码转换为调用包装类的valueOf()方法来完成装箱操作。例如,将int赋值给Integer时,编译器会将代码转换为类似于Integer.valueOf(int)的形式。 生成装箱后的对象:valueOf()方法会返回一个对应的包装类对象,将基本数据类型的值封装起来。编译器会生成代码来创建这个包装类对象,并将其赋值给目标变量。例如,将int赋值给Integer时,编译器会生成代码类似于Integer obj = Integer.valueOf(intValue)。 识别自动拆箱:编译器还会识别需要进行自动拆箱的地方,例如,将一个包装类对象与基本数据类型进行比较或参与运算。 插入xxxValue()方法调用:一旦编译器确定需要进行自动拆箱,它会将代码转换为调用包装类的xxxValue()方法来提取基本数据类型的值。例如,将Integer与int进行相加时,编译器会将代码转换为类似于intValue()的形式。 使用提取的基本数据类型值:xxxValue()方法会从包装类对象中提取出基本数据类型的值,并将其用于运算或比较操作。编译器会生成代码来使用这个提取的基本数据类型值。例如,将Integer与int进行相加时,编译器会生成代码类似于int result = intValue + intValue2。 需要注意的是,自动装箱和自动拆箱虽然方便了开发和编码,但在一些特定的场景下也可能导致性能问题。因为自动装箱和自动拆箱涉及到对象的创建和销毁,可能会引发额外的内存开销和垃圾回收的压力。因此,在性能敏感的代码中,应该谨慎使用自动装箱和自动拆箱,可以选择使用基本数据类型来提高性能。 三、自动装箱和自动拆箱的应用 自动装箱和自动拆箱在Java编程中广泛应用于各种场景,特别是在集合框架中。例如,我们经常使用ArrayList来存储一组数据,而ArrayList只能存储对象类型。在这种情况下,我们可以使用自动装箱将基本数据类型转换为对应的包装类,然后将其添加到ArrayList中。 另一个常见的应用是在方法参数传递和返回值中。方法通常定义为使用包装类作为参数或返回值,以便能够处理各种类型的数据。通过自动装箱和自动拆箱,我们可以方便地在基本数据类型和包装类之间进行转换,从而使方法的调用更加灵活和方便。 此外,自动装箱和自动拆箱还可以简化条件判断和循环操作。例如,我们可以使用自动拆箱将一个Integer类型的变量与一个int类型的常量进行比较,而无需手动进行类型转换。 总结: 自动装箱和自动拆箱是Java语言中的一种语法糖,用于简化基本数据类型和包装类之间的转换过程。自动装箱通过调用valueOf()方法将基本数据类型转换为包装类对象,自动拆箱通过调用xxxValue()方法提取包装类对象中的基本数据类型值。这种特性在集合框架、方法参数传递和返回值等场景中得到广泛应用。 ———————————————— 原文链接:https://blog.csdn.net/DU9999999/article/details/132883399
-
为什么Java需要自动装箱和拆箱这一机制呢? 简单来说,就是有些历史原因的。 比如,泛型(Java5引入),Java中的泛型只能使用引用类型,不能使用基本数据类型。还有集合框架(Java2引入),Java 的集合框架(如 List、Set、Map 等)只能存储对象(引用类型),不能存储基本数据类型。因此为了API的兼容性,代码的灵活性和便利性,就有了自动装箱和拆箱机制。 下边一起来体会下这个机制。 1、Java 中的自动装箱 自动装箱是 Java 编译器在基本类型和它们对应的包装类之间进行的自动转换。例如,将 int 类型转换为 Integer 类型,将 double 类型转换为 Double 型等等。 如果转换以相反的方式进行,则称为拆箱。// 包装类和基本数据类型的相互转换 下面是一个最简单的自动装箱例子: Character ch = 'a'; 例如,下面的代码: List<Integer> li = new ArrayList<>(); for (int i = 1; i < 50; i += 2){ li.add(i); } 尽管将 int 值作为基本类型而不是 Integer 对象添加到 li 列表,但是代码仍然可以编译。这里 li 是一个 Integer 对象的列表,而不是 int 值的列表,为什么 Java 编译器不会发出编译时错误呢? 编译器之所以不会产生错误,是因为它从 i 创建了一个 Integer 对象,并将该对象添加到 li 列表。因此,编译器在运行时实际是将前面的代码转换为以下代码: List<Integer> li = new ArrayList<>(); for (int i = 1; i < 50; i += 2){ li.add(Integer.valueOf(i)); //装箱 } Integer.valueOf(i) 这段代码里有什么呢?//自动装箱 //源码版本:java17 public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); } Java 在拆箱的过程中,创建了一个新的对象(new Integer),既然创建了额外的对象,就增加内存开销和垃圾回收的负担,这也是为什么要避免频繁进行大量的自动装箱和拆箱操作的原因。//自动装箱和拆箱涉及到创建和销毁额外的对象,即包装类对象 在以下情况下,Java 编译器会对基本类型的值进行自动装箱: 把基本类型的值作为参数传递给需要相应包装类的对象的方法。 把基本类型的值赋给相应包装类的变量。 2、Java 中的自动拆箱 接下来,看一下Java中的自动拆箱,例如下边的代码: public static int sumEven(List<Integer> li) { int sum = 0; for (Integer i: li){ if (i % 2 == 0){ sum += i; } return sum; } } 求余运算符 (%) 和一元运算符 (+=) 并不适用于 Integer 对象,但 Java 编译器在编译该方法时却不会产生任何错误,因为在调用 intValue() 方法时,Java 会将 Integer 转换为 int: public static int sumEven(List<Integer> li) { int sum = 0; for (Integer i : li) if (i.intValue() % 2 == 0) //拆箱操作 sum += i.intValue(); return sum; } 将包装类型(Integer)的对象转换为其对应的基本类型(int)称为拆箱。在以下情况下,Java 编译器会对包装类型的值进行自动拆箱: 把包装类型的值作为参数传递给需要相应基本类型的值的方法。 把包装类型的值赋值给相应基本类型的变量。 下边的例子展示了拆箱是如何工作的: import java.util.ArrayList; import java.util.List; public class Unboxing { public static void main(String[] args) { Integer i = new Integer(-8); // 1. 通过方法调用进行拆箱 int absVal = absoluteValue(i); System.out.println("absolute value of " + i + " = " + absVal); List<Double> ld = new ArrayList<>(); ld.add(3.1416); // Π 通过方法调用自动装箱。 // 2. 通过赋值进行拆箱 double pi = ld.get(0); System.out.println("pi = " + pi); } public static int absoluteValue(int i) { return (i < 0) ? -i : i; } } 该程序会打印以下内容: absolute value of -8 = 8 pi = 3.1416 3、自动装箱和拆箱总结 自动装箱和拆箱可以让开发人员编写更加清晰的代码,使代码更加易于阅读。下表列出了基本类型及其对应的包装类,Java 编译器会使用它们进行自动的装箱和拆箱: 基本类型 包装类型 boolean Boolean byte Byte char Character float Float int Integer long Long short Short double Double 自动装箱和拆箱的实现是通过 Java 编译器在编译时进行的。具体来说,Java 编译器会将自动装箱和拆箱操作转换为对应的方法调用,以实现基本数据类型和包装类型之间的转换。 但这在性能方面是要付出代价的。装箱后的值本质上就是把原始类型包裹起来,并保存在堆里。因此,装箱后的值需要更多的内存,并需要额外的内存搜索来获取被包裹的原始值。//所以,应该尽量避免不必要的装箱 4、在 Java 中怎样避免自动装箱和拆箱? 就一条原则:尽量使用基本数据类型 尽可能地使用基本数据类型,而不是对应的包装类型。基本数据类型的数据存储在栈中,而包装类型的对象存储在堆中,因此基本数据类型的操作比包装类型的操作更加高效。 至此,全文结束。 ———————————————— 原文链接:https://blog.csdn.net/swadian2008/article/details/128290566
-
什么是装箱和拆箱 装箱就是自动将基本数据类型转换为包装器类型。 拆箱就是自动将包装器类型转换为基本数据类型。 装箱和拆箱的原理 自动装箱都是通过包装类的 valueOf() 方法来实现的.自动拆箱都是通过包装类对象的 xxxValue() 来实现的。 场景介绍 包装类与基本数据类型进行比较运算,是先将包装类进行拆箱成基本数据类型,然后进行比较的。 两个包装类型之间的运算,会被自动拆箱成基本类型进行计算。 基本数据类型放入集合类中的时候,会进行自动装箱。 三目运算符的使用过程中。当第二,第三位操作数分别为基本类型和对象时,其中的对象就会拆箱为基本类型进行操作。 函数参数与返回值。 装箱缓存 装箱才会使用到缓存。 Byte, Short, Long有固定范围: -128 到 127。对于Character, 范围是 0 到 127。除了Integer以外,这个范围都不能改变。 总结 Ingeter是int的包装类,int的初始值为0,Ingeter的初始值为null。 无论如何,Integer与new Integer()不会相等。不会经历拆箱过程,Integer i8 = new Integer(127)的引用指向堆,而Integer i4 = 127指向专门存放他的内存(常量池),他们的内存地址不一样,使用 == 比较都为false。 两个都是非new出来的Integer,使用 == 比较,如果数在-128到127之间,则是true,否则为false。 他们的内存地址不一样,使用 == 比较都为false两个都是new出来的,==比较都为false。若要比较值是否相等,需使用equals方法进行比较。 int和Integer(无论new否)比较,都为true,因为会把Integer自动拆箱为int再去比。 实验 public class Test { public static void main(String[] args) { // 两个new出来的Integer类型的数据比较,相当于把new出来的地址作比较 Integer a0 = new Integer(1); Integer a1 = new Integer(1); System.out.println("Integer 对象作比较 a0 == a1: " + (a0 == a1)); // 调用intValue方法得到其int值 System.out.println("使用intValue得到int值作比较 a0 == a1: " + (a0.intValue() == a1.intValue())); // 把Integer类型的变量拆箱成int类型 int a2 = 1; System.out.println("将Integer自动拆箱 a1 == a2: " + (a1 == a2)); // Integer对象赋值比较,其实也是内存地址的比较 // 自动装箱,如果在-128到127之间,则值存在常量池中 Integer a3 = 30; Integer a4 = 30; System.out.println("Integer对象赋值比较 a3 == a4: " + (a3 == a4)); // Integer对象赋值(超过-128~127区间)比较 Integer a5 = 128; Integer a6 = 128; System.out.println("Integer对象赋值(超过-128~127区间)比较 a5 == a6: " + (a5 == a6)); // Integer对象赋值(超过-128~127区间)比较,调用intValue后再作比较 Integer a7 = 128; Integer a8 = 128; System.out.println("Integer对象赋值(超过-128~127区间)比较,调用intValue后 a7 == a8: " + (a7.intValue() == a8.intValue())); // 使用Integer类的equals()方法进行的是数值的比较 Integer a9 = 129; Integer a10 = 129; System.out.println("Integer类的equals()方法进行的是数值的比较 a9 == a10: " + a9.equals(a10)); } } ———————————————— 原文链接:https://blog.csdn.net/xiaowanzi_zj/article/details/122465712
-
自动装箱和拆箱问题是Java中一个老生常谈的问题了,今天我们就来一些看一下装箱和拆箱中的若干问题。本文先讲述装箱和拆箱最基本的东西,再来看一下面试笔试中经常遇到的与装箱、拆箱相关的问题。 一.什么是装箱?什么是拆箱? 我们知道 Java为每种基本数据类型都提供了对应的包装器类型,至于为什么会为每种基本数据类型提供包装器类型在此不进行阐述,有兴趣的朋友可以查阅相关资料。在Java SE5之前,如果要生成一个数值为10的Integer对象,必须这样进行: Integer i = new Integer(10); 而在从Java SE5开始就提供了自动装箱的特性,如果要生成一个数值为10的Integer对象,只需要这样就可以了: Integer i = 10; 这个过程中会自动根据数值创建对应的 Integer对象,这就是装箱。 那什么是拆箱呢?顾名思义,跟装箱对应,就是自动将包装器类型转换为基本数据类型: Integer i = 10; //装箱 nt n = i; //拆箱 简单一点说,装箱就是 自动将基本数据类型转换为包装器类型;拆箱就是 自动将包装器类型转换为基本数据类型。 下表是基本数据类型对应的包装器类型: int(4字节) Integer byte(1字节) Byte short(2字节) Short long(8字节) Long float(4字节) Float double(8字节) Double char(2字节) Character boolean(未定) Boolean 二.装箱和拆箱是如何实现的 上一小节了解装箱的基本概念之后,这一小节来了解一下装箱和拆箱是如何实现的。 我们就以Interger类为例,下面看一段代码: public class Main { public static void main(String[] args) { Integer i = 10; int n = i; } } 反编译class文件之后得到如下内容: 从反编译得到的字节码内容可以看出,在装箱的时候自动调用的是Integer的valueOf(int)方法。而在拆箱的时候自动调用的是Integer的intValue方法。 其他的也类似,比如Double、Character,不相信的朋友可以自己手动尝试一下。 因此可以用一句话总结装箱和拆箱的实现过程: 装箱过程是通过调用包装器的valueOf方法实现的,而拆箱过程是通过调用包装器的 xxxValue方法实现的。(xxx代表对应的基本数据类型)。 三.面试中相关的问题 虽然大多数人对装箱和拆箱的概念都清楚,但是在面试和笔试中遇到了与装箱和拆箱的问题却不一定会答得上来。下面列举一些常见的与装箱/拆箱有关的面试题。 1.下面这段代码的输出结果是什么? public class Main { public static void main(String[] args) { Integer i1 = 100; Integer i2 = 100; Integer i3 = 200; Integer i4 = 200; System.out.println(i1==i2); System.out.println(i3==i4); } } 也许有些朋友会说都会输出false,或者也有朋友会说都会输出true。但是事实上输出结果是: true false 为什么会出现这样的结果?输出结果表明i1和i2指向的是同一个对象,而i3和i4指向的是不同的对象。此时只需一看源码便知究竟,下面这段代码是Integer的valueOf方法的具体实现: public static Integer valueOf(int i) { if(i >= -128 && i <= IntegerCache.high) return IntegerCache.cache[i + 128]; else return new Integer(i); } 而其中IntegerCache类的实现为: private static class IntegerCache { static final int high; static final Integer cache[]; static { final int low = -128; // high value may be configured by property int h = 127; if (integerCacheHighPropValue != null) { // Use Long.decode here to avoid invoking methods that // require Integer's autoboxing cache to be initialized int i = Long.decode(integerCacheHighPropValue).intValue(); i = Math.max(i, 127); // Maximum array size is Integer.MAX_VALUE h = Math.min(i, Integer.MAX_VALUE - -low); } high = h; cache = new Integer[(high - low) + 1]; int j = low; for(int k = 0; k < cache.length; k++) cache[k] = new Integer(j++); } private IntegerCache() {} } 从这2段代码可以看出,在通过valueOf方法创建Integer对象的时候,如果数值在[-128,127]之间,便返回指向IntegerCache.cache中已经存在的对象的引用;否则创建一个新的Integer对象。 上面的代码中i1和i2的数值为100,因此会直接从cache中取已经存在的对象,所以i1和i2指向的是同一个对象,而i3和i4则是分别指向不同的对象。 2.下面这段代码的输出结果是什么? public class Main { public static void main(String[] args) { Double i1 = 100.0; Double i2 = 100.0; Double i3 = 200.0; Double i4 = 200.0; System.out.println(i1==i2); System.out.println(i3==i4); } } 也许有的朋友会认为跟上面一道题目的输出结果相同,但是事实上却不是。实际输出结果为: false false 至于具体为什么,读者可以去查看Double类的valueOf的实现。 在这里只解释一下为什么Double类的valueOf方法会采用与Integer类的valueOf方法不同的实现。很简单:在某个范围内的整型数值的个数是有限的,而浮点数却不是。 注意,Integer、Short、Byte、Character、Long这几个类的valueOf方法的实现是类似的。 Double、Float的valueOf方法的实现是类似的。 3.下面这段代码输出结果是什么: public static final Boolean TRUE = new Boolean(true); /** * The <code>Boolean</code> object corresponding to the primitive * value <code>false</code>. */ public static final Boolean FALSE = new Boolean(false); 至此,大家应该明白了为何上面输出的结果都是true了。 4.谈谈Integer i = new Integer(xxx)和Integer i =xxx;这两种方式的区别。 当然,这个题目属于比较宽泛类型的。但是要点一定要答上,我总结一下主要有以下这两点区别: 1)第一种方式不会触发自动装箱的过程;而第二种方式会触发; 2)在执行效率和资源占用上的区别。第二种方式的执行效率和资源占用在一般性情况下要优于第一种情况(注意这并不是绝对的)。 5.下面程序的输出结果是什么? public class Main { public static void main(String[] args) { Integer a = 1; Integer b = 2; Integer c = 3; Integer d = 3; Integer e = 321; Integer f = 321; Long g = 3L; Long h = 2L; System.out.println(c==d); System.out.println(e==f); System.out.println(c==(a+b)); System.out.println(c.equals(a+b)); System.out.println(g==(a+b)); System.out.println(g.equals(a+b)); System.out.println(g.equals(a+h)); } } 先别看输出结果,读者自己想一下这段代码的输出结果是什么。这里面需要注意的是:当 “==”运算符的两个操作数都是 包装器类型的引用,则是比较指向的是否是同一个对象,而如果其中有一个操作数是表达式(即包含算术运算)则比较的是数值(即会触发自动拆箱的过程)。另外,对于包装器类型,equals方法并不会进行类型转换。明白了这2点之后,上面的输出结果便一目了然: true false true true true false true 第一个和第二个输出结果没有什么疑问。第三句由于 a+b包含了算术运算,因此会触发自动拆箱过程(会调用intValue方法),因此它们比较的是数值是否相等。而对于c.equals(a+b)会先触发自动拆箱过程,再触发自动装箱过程,也就是说a+b,会先各自调用intValue方法,得到了加法运算后的数值之后,便调用Integer.valueOf方法,再进行equals比较。同理对于后面的也是这样,不过要注意倒数第二个和最后一个输出的结果(如果数值是int类型的,装箱过程调用的是Integer.valueOf;如果是long类型的,装箱调用的Long.valueOf方法)。 如果对上面的具体执行过程有疑问,可以尝试获取反编译的字节码内容进行查看。 ———————————————— 原文链接:https://blog.csdn.net/omygodvv/article/details/135480392
-
Java是一门面向对象的编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承、指针等概念,因此Java语言具有功能强大和简单易用两个特征。Java语言作为静态面向对象编程语言的代表,极好地实现了面向对象理论,允许程序员以优雅的思维方式进行复杂的编程。Java具有简单性、面向对象、分布式、健壮性、安全性、平台独立与可移植性、多线程、动态性等特点。 Java可以编写桌面应用程序、Web应用程序、分布式系统和嵌入式系统应用程序等。包装类: 在实际开发中,我们很多时候,需要将基本类型转为引用类型,便于后期的操作, 这个时候,java就给我们提供了8种包装类,分别是 基本类型 包装类 byte —Byte short — Short int — Integer long — Long char — Character float — Float double — Double boolean — Boolean 如何学习java中的类型 1:类型的解释 2:父类,子类,接口 3:jdk的版本 4:构造器 5:常用属性 6:常用方法 Integer 类在对象中包装了一个基本类型 int 的值。Integer 类型的对象包含一个 int 类型的字段。 父类:Number 父接口:Serializable,序列化接口 Comparable 自然比较接口 构造器 构造方法摘要 Integer(int value) 构造一个新分配的 Integer 对象,它表示指定的 int 值。 Integer(String s) 构造一个新分配的 Integer 对象,它表示 String 参数所指示的 int 值 属性 MAX_VALUE int的最大值 MIN_VALUE int的最小值 方法 转换方法 获取方法 设置方法 判断方法 注意:Integer范围值 在[-128,127] 的值,是直接声明在一个Integer数组中的,这个数组是一个final类型的数组 所以,存在的内存在常量池中,所以获取-128-127 之间的值,直接去常量池获取,即可,不用创建Integer对象,节省内存空间 其他几种包装类和Integer类似! 如何把字符串转为int? int a = Integer.parseInt(“100”)’ public static void main(String[] args) { //Integer it = new Integer(100); //自动装箱功能:把int类型自动装载到Integer中 先装箱,再赋值 //Integer it2 = 200; //Integer it3 = Integer.valueOf(100); //System.out.println(it2); //自动拆箱功能:把Integer类型中int值取出来 //Integer it4 = it2+it3; //先对it2 和 it3做拆箱功能,然后相加, 得到一个int类型的值,然后在对这个int类型的值 ,做装箱操作,最后再赋值 //Integer it4 = Integer.valueOf(it2.intValue() + it3.intValue()); //System.out.println(it4); //System.out.println(it2+100); 获取int类型的最大值和最小值 所以,存在的内存在常量池中,所以获取-128-127 之间的值,直接去常量池获取,即可,不用创建Integer对象,节省内存空间 int max_value = 2147483647; System.out.println(Integer.MAX_VALUE); System.out.println(Integer.MIN_VALUE); Integer it6 = new Integer("abc"); //NumberFormatException Integer it7 = 1000; byte b = it7.byteValue(); System.out.println(b); Integer it1 = 100; Integer it2 = 100; Integer it3 = new Integer(100); Integer it4 = new Integer(100); 在地址符做比较 System.out.println(it1==it2); //true System.out.println(it1==it3); //false System.out.println(it2==it3); //false System.out.println(it3==it4); //false System.out.println(it1.equals(it2)); System.out.println(it1.equals(it3)); System.out.println(it2.equals(it3)); System.out.println(it3.equals(it4)); 在数字上做比较 结果为0代表数字相等,结果为1,代表当前对象比你传进来的对象的值大,-1 反之则小 System.out.println(it1.compareTo(it2)); System.out.println(it1.compareTo(it4)); System.out.println(it4.compareTo(it1)); 将字符串解码为Integer System.out.println(Integer.decode("1001")+100); 在实际开发 System.out.println(0.00001+0.00004f); //数字必须精确 把Integer转为int Integer it = 1024; System.out.println(it.intValue()); 将字符串参数作为有符号的十进制整数进行解析。 /*System.out.println(Integer.parseInt("-100")); System.out.println(Integer.parseInt("100")); 使用第二个参数指定的基数,将字符串参数解析为有符号的整数。 System.out.println(Integer.parseInt("200", 10)); System.out.println(Integer.reverse(100));*/ 把10进制的数字转为2进制,8进制,16进制的字符串 System.out.println(Integer.toBinaryString(100)); System.out.println(Integer.toHexString(100)); System.out.println(Integer.toOctalString(100)); 把10进制的数字转为任意进制 范围2-36进制 System.out.println(Integer.toString(100, 16)); } ———————————————— 原文链接:https://blog.csdn.net/fengbingbing1/article/details/85267299
-
基本类型和包装类之间的转换基本类型和包装类之间经常需要互相转换,以 Integer 为例(其他几个包装类的操作雷同哦):在 JDK1.5 引入自动装箱和拆箱的机制后,包装类和基本类型之间的转换就更加轻松便利了。那什么是装箱和拆箱呢?我们分别来看下装箱:把基本类型转换成包装类,使其具有对象的性质,又可分为手动装箱和自动装箱拆箱:和装箱相反,把包装类对象转换成基本类型的值,又可分为手动拆箱和自动拆箱在实际转换时,使用Integer类的构造方法和Integer类内部的intValue方法实现这些类型之间的相互转换,实现的代码如下: int n = 10; Integer in = new Integer(100); //将int类型转换为Integer类型 Integer in1 = new Integer(n); //将Integer类型的对象转换为int类型 int m = in.intValue();JDK5.0的一个新特性是自动装箱和自动拆箱。 自动装箱 - 基本类型就自动地封装到与它相似类型的包装中,如:Integer i = 100; - 本质上是,编译器编译时自动添加:Integer i = new Integer(100); 自动拆箱 - 包装类对象自动转换成基本数据类型。如:int a = new Integer(100); - 本质是上,编译器编译时自动添加:int a = new Integer(100).intValue();扩展文章:JAVA菜鸟入门篇 - Java基本数据类型常用包装类(二十六)基本类型和字符串之间的转换在程序开发中,我们经常需要在基本数据类型和字符串之间进行转换。其中,基本类型转换为字符串有三种方法:1. 使用包装类的 toString() 方法2. 使用String类的 valueOf() 方法3. 用一个空字符串加上基本类型,得到的就是基本类型数据对应的字符串再来看,将字符串转换成基本类型有两种方法:1. 调用包装类的 parseXxx 静态方法2. 调用包装类的 valueOf() 方法转换为基本类型的包装类,会自动拆箱PS:其他基本类型与字符串的相互转化这里不再一一列出,方法都类似原文链接:https://blog.csdn.net/weixin_34197488/article/details/86393556
上滑加载中
推荐直播
-
HDC深度解读系列 - Serverless与MCP融合创新,构建AI应用全新智能中枢2025/08/20 周三 16:30-18:00
张昆鹏 HCDG北京核心组代表
HDC2025期间,华为云展示了Serverless与MCP融合创新的解决方案,本期访谈直播,由华为云开发者专家(HCDE)兼华为云开发者社区组织HCDG北京核心组代表张鹏先生主持,华为云PaaS服务产品部 Serverless总监Ewen为大家深度解读华为云Serverless与MCP如何融合构建AI应用全新智能中枢
回顾中 -
关于RISC-V生态发展的思考2025/09/02 周二 17:00-18:00
中国科学院计算技术研究所副所长包云岗教授
中科院包云岗老师将在本次直播中,探讨处理器生态的关键要素及其联系,分享过去几年推动RISC-V生态建设实践过程中的经验与教训。
回顾中 -
一键搞定华为云万级资源,3步轻松管理企业成本2025/09/09 周二 15:00-16:00
阿言 华为云交易产品经理
本直播重点介绍如何一键续费万级资源,3步轻松管理成本,帮助提升日常管理效率!
回顾中
热门标签