疯狂Java讲义(六)----第⼀部分
本章要点:
1. Java 8 增强的包装类
Java是⾯向对象的编程语⾔,但它也包含了8种基本数据类型,这8种基本数据类型不⽀持⾯向对象的编程机制,基本数据类型的数据也不具备“对象”的特性:没有成员变量、⽅法可以被调⽤。Java之所以提供这8种基本数据类型,主要是为了照顾程序员的传统习惯。
这8种基本数据类型带来了⼀定的⽅便性,例如可以进⾏简单、有效的常规数据处理。但在某些时候,基本数据类型会有⼀些制约,例如所有引⽤类型的变量都继承了Object 类,都可当成Object类型变量使⽤。但基本数据类型的变量就不可以,如果有个⽅法需要Object类型的参数,但实际需要的值却是2、3等数值,这可能就⽐较难以处理。
为了解决8种基本数据类型的变量不能当成Object类型变量使⽤的问题,Java提供了包装类(Wrapper Class)的概念,为8种基本数据类型分别定义了相应的引⽤类型,并称之为基本数据类型的包装类。
在JDK 1.5以前,把基本数据类型变量变成包装类实例需要通过对应包装类的 valueOf()静态⽅法来实现。在JDK 1.5以前,如果希望获得包装类对象中包装的基本类型变量,则可以使⽤包装类提供的xxxValue()实例⽅法。由于这种⽤法已经过时,故此处不再给出⽰例代码。
通过上⾯介绍不难看出,基本类型变量和包装类对象之间的转换关系如图6.1所⽰。
从图6.1中可以看出,Java提供的基本类型变量和包装类对象之间的转换有点烦琐,但从JDK 1.5之后这种烦琐就消除了,JDK 1.5提供了⾃动装箱((Autoboxing〉和⾃动拆箱(AutoUnboxing)功能。所谓⾃动装箱,就是可以把⼀个基本类型变量直接赋给对应的包装类变量,或者赋给Object变量(Object是所有类的⽗类,⼦类对象可以直接赋给⽗类变量);⾃动拆箱则与之相反,允许直接把包装类对象直接赋给⼀个对应的基本类型变量。
当JDK提供了⾃动装箱和⾃动拆箱功能后,⼤⼤简化了基本类型变量和包装类对象之间的转换过程。值得指出的是,进⾏⾃动装箱和⾃动拆箱时必须注意类型匹配,例如Integer 只能⾃动拆箱成int类型变量,不要试图拆箱成boolean类型变量;与之类似的是,int类型变量只能⾃动装箱成Integer对象(即使赋给Object类型变量,那也只是利⽤了Java的向上⾃动转型特性),不要试图装箱成Boolean对象。
借助于包装类的帮助,再加上JDK 1.5提供的⾃动装箱、⾃动拆箱功能,开发者可以把基本类型的变量“近似”地当成对象使⽤(所有装箱、拆箱过程都由系统⾃动完成,⽆须程序员理会);反过来,开发者也可以把包装类的实例近似地当成基本类型的变量使⽤。
除此之外,包装类还可实现基本类型变量和字符串之间的转换。把字符串类型的值转换为基本类型的值有两种⽅式。
➢利⽤包装类提供的parseXx(String s)静态⽅法(除Character 之外的所有包装类都提供了该⽅法。
➢利⽤包装类提供的valueOf(String s)静态⽅法。
String类也提供了多个重载valueOf(⽅法,⽤于将基本类型变量转换成字符串,下⾯程序⽰范了这种转换关系。
此处要指出的是,虽然包装类型的变量是引⽤数据类型,但包装类的实例可以与数值类型的值进⾏⽐较,这种⽐较是直接取出包装类实例所包装的数值来进⾏⽐较的。
两个包装类的实例进⾏⽐较的情况就⽐较复杂,因为包装类的实例实际上是引⽤类型,只有两个包装类引⽤指向同⼀个对象时才会返回true。下⾯代码⽰范 了这种效果(程序清单同上)。
但JDK1.5以后⽀持所谓的⾃动装箱,⾃动装箱就是可以直接把⼀个基本类型值赋给⼀个包装类实例,在这种情况下可能会出现⼀些特别的情形。看如下代码(程序清单同上)。
上⾯程序让⼈⽐较费解:同样是两个int类型的数值⾃动装箱成Integer实例后,如果是两个2⾃动装箱后就相等;但如果是两个128⾃动装箱后就不相等,这是为什么呢?这与Java的Integer类的设计有关,查看Java系统中java.lang.Integer类的源代码,如下所⽰。
从上⾯代码可以看出,系统把⼀个 -128~127之间的整数⾃动装箱成Integer实例,并放⼊了⼀个名为cache的数组中缓存起来。如果以后把⼀个- 128~127之间的整数⾃动装箱成⼀个Integer实例时,实际上是直接指向对应的数组元素,因此-128~127之间的同⼀个整数⾃动装箱成Integer实例时,永远都是引⽤cache数组的同⼀个数组元素,所以它们全部相等;但每次把⼀个不在-128~127范围内的整数⾃动装箱成Integer实例时,系统总是重新创建--个Integer实例,所以出现程序中的运⾏结果。
Java 7增强了包装类的功能,Java 7为所有的包装类都提供了⼀个静态的compare(xxx vall, xxx val2)⽅法,这样开发者就可以通过包装类提供的compare(xxx vall, xxx val2)⽅法来⽐较两个基本类型值的⼤⼩,包括⽐较两个boolean类型值,两个boolean类型值进⾏⽐较时,true>false。例如如下代码:
2.打印对象和toString⽅法
上⾯程序创建了⼀个 Person对象,然后使⽤System.out.println()⽅法输出Person 对象。编译、运⾏上⾯程序,看到如下运⾏结果: .
当使⽤该⽅法输出Person对象时,实际上输出的是Person对象的toString()⽅法的返回值。也就是说,下⾯两⾏代码的效果完全⼀样。
toString()⽅法是Object类⾥的⼀个实例⽅法,所有的Java类都是Object类的⼦类,因此所有的Java对象都具有toString()⽅法。
java的tostring方法不仅如此,所有的Java对象都可以和字符串进⾏连接运算,当Java对象和字符串进⾏连接运算时,系统⾃动调⽤Java对象toString()⽅法的返回值和字符串进⾏连接运算,即下⾯两⾏代码的结果也完全相同。
⼤部分时候,重写toString()⽅法总是返回该对象的所有令⼈感兴趣的信息所组成的字符串。通常可返回如下格式的字符串:
因此,可以将上⾯Apple类的toString()⽅法改为如下:
3. ==和equals⽅法
== :
当使⽤==来判断两个变量是否相等时,如果两个变量是基本类型变量,且都是数值类型(不⼀定要求数据类型严格相同),则只要两个变量的值相等,就将返回true。
但对于两个引⽤类型变量,只有它们指向同⼀个对象时,==判断才会返回true。 ==不可⽤于⽐较类型上没有⽗⼦关系的两个对象。下⾯程序⽰范了使⽤==来判断两种类型变量是否相等的结果。
运⾏上⾯程序,可以看到65、65.0f 和'A'相等。但对于str1 和str2,因为它们都是引⽤类型变量,它们分别指向两个通过new关键字创建的String对象,因此str1和str2两个变量不相等。
对初学者⽽⾔,String 还有⼀个⾮常容易迷惑的地⽅: "hello" 直接量和new String("hello")有什么区别呢?
当Java程序直接使⽤形如"hello"的字符串直接量(包括可以在编译时就计算出来的字符串值)时,JVM将会使⽤常量池来管理这些字符串;当使⽤new String("hello")时,JVM会先使⽤常量池来管理"hello"直接量,再调⽤String类的构造器来创建⼀个新的String对象,新创建的S tring对象被保存在堆内存中。换句话说,new String("hello")⼀共产⽣了两个字符串对象。
下⾯程序⽰范了JVM使⽤常量池管理字符串直接量的情形。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论