我们在前面的文章中详细的写了关于类,对象的基本语法,JAVA也提供了一些高级类特性。JAVA为8个基本类型提供了对应的包装类,通过这些包装类可以把8个基本类型的值包装成对象使用,JDK1.5提供了自动装箱和自动拆箱,允许把基本类型值直接赋给对应的包装类引用变量,也允许把包装类对象直接赋给对应的基本类型变量。
JAVA提供了final 关键字来修饰变量,方法和类,系统不允许为final变量重新赋值,子类不允许覆盖父类的final方法,final类不能派生子类。通过使用final关键字,允许JAVA实现不可变类,不可变类会让系统更加安全.
abstract 和interface两个关键字分别用于定义抽象类和接口,抽象类和接口都是从多个子类中抽象出来的共同物征。但抽象类主要作为多类类的模板,而接口则定义了多类应该遵守的规范。enum 关键字则用于创建枚举类,枚举类是一种不能自由创建对象的类,枚举类的对象在定义类时已经固定下来。枚举类特别适合定义像行星,季节这样的类,它们能创建的实例是有限且确定的。
我们现在先看下基本数据类型的包装类
JAVA是面向对象的编程语言,但它也包含了8种基本数据类型,这8个基本数据类型不支持面向对象的编程机制,基本数据类型的数据也不具备“对象”的特性:没有属性,方法可以被调用。JAVA之所以提供这8种基本数据类型,主要是为了照顾程序员传统的习惯。
这8种基本数据类型带来了一定的方便之处,例如可以进行简单,有效的常规数据处理。但在某些时候,基本数据类型就有一些制约,例如所有引用 类型的变量都继承了Object类,都可当成Object类型变量使用。但基本数据类型的变量就不可以,如果有个方法需要Object 类型的参数,但实际需要的值却是2,3等,这可能就比较难以处理。
为了解决8个基本数据类型的变量不能当成Object类型变量使用的问题,JAVA提供了包装类(Wrapper Class)的概念,为了8个基本数据类型分别定义了相应的引用类型,并称之为基本数据类型的包装类。
描述了基本数据类型和包装类之间的对应关系:
从表6.1可以看出,除了int和char两个有点例外之外,8个基本类型对应的包装类都是将其首字母大写即可。
把基本数据类型变量包装成包装类实例是通过对应包装类似构造器来实现的,不仅如此,8个包装类中除了Character之外,还可以通过传入一个字符串参数来构建包装类对象。
那么我们该如何把基本类型变量转换成对应包装类对象,以及如何把一个字符串包装成包装类对象呢?
看代码:
public class Primitive2Wrapper {
public static void main(String[] args) {
boolean b1 = true;
//通过构造器把b1基本类型变量包装成包装类对象 Boolean blobj = new Boolean(b1);
int it =5;
//通过构造器把it基本类型变量包装成包装类对象 Integer itobj = new Integer(it);
//把一个字符串转换成Float 对象 Float f1 = new Float(\"4.56\");
//把一个字符串转换成Boolean 对象 Boolean bobj = new Boolean(\"false\");
//下面程序运行时将出现java.lang.NumberFormatException异常 //Long lobj = new Long(\"ddd\");
//取出Boolean对象里的boolean变量 boolean bb = bobj.booleanValue();
//取出Integer 对象里的int变量 int i = itobj.intValue();
//取出Float 对象里的float变量 float f = f1.floatValue();
} }
上面的程序分别可以把true,5等基本类型变量包装成包装类对象。除此之外,上面程序还通过向包装类构造器里传入一个字符串参数,分别利用\"4.56\等字符串为创建包装类对象。在上面程序的最后一行:Long lObj = new Long(\"ddd\");,这行代码试图把\"ddd\"字符串转换成Long 类型变量,这行代码编译时没有问题,但运行时会引发java.lang.NumbwrFormatException异常。
当试图使用一个字符串来创建Byte ,Short ,Integer,Long,Float,和Double等包装类对象时,如果传入的字符串不能成功转换成对应基本类型变量,则会引发java.lang.NumberFormatException异常。
如果试图使用一个字符串来创建Boolean对象时,如果传入的字符串是“true”,或此字符串不同字母的大小写变化形式,如\"True\",都将创建true对应的Boolean对象;如果传入其他字符串,则会创建false对应的Boolean对象。
我们可以看出基本类型变量和包装类对象的关系:
从图中我们可以看出:JAVA提供的基本类型变量和包装类对象之间转换有点繁琐,但从JDK1.5之后就清除了,JDK1.5提供了自动装箱(Autoboxing)和自动拆箱(AutoUnboxing)功能,所谓自动装箱,就是可以把一个基本类型变量直接赋给对应的包装类变量,或者赋给Object变量(Objectj 是所有类的父类,子类对象可心直接赋给父类变量):自动拆箱则与之相反,允许直接把包装类对象直接赋给一个对应的基本类型变量。
看代码:
public class AutoBoxingUnboxing {
public static void main(String[] args) {
//直接把一个基本类型变量赋给Integer对象 Integer inobj = 5;
//直接把一个boolean类型变量赋给一个object类型的变量 Object boolobj = true;
//直接把一个Integer对象赋给int类型的变量 int it = inobj;
if(boolobj instanceof Boolean) {
//先把object对象强制类型转换为Boolean类型,再赋给boolean变量
boolean b = (Boolean)boolobj; System.out.println(b); } } }
编译结果为:
我们可以知道,当JDK提供了自动装箱和自动拆箱后,大大简化了基本类型变量和包装类对象之间的转换过程。值得指出的是,进行自动装箱和自动拆箱时必须注意类型匹配,例如Integer只能自动拆箱成int类型的变量,不要试图拆箱成boolean类型的变量;与之在似的是,Int类型的变量只能自动装箱成Integer对象(即使赋给Object类型的变量,那只是利用了JAVA的向上自动转型特性),不要试图装箱Boolean对象。
除此之外
包装类还可实现基本类型变量和字符串之音的转换,除了Character之外的怕用包装类都提供了一个parsexxx(String s)静态方法,用于将一个特定字符串转换成基本类型变量;除此之外,在String类里也提供了多个重载valueOf()方法,用于将基本类型变量转换成字符串,
看代码:
public class Primitive2String {
public static void main(String[] args) {
String intStr = \"123\";
//把一个特定字符串转换成int变量 int it = Integer.parseInt(intStr);
System.out.println(\"it的结果是:\"+it);
String floatStr = \"4.56\";
//把一个特定字符串转换成float 变量 float ft = Float.parseFloat(floatStr); System.out.println(ft);
//把一个float变量转换成string变量 String ftStr = string.valueOf(2.345f); System.out.println(ftStr);
//把一个double变量转换成String变量 String dbStr = string.valueOf(3.344); System.out.println(dbStr);
//把一个boolean变量转换成String变量 String boolStr = String.valueOf(true);
System.out.println(boolStr.toUpperCase()); } }
看下编译结果:
通过上面程序可以看出基本类型变量和字符串之间的转换关系
如果希望把基本类型变量转换成字符串,还有一种更简单的方法:将基本类型变量和\"\"进行连接运算,系统会自动把基本类型变量转成字符串, //intStr 的值为\"5\" String intStr = 5 + \"\";
这样就OK了
我们现在也可以看出来一点就是我们在慢慢地介绍JAVA中的类库是的方法了,我们也开始会经常查看JDK开发文档了。
处理对象:
JAVA对象都是Object类的实例,都可直接调用该类中定义的方法,这些方法提供了处理JAVA对象的通用方法。
打印对象和toString 方法
看代码:
class Person {
private String name;
public Person(String name) {
this.name = name; }
public void info() {
System.out.println(\"此人名为:\"+name); } }
public class PrintObject {
public static void main(String[] args) {
//创建一个Person对象,将值赋给P变量 Person p = new Person(\"世界您好!\");
//打印P所引用的Person对象 System.out.println(p); } }
编译的结果为:
细心的读者,可能会发现每次编译都会看到不同的结果:@符号后的6位16进制数字可能发生改变,但这个输出结果是怎么来的呢?System.out.println 方法只能在控制台输出字符串,当使用该方法输出Person对象时,实际上输出的是Person对象的toString()方法的返回值,也就是说,下面两行代码的效果完全一样: System.out.println(p);
System.out.println(p.toString());
toString方法是Objct类里的一个实例方法,所有JAVA类都是Object类的子类,因此所有JAVA对象都具有toString方法。
不仅如此,所有JAVA对象都可以和字符串进地连接运算,当JAVA对象和字符串进行连接运算时,系统会自动调用JAVA对象toString方法的返回值和字符串进行连接运算,即下面两行代码的结果也完全相同: String pStr = p+\"\";
String pStr = p.toString() +\"\";
toString 方法是一个非常特殊的方法,它是一个“自我描述”方法,该方法通常用于实现这亲一个功能:当程序员直接打印该对象时,系统将会输出该对象的\"自我描述\"信息,用以告诉外界该对象具有的状态信息。
Object类提供的toString方法总是返回该对象实现类的类名值,这个返回值并不能真正实现\"自我描述\"的功能,因为如果用户需要自定义类能实现\"自我描述\"的功能,必须重写Object类的toString方法。
看代码:
class Apple {
private String color; private double weight;
public Apple() //显式显示系统的无参数构造器 {
}
public Apple(String color, double weight) {
this.color = color; this.weight = weight; }
//color属性的setter和getter方法 public void setColor (String color) {
this.color = color; }
public String getColor() {
return this.color; }
//weight属性的setter和getter方法 public void setWeight(double weight) {
this.weight = weight; }
public double getWeight() {
return this.weight; }
//重写toString方法,用于实现Apple对象的\"自我描述\"、 public String toString() {
return \"一个苹果,顔色是:\" + color +\重量是:\"+weight; } }
public class TestToString {
public static void main(String[] args) {
Apple a = new Apple(\"红色\
//打印Apple对象 System.out.println(a); } }
编译结果:
从运行结果可以看出,通过重写Apple类的toString 方法,就可以让系统在打印Apple对象时打印出该对象的\"自我描述\"信息。
== 和equals 比较运算符
JAVA程序中测试两个变量是否相等有两种方式,一种是利用==运算符,另外一种是利用equals方法。
当使用==来判断两个变量是否相等时,如果2个变量是基本类型的变量,且都是数值型(但不一定要求数据类型严格相同),只要两个变量的值相等,使用==判断就将返回true.
但对于两个引用类型的变量,必须它们指向同一个对象时,==判断才会返回true。
看代码理解:
public class TestEqual {
public static void main(String[] args) {
int it = 65;
float f1 = 65.0f; //默认情况下是double类型的,所以这里强制转换
//将输出true
System.out.println(\"65和65.0f是否相等?\"+(it == f1));
char ch ='A'; //将输出true
System.out.println(\"65和A是否相等?\"+(it == ch));
String str1 = new String(\"hello\"); String str2 = new String(\"hello\"); 将输出false
Sysem.out.println(\"str1和str2是否相等?\"+(str1 == str2));
将输出true
System.out.println(\"str1是否equals str2?\"+(str1.equals(str2)));
} }
编译结果:
运行上面程序,可以看到65,65.0F和'A'相等。但对于str1和str2,因为它们都是引用类型变量,它们分别指向2个通过new关键字创建的String 对象,因此str1和str2两个变量不相等。
但在很多时候,程序判断两个引用变量是否相等时,也希望有种类似于\"值相等\"的判
断规则,并不严格要求两个引用变量指向同一个对象。例如对于两个字符串变量,可能只是要求它们引用字符串对象里包含的字符序列相同即可认为相等。此时就可以利用String对象的equals方法来判断。
String已经重写了Object的equals()方法,String的equals()方法判断两个字符串相等的标准是:只要两个字符串所包含的字符序列相同,通过equals()比较将返回true;否则将返回false.
equals方法也是Object类提供的一个实例方法,因此所有引用变量都可调用该方法来判断是否与其他引用变量相等。但这个方法判断两个对象相等的标准与==符号没有区别,同样要求两个引用变量指向同一个对象才会返回true。因此这个Object类提供的equals方法没有太大的实际意义,如果希望采用自定义的相等标准,可采用重写equals方法来实现。
现在我们再提下以前写过的一个内容,再加深下印象:
==:等于,如果进行比较的两个操作数都是数值型,即使它们的数据类型不相同,只要它们的值相等,都将返回true,例如97=='a',返回true . 5.0==5也返回true。如果两个操作数都是引用类型,只有当两个引用变量引用的相同类的实例时才可以比较,而且必须这两个引用指向同一个对象才会返回true。JAVA也支持两个boolean类型的值进行比较。例如true == false将返回false。
之所以会重提下,是因为要写到常量池的问题:
public class StringCompareTest {
public static void main(String[] args) {
//s1直接引用常量池中的\"世界您好\" String s1 = \"世界您好\"; String s2 = \"世界\"; String s3 = \"您好\";
//s4后面的字符串值可以在编译时就确定下来 //s4直接引用常量池中的\"世界您好\" String s4 = \"世界\" + \"您好\";
//s5后面的字符串值可以在编译时就确定下来 //s5直接引用常量池中的\"世界您好\" String s5 = \"世\" + \"界\" + \"您好\";
//s6后面的字符串值不能在编译时就确定下来, //不能引用常量池中的字符串 String s6 = s2 + s3;
//使用new调用构造器将会创建一个新的String对象, //s7引用堆内存中新创建的String对象 String s7 = new String(\"世界您好!\");
//输出true
System.out.println(s1 == s4);
//输出true
System.out.println(s1 == s5);
//输出false
System.out.println(s1 == s6);
//输出false
System.out.println(s1 == s7); } }
编译结果:
我们实际上,重写equals方法就是提供自定义的相等标准,你认为怎么相等,那就怎么是相等,一切都是你做主!极端的情况下,你可以让Perso对象 和Dog对象相等,不可思义吧?
看代码:
//定义一个Person类 class Person {
//重写equals方法,提供自定义的相等标准 public boolean equals(Object obj) {
//不加判断,总是返回true,即Person对象与任何对象都相等 return true; } }
//定义一个Dog空类 class Dog{}
//主方法入口
public class OverrideEqualsError {
public static void main(String[] args) {
Person p = new Person();
System.out.println(\"Person对象是否equals Dog对象?\" +p.equals(new Dog()));
//包装类对象
System.out.println(\"Person对象是否equals String对象?\"
+ p.equals(new String(\"Hello\"))); //通过构造器把\"Hello\"基本类型变量包装成包装类对象
System.out.println(\"Person对象是否equals Integer对象?\" + p.equals(new Integer(12))); } }
看编译结果:
从刚才的编译结果,我们可以可看到Person对象和Dog对象相等,Person对象和String对象也相等的\"奇怪结果\"造成这种结果的原因是由于重写了Person类的equals方法时没有任何判断,无条件地返回true。
我们知道大部分时候,我们不希望看到Person对象和Dog对象相等的\"奇怪结果\",我们还是希望两个类型相同的对象才可能相等,而且必须关键属性相等才能相等。
写下面代码之前我想再次提点之前文章中提到过的内容:
JAVA类里属性的setter和getter方法有非常重要的意义,例如某个类里包含了一个名为abc的属性,则其对应的setter和getter方法名应为setAbc和getAbc(即将原属性名的首字母大写,并在前面分别增加set和get动词,就变成setter和getter方法名)。如果一个JAVA类的每个属性都被使用private修饰,并为每个属性都提供了public修饰setter和getter方法,这个类就是一个符合JavaBean规范的类。因此,JavaBean总是一个封装良好的类。
再次重写Person类的equals方法。
//定义一个Person类 class Person {
private String name; private String idStr;
public Person() {
//显式写出系统默认的构造器 }
public Person(String name , String idStr) {
this.name = name; this.idStr = idStr; }
//用到前面提到的setter和getter方法 public void setName(String name) {
this.name = name; }
public String getName() {
return this.name; }
//谁调用这个属性,就是this所指的对象 }
因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- huatuo6.com 版权所有 湘ICP备2023023988号-11
违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务