什么叫包装类-java语言中有哪些包装类-,简述java的基本类型和对应的包装类型

  什么叫包装类?java语言中有哪些包装类?,简述java的基本类型和对应的包装类型

  00-1010 1.II类包装概述。III类包装的自动装拆机构。封装类IV的缓存机制。四则运算、位运算、比较运算、逻辑运算1、四则运算和位运算2、比较运算和逻辑运算五、将类封装为方法的形参,返回值VI。包装类作为集合VII的一个元素。使用包装类可能造成的空隙。既然有了包装类,为什么还要保留基本数据类型?(包装类的优缺点)

  00-1010Java有八种基本数据类型:整数(字节、短整型、整型、长型)、浮点型(浮点型、双精度型)、布尔型和字符型。相应地,Java提供了八个打包类:字节、短整型、整型、长型、浮点型、双精度型、布尔型和字符型。类创建对象的方式与其他类相同。

  Integer num=新整数(0);//创建一个值为0的整数对象

  00-1010以上构造对象的语句,其实就是基本数据类型到包装类的转换。在应用中,我们经常需要用封装类对象来交换基本类型数据。

  Integer num1=新整数(1);//基础数据类型改为包装类int num 2=num 1 . int value();//包装器类型改为基本数据类型system . out . println(num 1 num 2);Java为我们提供了自动打包和解包机制,方便了我们的使用和其他目的,比如性能调优。这种机制简化了基本类型和打包类型之间的转换。

  //1.整数num1=1,打包类中的自动打包和解包机制;//自动打包int num2=num1//自动拆箱system . out . println(num 1 num 2);当使用jad工具反编译上述代码时,结果如下。

  integer integer=integer . value of(1);int I=integer . int value();system . out . println((new StringBuilder())。追加(整数)。追加( t )。追加(一)。toString());可以看出,Java编译器帮助我们完成了转换操作。此外,我们可以看到,除了使用new关键字,我们还可以使用Integer类的valueOf()方法来创建一个Integer对象。两种方式是有区别的,下面我们会讲到。

  00-1010如前所述,创建打包类对象有两种方法:new关键字和valueOf()方法。让我们看一段代码,感受一下它们之间的区别。

  //2,包装类中缓存机制整数num3=10整数num4=10Integer num5=新整数(20);Integer num6=新整数(20);整数num7=128整数num8=128system . out . println((num 3==num 4) num 3 . equals(num 4));system . out . println((num 5==num 6) num 5 . equals(num 6));system . out . println((num 7==num 8) num 7 . equals(num 8));运行结果是

  我们来看看它的反编译代码。

  integer integer=integer . value of(10);integer integer 1=integer . value of(10);Integer integer2=新整数(20);Integer integer3=新整数(20);integer integer 4=integer . value of(128);integer integer 5=integer . value of(128);system . out . println((new StringBuilder())。append(integer==integer1)。追加( t )。append(integer.equals(integer1))。toString());system . out . println((new StringBuilder())。append(integer2==整数

  3).append("t").append(integer2.equals(integer3)).toString());System.out.println((new StringBuilder()).append(integer4 == integer5).append("t").append(integer4.equals(integer5)).toString());首先,我们查看Integer的valueOf()方法的源码

  

 public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); }

再查看下Integer的内部类IntegerCache的cache数组成员、low、high成员

 

  pre class="brush:java;"> static final int low = -128; static final int high; static final Integer cache[]; static { // high value may be configured by property int h = 127; String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); if (integerCacheHighPropValue != null) { try { int i = parseInt(integerCacheHighPropValue); i = Math.max(i, 127); // Maximum array size is Integer.MAX_VALUE h = Math.min(i, Integer.MAX_VALUE - (-low) -1); } catch( NumberFormatException nfe) { // If the property cannot be parsed into an int, ignore it. } } high = h; cache = new Integer[(high - low) + 1]; int j = low; for(int k = 0; k < cache.length; k++) cache[k] = new Integer(j++); // range [-128, 127] must be interned (JLS7 5.1.7) assert IntegerCache.high >= 127; }可以发现,只要Integer类第一次被使用到,Integer的静态内部类就被加载,加载的时候会创建-128到127的Integer对象,同时创建一个数组cache来缓存这些对象。当使用valueOf()方法创建对象时,就直接返回已经缓存的对象,也就是说不会再新建对象;当使用new关键字or使用valueOf()方法创建小于-128大于127的值对象时,就会创建新对象。

  

//2、包装类中的缓存机制Integer num3 = 10;Integer num4 = 10;Integer num5 = new Integer(20);Integer num6 = new Integer(20);Integer num7 = 128;Integer num8 = 128;

由于num3、num4都小于等于127,它们指向的是同一个缓存的Integer对象,所以用==进行比较的结果是true;num5、num6由于使用new关键字指向的是两个不同的新对象,结果为false;num7、num8虽然是采用自动装箱的方式,但执行valueOf()方法的时候,由于不满足条件i >= IntegerCache.low && i <= IntegerCache.high,而同样新建了两个不同的新对象,结果同样是false。

 

  接着,我们再来看看源码中Integer的equals()方法的实现

  

 public boolean equals(Object obj) { if (obj instanceof Integer) { return value == ((Integer)obj).intValue(); } return false; }

可见equals()方法比较的是Integer对象的值,而不是像==一样比较的是对象是否是同一个对象。所以,当需要比较两个Integer对象的值是否相等时,记住要用equals()方法。用==比较的话由于缓存机制的存在,可能产生一些让人困扰的结果。

 

  此外,在8种包装类型中,有缓存区的有Character、Byte、Short、Integer、Long,而且它们的实现方式基本一样,都是-128到127的缓存范围。Boolean虽然没有缓存区,但是因为只有两个值true、false,所以Boolean在成员变量中就创建了两个相应的对象。没有缓存区的只有Float、Double,之所以没有原因很简单,即便是0到1这么小的范围,浮点数也有无数个,使用缓存区缓存它们不具备可能性和实用性。

  缓存区的存在使得常用的包装类对象可以得到复用,这有利于提升性能。当我们需要创建新对象的时候再new一个,增加了灵活性。

  

 

  

四、包装类的四则运算、位运算、比较运算、逻辑运算

 

  

1、四则运算和位运算

//四则运算、位运算Integer num9 = 1;Integer num10 = 2;Integer num11 = num9 + num10; Short num12 = 5;Integer num13 = num9 + num12;Long num14 = num9 + 10L;System.out.println(num9 << 1);//位运算System.out.println(num9 +""+ num10 +""+ num11 +""+ num12 +""+ num13 +""+ num14);

 

  反编译结果如下

  

Integer integer = Integer.valueOf(1); Integer integer1 = Integer.valueOf(2); Integer integer2 = Integer.valueOf(integer.intValue() + integer1.intValue()); Short short1 = Short.valueOf((short)5); Integer integer3 = Integer.valueOf(integer.intValue() + short1.shortValue()); Long long1 = Long.valueOf((long)integer.intValue() + 10L); System.out.println(integer.intValue() << 1); System.out.println((new StringBuilder()).append(integer).append("t").append(integer1).append("t").append(integer2).append("t").append(short1).append("t").append(integer3).append("t").append(long1).toString());

 

  

可以看到Integer num11 = num9 + num10; 这一句被划分为3个步骤:将两个Integer对象分别进行拆箱;将拆箱得到的两个int数值相加求其和;将和值进行装箱,从而将num11指向缓存数组中值为3的Integer对象。

 

  而Short num12 = 5; 这一句则先将5强制转换成short类型,再将其装箱把值为5的Short对象的引用赋给num12。

  而Integer num13 = num9 + num12; 这一句除了Integer num11 = num9 + num10;的3个步骤,中间还有short+int=int的类型自动提升的过程。

  而Long num14 = num9 + 10L; 这一句Integer num11 = num9 + num10;的3个步骤,中间还有强制类型转换的过程。需要注意的是,如果是Long num14 = num9 + num10; 的话就会出现类型不匹配的错误,因为num9、num10拆箱之后相加的和是int类型,而Long.valueOf(long)需要的形参是long类型,自然会出错。我们也可以看到,当包装类型对象和基本类型数据进行四则运算的时候,对象是会被拆箱的,然后再按基本类型数据的运算规则进行运算。

  另外,如果仅仅是打印两个包装类型对象求和的结果,是不会有将和值重新转换成该包装类型的步骤的,如下面所示

  

System.out.println(num9 + num10);
System.out.println(integer.intValue() + integer1.intValue());

这里还需要注意一点,尽管基本类型与自动类型提升/强制类型转换,包装类是没有类似的用法的。下面的做法是错的。

 

  

Short num3 = 10;Integer num4 = num3;//错误: 不兼容的类型: Short无法转换为IntegerLong num5 = (Long)num4;//错误: 不兼容的类型: Integer无法转换为LongDouble num6 = num5;//错误: 不兼容的类型: Long无法转换为Double

小结:不同包装类型对象是不能直接转换的,不过有两种途径可以代替:一种是上面讨论的不同包装类对象进行四则运算后赋给某一种类型;另一种就是利用包装类的方法

 

  

Integer a = 20;Long b = a.longValue();Short c = b.shortValue();System.out.println(a +""+ b +""+ c);

 

  

2、比较运算和逻辑运算

Integer num9 = 100;Integer num10 = 200;Short num11 = 50;Long num12 = 50L;System.out.println((num9<num10) +""+ (num9<200) +""+ (num9<num11) +""+ (num9<num12) +""+ (num9<10L));

反编译结果为

 

  

Integer integer = Integer.valueOf(100);Integer integer1 = Integer.valueOf(200);Short short1 = Short.valueOf((short)50);Long long1 = Long.valueOf(50L);System.out.println((new StringBuilder()).append(integer.intValue() < integer1.intValue()).append("t").append(integer.intValue() < 200).append("t").append(integer.intValue() < short1.shortValue()).append("t").append((long)integer.intValue() < long1.longValue()).append("t").append((long)integer.intValue() < 10L).toString());

 

  

可以看到,两个同类型的包装类对象进行比较时比较的其实是各自的基本类型数值,如num9 < num10;两个不同类型的包装类对象进行比较时则在比较基本类型数值之前,会有类型提升or强制类型转换,如num9 < num11,num9 < num12。

 

  当想比较两个对象是否相等时,注意要使用equals()方法,从前面的讨论也知道,使用==的话比较的其实是引用的对象是否同一个,一般不满足我们的需求。

  

Integer num13 = new Integer(100);System.out.println(num9.equals(num13) +""+ num9.equals(50));

反编译结果为

 

  

Integer integer2 = new Integer(100);System.out.println((new StringBuilder()).append(integer.equals(integer2)).append("t").append(integer.equals(Integer.valueOf(50))).toString());

 

  

逻辑运算举例:

 

  

System.out.println((num9&1));

反编译结果为

 

  

System.out.println(integer.intValue() & 1);

 

  

五、包装类作为方法的形参、返回值

//包装类作为方法的形参、返回值public static Integer intToInteger(int i) {return i;} public static int integerToInt(Integer i) {return i;}

反编译结果为

 

  

 public static Integer intToInteger(int i) { return Integer.valueOf(i); } public static int integerToInt(Integer integer) { return integer.intValue(); }

 

  

六、包装类作为集合的元素

//包装类作为集合元素List list = new ArrayList();list.add(1);list.add(new Object());Iterator it = list.iterator();while (it.hasNext()) {System.out.println(it.next());}

反编译结果为

 

  

ArrayList arraylist = new ArrayList();arraylist.add(Integer.valueOf(1));arraylist.add(new Object());for(Iterator iterator = arraylist.iterator(); iterator.hasNext(); System.out.println(iterator.next()));

可以发现,虽然集合元素要求是对象,add()方法的形参也是对象(public boolean add(E e)),但由于自动装箱,基本数据类型也可以直接加入集合中。

 

  

 List<Integer> list = new ArrayList<>();for (int i=0; i<5; i++) {list.add(i);}Iterator it = list.iterator();while (it.hasNext()) {System.out.println(it.next());}

反编译结果为

 

  

 ArrayList arraylist = new ArrayList(); for(int i = 0; i < 5; i++) arraylist.add(Integer.valueOf(i)); for(Iterator iterator = arraylist.iterator(); iterator.hasNext(); System.out.println(iterator.next()));

 

  

七、包装类使用过程中有可能引起的空指针异常

//注意包装类可能产生的空引用异常Boolean flag1 = false;System.out.println(flag1?"命题为真":"命题为假");Boolean flag2 = null;System.out.println(flag2?"命题为真":"命题为假");Boolean flag3 = true;

运行结果为

 

  

 

  这里只是简单演示空指针异常。平时使用时需要注意这一点,比如当Boolean的对象作为形参时,在方法执行体的头部需要做下null检测。

  上述代码的反编译结果为

  

Boolean boolean1 = Boolean.valueOf(false); System.out.println(boolean1.booleanValue() ? "u547Du9898u4E3Au771F" : "u547Du9898u4E3Au5047"); Boolean boolean2 = null; System.out.println(boolean2.booleanValue() ? "u547Du9898u4E3Au771F" : "u547Du9898u4E3Au5047"); Boolean boolean3 = Boolean.valueOf(true);

 

  

可见三目运算符的条件表达式的位置一定是boolean值,如果你传入的是Boolean对象,则会自动拆箱转换为boolean值。

 

  另外,三目运算符的其他两个表达式位置也是如此,会把包装类对象转换为相应的基本类型对象。

  

 

  

八、为什么需要包装类?有了包装类又为什么要保留基本数据类型?(包装类的优缺点)

为什么需要包装类?

 

  首先,Java语言是一个面向对象的语言,但是Java中的基本数据类型却是不面向对象的,将每个基本数据类型设计一个对应的类进行代表,这种方式增强了Java面向对象的性质。

  其次,如果仅仅有基本数据类型,那么在实际使用时将存在很多的不便,很多地方都需要使用对象而不是基本数据类型。比如,在集合类中,我们是无法将int 、double等类型放进去的,因为集合的容器要求元素是Object类型。而包装类型的存在使得向集合中传入数值成为可能,包装类的存在弥补了基本数据类型的不足。

  此外,包装类还为基本类型添加了属性和方法,丰富了基本类型的操作。如当我们想知道int取值范围的最小值,我们需要通过运算,如下面所示,但是有了包装类,我们可以直接使用Integer.MAX_VALUE即可。

  

//求int的最大值int max = 0;int flag = 1;for (int i=0; i<31; i++) {max += flag;flag = flag << 1;}System.out.println(max +""+ Integer.MAX_VALUE); //2147483647 2147483647

为什么要保留基本数据类型?

 

  我们都知道在Java语言中,用new关键字创建的对象是存储在堆里的,我们通过栈中的引用来使用这些对象,所以,对象本身来说是比较消耗资源的。对于经常用到的类型,如int等,如果我们每次使用这种变量的时候都需要new一个对象的话,就会比较笨重了。所以,Java提供了基本数据类型,这种数据的变量不需要使用new在堆上创建,而是直接在栈内存中存储,因此会更加高效。

  到此这篇关于Java包装类的文章就介绍到这了,更多相关Java包装类内容请搜索盛行IT以前的文章或继续浏览下面的相关文章希望大家以后多多支持盛行IT!

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: