1、 本章本章导读1. 类声明和声明和类体体2. 类体的构成体的构成3.构造方法与构造方法与对象的象的创立立4. 对象的引用与象的引用与实体体5. 成成员变量量6. 方法方法 第第4章章 类与对象类与对象n7. 方法重载n8. this关键字n9. 包n10. import 语句n11. 访问权限n12. 根本类型数据的类包装n13. 反编译和文档生成器序面向对象编程:封装,继承,多态性:一种操作名称的多态性,同名多操作。一种是和继承有关的多态性:指同一个操作被不同类型对象掉用时产生不同的行为。4.1 类声明和类体 类是组成Java程序的根本要素。类封装了一类对象的状态和方法。类是用来定义对象的模板。可以用类创立对象,当使用一个类创立了一个对象时,我们也说给出了这个类的一个实例。 在语法上,类由两局部构成:类声明和类体。根本格式为: class 类名 类体的内容 class是关键字,用来定义类。“class 类名是类的声明局部,类名必须是合法的Java标识符。两个大括号“、“以及之间的内容称作类体。 以下是两个类声明的例子。 class Dog class 机动车 类的名字不能是Java中
2、的关键字,要符合标识符规定,即名字可以由字母、下划线、数字或美元符号组成,并且第一个字符不能是数字。但给类命名时,最好遵守以下习惯: 1如果类名使用拉丁字母,那么名字的首字母使用 大写字母,如Hello、Time、,People 等。 2类名最好容易识别、见名知意。当类名由几个“单词复合而成时,每个单词的首写字母使用大写,如BeijingTime、AmericanGame、HelloChina等。 返回4.2 类体的构成 类体内容可以有2种类型的成员: 1成员变量:通过变量声明定义的变量,称作成员变量或域,用来刻画类创立的对象的属性。将在后面的第3节详细地讨论成员变量。 2方法:方法是类体的重要成员之一。其中的构造方法是具有特殊地位的方法,供类创立对象时使用,用来给出类所创立的对象的初始状态,另一类方法,可以由类所创立的对象调用,对象调用这些方法操作成员变量形成一定的算法,表达对象具有某种功能。 下面是一个类名为“机动车的类,类体内容的变量定义局部定义了2个float类型的变量:“weight、“height和一个int型变量“speed;方法定义局部定义了3个方法:“changSpe
3、ed、“getWeight和“getHeight。 成员变量的类型可以是Java中的任何一种数据类型,包括前面学习过的根本类型:整型、浮点型、字符型、数组以及后面要学习的对象及接口。 成员变量在整个类内都有效,与它在类体中书写的先后位置无关,例如,前述的机动车类也可以写成: class 机动车 int speed; /变量定义局部。 float weight,height; /变量定义局部。 void changSpeed(int newSpeed) /方法定义。 speed=newSpeed; float getWeight() /方法定义。 return weight; float getHeight() /方法定义。 return height; 在定义类的成员变量时可以同时赋予初值,说明类所创立的对象的初始状态。需要注意的是。对成员变量的操作只能放在方法中,方法可以对成员变量进行操作形成算法,如:class A int a=9; float b=12 .6f; void f() a=12; b=12.56f;返回但是不可以这样做:class A int a; float b;
4、a=12; /非法 b=12.56f; /非法void f() 返回 因为,a=12是赋值语句,不是数据的声明。类的成员类型中可以有数据和方法,即数据的定义和方法的定义,但没有语句,语句必须放在方法中。但没有语句,语句必须放在方法中。 返回4.3构造方法与对象的创立 类中有一局部方法称作构造方法,类创立对象时需使用构造方法,以便给类所创立的对象一个合理的初始状态。构造方法是一种特殊方法,它的名字必须与它所在的类的名字完全相同,并且不返回任何数据类型,即它是void型,但void必须省略不写。Java允许一个类中有假设干个构造方法,但这些构造方法的参数必须不同,即或者是参数的个数不同,或者是参数的类型不同。下面的Rect类有两个构造方法: class Rect double sizdA,siddB; Rect() /无参数构造方法。 Rect(double a,double b) /有参数构造方法。 sideA=a; sideB=b; double computerArea() return sideA*sideB; double computerGirth() return (size
5、A+sideB)*2; 当使用一个类创立了一个对象时,我们也说给出了这个类的一个实例。创立一个对象包括对象的声明和为对象分配成员变量两个步骤。 1对象的声明。 一般格式为: 类的名字 对象名字; 如: Rect rectangleOne; rectangleOne null2为声明的对象分配成员变量 使用new运算符和类的构造方法为声明的对象分配成员变量,如果类中没有构造方法,系统会调用默认的构造方法默认的构造方法是无参数的,你一定还记得构造方法的名字必须和类名相同这一规定,上述的Rect类提供了2个构造方法,下面都是合法的创立对象的语句: rectangleOne =new Rect(); 或 rectangleOne =new Rect(10,20); 如果类里定义了一个或多个构造方法,那么Java不提 供默认的构造方法。如果上述Rect只提供一个带参数的构造方法,代码: rectangleOne =new Rect(); 创立对象是非法的。 创立对象的代码: rectangleOne =new Rect(10,20); 会实现下述两件事: 1为成员变量分配内存空间,然后执行构造方
6、法中的语句 。 2给出一个信息,已确保这些成员变量是属于对象 rectangleOne的 。 创立对象就是指为它分配成员变量,并获得一个引用,以确保这些成员变量由它来“操作管理。为对象分配成员变量后,内存模型由声明对象时的模型图4.1,变成如图4.2所示,箭头示意对象可以操作这些属于自己的成员变量。图4.2 分配实体后的对象sideBsideA 20 100xAA11RectangleOne3创立多个不同的对象 一个类通过使用new运算符可以创立多个不同的对象,这些对象将被分配不同的内存空间,因此,改变其中一个对象的状态不会影响其它对象的状态。例如,我们使用前面的Rect类创立两个对象:rectangleOne、rectangleTwo。 rectangleOne =new Rect(10,20); rectangleTwo =new Rect(33,66); 当创立对象rectangleOne时,Rect类中的成员变量sizeA、sizeB被分配内存空间,并返回一个引用给ectangleOne; 当再创立一个对象rectangleTwo时,Rect类中的成员 变量sizeA、size
7、B再一次被分配内存空间,并返回一个 引用给rectangleTwo 。内存模型如图4.3所示。 sideBsideA 20 100xAA11rectangleOne图4.3 创建多个对象sideBsideA 66 330xBB42rectangleTwo 4使用对象 对象不仅可以操作自己的变量改变状态,而且还拥有了使用创立它的那个类中的方法的能力,对象通过使用这些方法可以产生一定的行为。 通过使用运算符“.,对象可以实现对自己的变量访问 和方法的调用。 1对象操作自己的变量对象的属性 2对象调用类中的方法对象的功能 下面例子1中,“Lader类创立了2个对象:laderOne, laderTwo。 返回class Lader double above,bottom,height; Lader(double a,double b,double h) above=a; bottom=b; height=h; public void setAbove(double a) above=a; public void setBottom(double b) bottom=b; public voi
8、d setHeight(double h) height=h; double computeArea() return (above+bottom)*height/2.0; public class Example public static void main(String args) double area1,area2=0; Lader laderOne,laderTwo; laderOne=new Lader(5,10,12); laderTwo=new Lader(10,20.45,20); area1=laderOne puteArea(); area2=laderTwo puteArea(); System.out.printf(laderOne和laderTwo的面积分别是:%n%f,%fn,area1,area2); laderOne.setAbove(10); laderTwo.setBottom(40); area1=laderOne puteArea(); area2=laderTwo puteArea(); System.out.printf(laderOne
9、和laderTwo的面积分别是:%n%f,%fn,area1,area2); 4.4 对象的引用与实体 我们已经知道,当用类创立一个对象时,成员变量被分配内存空间,这些内存空间称做该对象的实体或变量,而对象中存放着引用,以确保这些变量由该对象操作使用。因此,如果两个对象有相同的引用,那么就具有同样的实体。 假设使用例子1“Lader类的构造方法创立了两个对象 t1,t2。 t1=new Lader(11,22,33); t2=new Lader(6,12,18);如果程序中使用了如下的赋值语句: t1=t2;那么:内存中引用t2,t1都指向了t2, t1无引用。 Java具有“垃圾收集机制,Java的运行环境周期地检测某个实体是否已不再被任何对象所引用,如果发现这样的实体,就释放实体占有的内存。因此,Java编程人员不必象C+程序员那样,要时刻自己检查哪些对象应该释放内存。当把变量t2中存放的引用赋给t1后,最初分配给对象t1的成员变量实体所占有的内存就会被释放。 没有实体的对象称作空对象。空对象不能使用,即不能让一个空对象去调用方法产生行为。假设程序中使用了空对象,程序在运行时会出现
10、异常:NullPointerException。由于对象是动态地分配实体,所以Java的编译器对空对象不做检查。因此,在编写程序时要防止使用空对象。 返回4.5 成员变量 用关键字static修饰的成员变量称作静态变量或类变量, 而没有使用static修饰的成员变量称作实例变量。例如,下述A类中,x是实例变量,而y是类变量。 class A float x; static int y; 类变量是与类相关联的数据变量,也就是说,类变量是和该类所创立的所有对象相关联的变量,改变其中一个对象的这个类变量就同时改变了其它对象的这个类变量。 因此,类变量不仅可以通过某个对象访问也可以直接通过类名访问。 实例变量仅仅是和相应的对象关联的变量,也就是说,不同对象的实例变量互不相同,即分配不同的内存空间,改变其中一个对象的实例变量不会影响其它对象的这个实例变量。实例变量必须通过对象访问。 下面例子2中,两个“ Lader对象共享bottom。效果如图4.7 class Lader float above,height; /实例变量。 static float bottom; /类变量。 void se
11、tAbove(float a) above=a; void setBottom(float b) bottom=b; float getAbove() return above; float getBottom() return bottom; class Example public static void main(String args) Lader.bottom=60; /Lader的字节码被加载到内存,通过类名操作类变量。 System.out.println(现在所有Lader对象的bottom都是+Lader.bottom); Lader laderOne,laderTwo; laderOne=new Lader(); laderTwo=new Lader(); System.out.println(laderOne的bottom:+laderOne.getBottom(); System.out.println(laderTwo的bottom:+laderTwo.getBottom(); laderOne.setAbove(11); laderTwo.setAbove(
12、22); laderTwo.setBottom(100); System.out.println(现在所有Lader对象的bottom都是+Lader.bottom); System.out.println(laderOne的above:+laderOne.getAbove(); System.out.println(laderTwo的above:+laderTwo.getAbove(); 2常量 如果一个成员变量修饰为final,就是常量,常量的名字习惯用大写字母,例如: final int MAX; final修饰的成员变量不占用内存,这意味着在声明final成员变量时,必须要初始化。对于final修饰的成员变量,对象可以操作使用,但不能做更改操作。下面的例子给出了常量的用法。效果如图4.9 class Tom final int MAX=100; static final int MIN=20; class Example public static void main(String args) System.out.println(Tom.MIN); Tom tom=new T
13、om(); int x=0; x=Tom.MIN+tom.MAX; System.out.println(x); 返回4.6 方法 我们已经知道,类体内容可以有2种类型的成员:成员变量和方法。其中一局部方法称作构造方法,供类创立对象时使用,用来给出类所创立的对象的初始状态。另一局部方法可分为实例方法和类方法,类所创立的对象可以调用这些方法形成一定的算法,表达对象具有某种功能。当对象调用方法时,方法中出现的成员变量就是指分配给该对象的成员变量。对象不可以调用构造方法,构造方法是专门用来创立对象的。 方法的定义包括两局部:方法声明和方法体。一般格式为:方法声明局部 方法体的内容1方法声明和方法体最根本的方法声明包括方法名和方法的返回类型,返回类型也简称作方法的类型。如:float area() . 方法的名字必须符合标识符规定。在给方法起名字时应遵守以下习惯:名字如果使用拉丁字母,首写字母使用小写。如果由多个单词组成,从第2个单词开始的其它单词的首写字母使用大写。例如 float getTrangleArea() void setCircleRadius(double radius) 等。
14、 方法声明之后的一对大括号“、“以及之间的内容称作方法的方法体。类中的方法必须要有方法体,如果方法的类型是void类型,方法体中也可以不书写任何语句。 2方法体的构成 方法体的内容包括变量的定义和合法的Java语句,在方法体中声明的变量以及方法的参数称作局部变量,局部变量仅仅在该方法内有效。方法的参数在整个方法内有效,方法内定义的局部变量从它定义的位置之后开始有效。写一个方法和C语言中写一个函数完全类似,只不过在这里称作方法。局部变量的名字必须符合标识符规定,遵守习惯:名字如果使用拉丁字母,首写字母使用小写。如果由多个单词组成,从第2个单词开始的其它单词的首写字母使用大写。 3实例方法与类方法 除构造方法外,其他的方法可分为实例方法和类方法。方法声明中用关键字static修饰的称作类方法或静态方法,不用static修饰的称作实例方法。一个类中的方法可以互相调用:实例方法可以调用该类中实例方法或类方法;类方法只能调用该类的类方法,不能调用实例方法;如:class A float a,b; void sum(float x,float y) a=max(x,y); b=min(x,y);
15、static float getMaxSqrt(float x,float y) float c; c=max(x,y)*max(x,y); return c; static float max(float x,float y) return xy?x:y; float min(float x,float y) return xb?a:b; class Example public static void main(String args) double max=Computer.max(12,45); /类名调用类方法。 System.out.println(max); 4参数传值 当方法被调用时,如果方法有参数,参数必须要实例化,即参数变量必须有具体的值。在Java中,方法的所有参数都是“传值的,也就是说,方法中参数变量的值是调用者指定的值的拷贝。如果向方法的int型参数x传递一个int值,那么参数x得到的值是传递值的拷贝。方法如果改变参数的值,不会影响向参数“传值的变量的值。 1根本数据类型参数的传值 下面的例子5中,向一个方法的根本型参数传值。效果如图4.11 class To
16、m void f(int x,double y) x=x+1; y=y+1; System.out.printf(参数x和y的值分别是:%d,%fn,x,y); public class Example public static void main(String args) int x=10; double y=12.58; Tom tom=new Tom(); tom.f(x,y); /方法 f中有一次打印,打印方法中的x,y System.out.printf(main方法中x和y的值仍然分别是:%d,%fn,x,y); 2引用类型参数的传值 Java的引用型数据包括我们以前学习过的对象、数组 以及后面将要学习的接口。当参数是引用类型时,“传值传递的是变量的引用而不是变量所引用的实体。 图4.13 引用类型参数的传值 如果改变参数变量所引用的实体,就会导致原变量的实体发生同样的变化,因为,两个引用型变量如果具有同样的引用,就会用同样的实体。但是,改变参数的引用不会影响向其传值的变量的引用。 下面的例子6向一个方法的引用型参数传值。效果如图4.13 class Tom void f
17、(Jerry a) /对象传递引用 a.setLeg(12); System.out.println(参数a的成员leg的值:+a.getLeg(); a=null; class Jerry int leg; Jerry(int n) leg=n; void setLeg(int n) leg=n; int getLeg() return leg; public class Example public static void main(String args) Tom tom=new Tom(); Jerry jerry=new Jerry(2); System.out.println(在调用方法f之前,jerry的成员leg的值:+jerry.getLeg(); tom.f(jerry); System.out.println(在调用方法f之后,jerry的成员leg的值:+jerry.getLeg(); 在上述例子6中,tom调用方法f把对象jerry的引用“传值给参数a后,对象jerry和对象a就具有同样的成员变量,即同样实体。因此,jerry和a就具有同样的功能,也就是说a调
18、用方法产生的行为和jerry调用同一方法产生的行为完全相同。当对象a执行 a=null; 后,a就不再有任何实体,变成一个空对象,如果再执行: a.setLeg(100);就会引起NullPointerExcetion异常。但是,jerry的引用没有发生任何变化,它依然引用着原来的实体,仍然可以调用方法产生行为。 在下面的例子7中,“Cone类在创立对象时,将一个“Circle对象的引用“传值给“Cone对象的“bottom。效果如图4.14 class Circle double radius; Circle(double r) radius=r; double computerArea() return 3.14*radius*radius; void setRadius(double newRadius) radius=newRadius; double getRadius() return radius; class Cone Circle bottom; double height; Cone(Circle c,double h) bottom=c; height=h; do
19、uble computerVolume() double volume; volume=bottom puterArea()*height/3.0; return volume; void setBottomRadius(double r) bottom.setRadius(r); double getBottomRadius() return bottom.getRadius(); class Example public static void main(String args) Circle circle=new Circle(10); Cone circular=new Cone(circle,20); System.out.println(circular的bottom半径:+circular.getBottomRadius(); System.out.println(circular的体积:+circular puterVolume(); circular.setBottomRadius(100); System.out.println(circular的bottom半径:
20、+circular.getBottomRadius(); System.out.println(circular的体积:+circular puterVolume(); 返回4.8 方法重载 方法重载是指一个类中可以有多个方法具有相同的名字,但这些方法的参数必须不同,即或者是参数的个数不同,或者是参数的类型不同。方法的返回类型和参数的名字不参与比较,也就是说,如果两个方法的名字相同,即使类型不同,也必须保证参数不同。 下面例4-8 Area类中getArea方法是一个重载方法。效果如图4.15 class People double getArea(double x,int y) return x*y; int getArea(int x,double y) return (int)(x*y); double getArea(float x,float y,float z) return (x*x+y*y+z*z)*2.0; public class Example4_8 public static void main(String args) People zhang=new Peo
21、ple(); System.out.println(面积:+zhang.getArea(10,3.88); System.out.println(面积:+zhang.getArea(10.0,8); 返回4.9 this 关键字 this是Java的一个关键字,可以出现在实例方法和构造方法中,但不可以出现在类方法中。 1在构造方法中使用this this关键字可以出现在类的构造方法中,代表使用该 构造方法所创立的对象。 下述例子9中的构造方法中出现了this,表示该对象在构造自己时调用了方法cry()。 2在实例方法中使用this this关键字可以出现在类的实例方法中,代表使用该方法的当前对象。class Tom int leg; Tom(int n) this.cry(); leg=n; this.cry(); void cry() System.out.println(我是Tom ,我现在有+leg+条腿); public static void main(String args) Tom tom=new Tom(4); 我们已经知道,实例方法可以操作成员变量。实际上,当成员变量
22、在实例方法中出现时,默认的格式是: this.成员变量; 意思是当前对象的成员变量,如: class A int x; void f() this.x=100; 在上述A类中的实例方法f中出现了this,this就代表使用f的当前对象。所以,this.x就表示当前对象的变量x,当对象调用方法f时,将100赋给该对象的变量x。因此,当一个对象调用方法时,方法中的成员变量就是指分配给该对象的成员变量。因此,通常情况下,可以省略成员变量名字前面的“this.。 我们知道类的实例方法可以调用类的其它方法,调用的默认格式是 this.方法; 如:class B void f() this.g(); /对象调用方法f时又调用了方法g。 void g() System.out.println(ok); 在上述B类中的方法f中出现了this,this代表使用方法f的当前对象,所以,方法f的方法体中this.g()就是当前对象调用方法g,也就是说,当某个对象调用方法f过程中,又调用了方法g。由于这种逻辑关系非常明确,一个方法调用另一个方法时可以省略方法名字前面的“this.。 3类方法中不可以使用thi
23、s this不能出现在类方法中,这是因为,类方法可以通过类名直接调用,这时,可能还没有任何对象诞生。 4使用this区分成员变量和局部变量 我们已经知道,成员变量在整个类内有效,局部变量仅在方法内有效。在方法体中声明的变量以及方法的参数称作局部变量,方法的参数在整个方法内有效,方法内定义的局部变量从它定义的位置之后开始有效。 如果局部变量的名字与成员变量的名字相同,那么成员变量被隐藏,即这个成员变量在这个方法内暂时失效。如: 返回 class Tom int x=188, y; void f() int x=3; y=x; /y得到的值是3,不是188。如果方法f 中没有“int x=3;语句,y的值将是188。 这时如果想在该方法内使用成员变量,成员变量前面的“this.就不可以省略,如:返回 class 三角形 float sideA, sideB, sideC, lengthSum; void setSide(float sideA, float sideB, float sideC) this.sideA=sideA; this.sideB=sideB; this.sideC=
24、sideC; this.sideA、this.sideB、this.sideC就分别表示当前对象的成员变量sideA、sideB、sideC。 返回4.10 包 通过关键字package声明包语句。package 语句作为Java源文件的第一条语句,指明该源文件定义的类所在的包。package语句的一般格式为: package 包名; 如果源程序中省略了package语句,源文件中所定义命名的类被隐含地认为是无名包的一局部,即源文件中定义命名的类在同一个包中,但该包没有名字。 包名可以是一个合法的标识符,也可以是假设干个标识符加“.分割而成,如: package sunrise; package sun ; 程序如果使用了包语句,例如: package tom.jiafei; 那么你的目录结构必须包含有如下的结构tomjiafei 比方 c:1000tomjiafei 并且要将源文件编译后得到的全部字节码文件拷贝到目录c:1000tomjiafei中,如果你事先将源文件保存到c:1000tomjiafei中,然后编译源文件,那么生成的字节码文件就直接保存到当前目录中了,如: c:100
25、0tomjiafeijavac 源文件 我们将下述例子10的源文件保存到c:1000tomjiafei。效果如图4.17 package tom.jiafei;class Tom void speak() System.out.println(Tom类在tom.jiafei包中); public class Example4_10 public static void main(String args) Tom tom=new Tom(); tom.speak(); System.out.println(Example4_10类在tom.jiafei包中); 然后编译原文件: c:1000tomjiafeijavac Example.java 运行程序时必须到tomjiafei的上一层目录1000中来运行,如: c:1000java tom.jiafei. Example 因为起了包名,类Example的全名已经是:tom.jiafei. Example就好比大连的全名是:“中国.辽宁.大连。 包名应该防止与其他包名冲突。但要做到这一点似乎很困难,如果你的包需要在全世界是唯一的,Sun
26、公司 建议大家使用自己所在公司的Internet域名倒置后做包名,例如,将域名“sina 的倒置“cn .sina做包名。 2使用参数“d编译源文件 javac 可以使用参数-d指定生成的字节吗文件所在的目录。如果不使用参数-d,javac在当前目录生成字节码文件。 如果源文件没有包名,使用参数-d可以将字节码文件存放到你指定的有效目录中,例如: javac d F:tsinghua1000 MyFile.java 将源文件MyFile.java生成的全部字节码文件存放到F:tsinghua1000。 如果源文件使用包语句声明了包名,使用参数-d时 要 格 外 小 心 。 假 设 源 文 件 的 包 名 是tom.jiafei,保存在在D:2000中, 下述编译命令: D:2000javac d F:tsinghua1000 MyFile.java 会在F:tsinghua1000目录下新建子目录结构tomjiafe并将字节码文件存放到F: tsinghua1000tomjiafei中。 而下述编译命令: D:2000javac d . MyFile.java 会在当前目录2000下新
27、建子目录结构tomjiafei,并将字节码文件存放到D:2000tomjiafei中。返回4.11 import 语句 使用import 语句可以引入包中的类。在编写源文件时, 除了自己编写类外,我们经常需要使用Java提供的许多类,这些类可能在不同的包中。在学习Java语言时,使用已经存在的类,防止一切从头做起,这是面向对象编程的一个重要方面。 1 .使用类库中的类 为了能使用Java提供给我们的类,我们可以使用import语句来引入包中类。在一个Java源程序中可以有多个import语句,它们必须写在package语句假设有package语句的话和源文件中类的定义之间.。 Java为我们提供了大约130多个包,如:java.applet 包含所有的实现Java applet的类java.awt 包含抽象窗口工具集中的图形、文本、窗口GUI类java.awt.image 包含抽象窗口工具集中的图像处理类java.lang 包含所有的根本语言类java.io 包含所有的输入输出类 包含所有实现网络功能的类java.until 包含有用的数据类型类 如果使用import语句引入了整个包中
28、的类,那么可能会增加编译时间。但绝对不会影响程序运行的性能。Java运行平台由所需要的Java类库和虚拟机组成,这些类库被包含在一个jrelib中的压缩文件rt.jar中,当程序执行时,Java运行平台从类库中加载程序真正使用的类字节码到内存。 下面的例子11使用了java.util包中的Date类,用来显示本机的当前时间。 import java.util.Date;public class Example4_11 public static void main(String args) Date date=new Date(); System.out.printf(本地机器的时间:n%s,date); 2使用自定义包中的类 我们也可以使用import 语句引入自定义包中的类。如: import tom.jiafei.*; 我们也可以对单独的一个类进行 编译,生成字节码文件然后供其它类使用。 以下的源文件SquareEquation.java只有一个类组成,这个类可以被其它的程序引入使用,该源文件的包名是tom.jiafei。 为了使程序能使用tom.jiafei包中的类,我们必须在
29、 classpath中指明我们包的位置,假设tom.jiafei的位置是:d:4000,即在d:4000下有子目录tomjiafei。更新classpath的设置,在命令行执行如下命令: set classpath=E:jdk1.5jrelibrt.jar;.;c:4000package tom.jiafei;public class SquareEquation double a,b,c; double root1,root2; boolean boo; public SquareEquation(double a,double b,double c) this.a=a; this.b=b; this.c=c; if(a!=0) boo=true; else boo=false; public void getRoots() if(boo) System.out.println(是一元2次方程); double disk=b*b-4*a*c; if(disk=0) root1=(-b+Math.sqrt(disk)/(2*a); root2=(-b-Math.sqrt(disk)/(
30、2*a); System.out.printf(方程的根:%f,%fn,root1,root2); else System.out.printf(方程没有实根n); else System.out.println(不是一元2次方程); public void setCoefficient(double a,double b,double c) this.a=a; this.b=b; this.c=c; if(a!=0) boo=true; else boo=false; 也可以将上述命令添加到Classpath值中。在Windows2000系统中,右击“我的电脑,弹出快捷菜单,然后选择“属性命令,弹出“系统特性对话框,再单击该对话框中的高级选项,然后单击“环境变量按钮。对于Win9x系统可以将上述命令写到autoexec.bat文件中。 将下述源文件SquareEquation.java编译得到的字节码文件拷贝到D:4000tomjiafei中。下面的例子12的源文件保存在 D:4000目录中,并用 import 语 句 引 入 包 tom.jiafei中 的SquareEquatio
31、n类。 nimport tom.jiafei.*;npublic class Example4_12n public static void main(String args )n SquareEquation equation=new SquareEquation(4,5,1);n equation.getRoots();n equation.setCoefficient(-3,4,5);n equation.getRoots();n n 3使用无名包中的类 我 们 也 可 以 使 用 无 名 包 中 的 类 。 假 设 上 述SquareEquation.java源文件中没有使用包语句,如果一个程序使用SquareEquation类,可以将该类的字节码文件存放在当前程序所在的目录中。 编写一个有价值的类是令人快乐的事情,你可以将这样的类打包,形成有价值的“软件产品,供其他软件开发者使用。 4防止类名混淆 Java运行环境总是先到程序所在目录中寻找程序所使用的类,然后加载到内存。如果在当前目录没有发现所需要的类,就到import语句所指的包中查找。 如果在当前目录没有发现所需要的类,
32、就到import语句所指的包中查找。如果在当前目录中寻找到了要加载的类,那么程序就不会再加载import语句引入的同名类。返回4.12 访问权限 类有2种重要的成员:成员变量和方法。类创立的对象可以通过“.运算符访问分配给自己的变量,也可以通过“.运算符调用类中的实例方法和类方法。类在定义声明成员变量和方法时,可以用关键字private、protected和public来说明成员变量和方法的访问权限,使得对象访问自己的变量和使用方法受到一定的限制。 1私有变量和私有方法 用关键字private修饰的成员变量和方法被称为私有变量和私有方法。 对于私有成员变量或方法,只有在本类中创立该类的对象时,这个对象才能访问自己的私有成员变量和类中的私有方法,如例子13,例子14所示。效果如图4.21 public class Example4_13 private int money; Example4_13() money=2000; private int getMoney() return money; public static void main(String args ) Example
33、4_13 exa=new Example4_13(); /对象exa在Example4_13类中 exa.money=3000; int m=exa.getMoney(); System.out.println(money=+m); class Employee private double salary=1800; public void setSalary(double salary) if(salary1800&salary=6000) this.salary=salary; public double getSalary() return salary; public class Example4_14 public static void main(String args) Employee zhang=new Employee(); Employee wang=new Employee(); zhang.setSalary(100); /赋值不成功 System.out.println(zhang的薪水:+zhang.getSalary(); wang.setSalary(
34、3888); /wang.salary=88888;是非法的,因为对象wang已经不在Employee类中 System.out.println(wang的薪水:+wang.getSalary(); 2共有变量和共有方法 用public修饰的成员变量和方法被称为共有变量和共有方法,如: class A public float weight; /weight被修饰为public的float型变量。 public float f(float a,float b) /方法 f是public方法。 当我们在任何一个类中用类A 创立了一个对象后,该 对象能访问自己的public变量和类中的public方法。如: class B void g() A a=new A(); a.weight=23f; /合法。 a.f(3,4); /合法。 3友好变量和友好方法 不用private、public 、protected修饰符的成员变量和方法被称为友好变量和友好方法,如: class A float weight; /weight是友好的float型变量。 float f(float a,float
35、b) /方法 f是友好方法。 假设B与A是同一个包中的类,那么,下述B类中的a.weight、a.f(3,4)都是合法的。 class B void g() A a=new A(); a.weight=23f; /合法。 a.f(3,4); /合法。 4受保护的成员变量和方法 用protected修饰的成员变量和方法被称为受保护的成员变量和受保护的方法,如: class A protected float weight; /weight被修饰为protected的float型变量。 protected float f(float a,float b) /方法 f是public方法。 假设另外一个类B使用A创立了一个对象k,并且A,与B是同一个包中的类,那么该对象k也能通过类A的类名访问自己的protected的变量和方法。 后面讲了继承后再讲保护与友好的区别。 5public类与友好类 类声明时,如果关键字class前面加上public关键字,就称这样的是一个public类,不能用protected和private修饰类。如: public class A 可以在任何另外一个类中,使用
36、public类创立对象。如果一个类不加public修饰,如: class A 这样的类成为友好。在另外一个类用友好类创立对象时,要保证在同一个包内。 6关于构造方法 private、public 、protected修饰符的意义也同样适合于构造方法。如果一个类没有明确地声明构造方法,那么public类的默认构造方法是public的,友好类的默认构造方法是友好的。需要注意的是,如果一个public类定义声明的构造方法中没有public的,那么在另外一个类中使用该类创立对象时,使用的构造方法就不是 public的,创立对象就受到一定的限制。 假设对象a是A类创立的,我们把对象对成员的访问权限总结在下表4.1中表4.1 对象访问成员对象对象a的位置的位置private成员成员友友 好好成员成员protected成员成员public成员成员在类A中,a访问成员允许允许允许允许在与A同包的另外一个类中a访问成员不允许允许允许允许在与A不同包的另外一个类中a访问成员不允许不 允许不允许允许返回4.13 对象的组合 n一个类可以把对象作为自己的成员变量,如果用这样的类创立对象,那么该对象中就会有其它
37、类对象,也就是说该对象将其他对象作为自己的组成局部这就是人们常说的Has-A,或者说该对象是由几个对象组合而成 .例子15Rectangle.javapublic class Rectangle private double x,y,width,height; public void setX(double x) this.x=x; public double getX() return x; public void setY(double y) this.y=y; public double getY() return y; public void setWidth(double width) if(width=0) this.width=0; else this.width=width; public double getWidth() return width; public void setHeight(double height) if(height=0) height=0; else this.height=height; public double getHeight()
38、 return height; Circle.javapublic class Circle private double x,y,radius; public void setX(double x) this.x=x; public double getX() return x; public void setY(double y) this.y=y; public double getY() return y; public void setRadius(double radius) if(radius0) this.radius=0; else this.radius=radius; public double getRadius() return radius; Geometry.javapublic class Geometry private Rectangle rect; private Circle circle; Geometry(Rectangle rect,Circle circle) this.rect=rect; this.circle=circle; pub
39、lic void setCirclePosition(double x,double y) circle.setX(x); circle.setY(y); public void setCircleRadius(double radius) circle.setRadius(radius); public void setRectanglePosition(double x,double y) rect.setX(x); rect.setY(y); public void setRectangleWidthAndHeight(double w,double h) rect.setWidth(w); rect.setHeight(h); public void showState() double circleX=circle.getX(); double rectX=rect.getX(); if(rectX-circleX=circle.getRadius()*2) System.out.println(图形中的矩形在圆的右侧); if(circleX-rectX=rect.getW
40、idth() System.out.println(图形中的矩形在圆的左侧); MainClass.javapublic class MainClass public static void main(String args) Rectangle rect1=new Rectangle(), rect2=new Rectangle(); Circle circle1=new Circle(), circle2=new Circle(); Geometry geometryOne,geometryTwo; geometryOne=new Geometry(rect1,circle1); geometryOne.setRectanglePosition(30,40); geometryOne.setRectangleWidthAndHeight(120,80); geometryOne.setCirclePosition(150,30); geometryOne.setCircleRadius(60); geometryTwo=new Geometry(rect2,circle2); ge
41、ometryTwo.setRectanglePosition(160,160); geometryTwo.setRectangleWidthAndHeight(120,80); geometryTwo.setCirclePosition(40,30); geometryTwo.setCircleRadius(60); geometryOne.showState(); geometryTwo.showState(); 分别编译4个类,运行MainClass.java4.14 根本类型数据的类包装 Java的根本数据类型包括:byte、int、short、long、float、double、char。Java同时也提供了根本数据类型相关的类,实现了对根本数据类型的封装。这些类在java.lang包中,分别是:Byte、Integer、Short、Long、Float、Double和Character类。 1.Double和Float类 Double类和Float类实现了对double和float根本型数据的类包装。 可以使用Double类的构造方法: Double (double num)
42、 创立一个Double类型的对象;使用Float类的构造方法: Float (float num) 创立一个Float类型的对象。Double对象调用doubleValue()方法可以返回该对象含有的double型数据;Float对象调用floatValue()方法可以返回该对象含有的float型数据。 Byte、Integer、Short和Long对象分别调用byteValue ()、intValue()、shortValue ()和longValue ()方法可以返回该对象含有的根本型数据。 3.Character类 Character类实现了对char根本型数据的类包装。 可以使用Character类的构造方法: Character (char c) 创立一个Character类型的对象。Character对象调charValue()方法可以返回该对象含有的char型数据。 Character类还包括一些类方法,这些方法可以直接通过类名调用,用来进行字符分类,比方判断一个字符是否是数字字符或改变一个字符的大小写等。 Character类中的一些常用类方法:l public sta
43、tic boolean isDigit(char ch) 如果ch是数字字符方法返回 true,否那么返回false。l public static boolean isLetter(char ch) 如果ch是字母方法返回 true,否那么返回false。l public static boolean isLetterOrDigit(char ch) 如果ch是数字字符或字母方法返回 true,否那么返回false。l public static boolean isLowerCase(char ch) 如果ch是 小 写 字 母 方 法 返 回 true, 否 那 么 返 回false。 l public static boolean isUpperCase(char ch) 如 果ch是大写字母方法返回 true,否那么返回false。l public static char toLowerCase(char ch) 返 回ch的小写形式。l public static char toUpperCase(char ch) 返回ch的大写形式。l public static boo
44、lean isSpaceChar(char ch) 如果ch是空格返回true。 图4.22 Character类的类方法 在下面的例子16中,将一个字符数组中的小写字母变 成大写字母,并将大写字母变成小写字母。 public class Example4_16 public static void main(String args ) char a=a,b,c,D,E,F; for(int i=0;ia.length;i+) if(Character.isLowerCase(ai) ai=Character.toUpperCase(ai); else if(Character.isUpperCase(ai) ai=Character.toLowerCase(ai); for(int i=0;ia.length;i+) System.out.printf(%6c,ai); 返回4.13 反编译和文档生成器 使用SDK提供的反编译器:javap.exe可以将字节码反编 译为源码,查看源码类中的public方法名字和public成员变量的名字,例如: 将列出Button中的public方法
45、和public成员变量。以下命令 javap 将列出Button中的全部方法和成员变量。 4.16 jar文件nJava应用程序在运行时需将字节码文件加载到内存,因此对字节码文件的位置有特殊要求。以下分四种情况讨论。n1.使用当前应用程序所在目录中没有包名的类。n 可以直接加载。n2.使用java运行环境中类库中的类。n这个类库中的类是有包的,应用程序必须使用import语句引入相关的包中的类。4.16 jar文件n n3.使用应用程序当前目录的子孙目录中的类。n应用程序当前目录的子孙目录可以作为用户自定义包的包名。具有该包名的的类必须放在子孙目录中,用import语句引入。n4.使用java运行环境扩展中的类。n我们可以使用jar.exe文件将一些类的字节码文件压缩成一个.jar文件。然后将这个jar文件放到java运行环境的扩展中,即放到JDK安装目录的jrelibext文件夹下。这样应用程序就可以使用jar文件中的类创立对象了。文档生成器 使用SDK提供的javadoc.exe可以制做源文件类结构的 html格式文档。 假设D:test有源文件:Example.java,用jav
46、adoc生成Example.java的html格式文挡: javadoc Example.java 这时在文件夹test中将生成假设干个html文挡,查看这些文档可以知道源文件中类的组成结构,如类中的方法和成员变量。 使用javadoc时,也可以使用参数-d指定生成文挡所在的目录,例如, javadoc d F:gxybook Example.java 返回第四章 习题1.在声明类时,类名应遵循哪些习惯?答:首字母大写, 望名知意。2.类体内容有哪两种重要成员?答:成员变量,和成员方法。3。实例方法可以操作类变量吗?类方法可以操作实例变量吗?答:实例方法可以操作类变量。而类方法不可以操作实例变量。4.当类的字节码加载到内存时,类变量就一定分配了内存空间吗?答:实例成员变量不分配内存,而类变量一定分配内存。5.类的实例变量在什么时候分配内存?答:声明之后,在用new关键字创立实例的时候才分配内存。6.一个类的类变量被该类创立的所有对象共享吗?答:共享。7.不同对象的实例变量分配的内存地址一定不同吗?答:当出现引用赋值语句时两个实例变量的内存地址相同。8.什么叫方法的重载?构造方法可以重载
47、吗?答:方法的重载是指一个类中可以有多个方法具有相同的名字,但这些方法的参数不同,或者参数的个数不同,或者参数的类型不同。构造方法可以重载。9.请阐述为什么类方法不能调用实例方法?答:对于类方法在该类加到内存时就分配了相应的入口地址,所以即使该类未创立对象,也可以通过类名调用类方法。而这时在类对象创立之前,实例方法还没有入口地址。还不知道一个方法从何处开始执行,当然不能调用。10.请阐述,为什么类方法中不能操作实例成员变量?答:对于类方法在该类加到内存时就分配了相应的入口地址,所以即使该类未创立对象,也可以通过类名调用类方法。而这时在类创立之前,实例成员变量还没有分配内存空间。没内存空间当然无法操作。11.实例方法可以用类名直接调用吗?答:不能,对于类方法在该类加到内存时就分配了相应的入口地址,所以即使该类未创立对象,也可以通过类名调用类方法。而这时对象创立之前实例方法还没有入口地址。实例方法表现实例的功能,或改变实例变量。用类调用改变那个实例的实例变量,表现那个实例的功能。12.关键字this可以出现在构造方法中吗?可以出现在实例方法中吗?可以出现在类方法中吗?答:可以出现在构造方法
48、中,代表该类构造方法所创造出的对象。可以出现在实例方法中,代表使用该方法的当前对象。This不能出现在类方法中,因为类方法是通过类名调用的。13.源文件声明编写的类一定在同一个包中吗?答:不一定,当不在同一包中时,可用import语句将其所在的包引入该源文件中。14.“import java.awt.*与“有什么不同?答:前者引入了awt包中的所有类,后者只引入了Button一个类。15.程序中使用了“import java.util.*;程序运行时,是要加载java.util包中的全部类到内存吗?答:不,只加载本程序用到的类到内存中,因为java程序是动态加载,字节码类文件。16.有哪几种访问权限修饰符?说出一种的作用。答:访问权限修饰符有public, private,protected.Private作用是只允许本类的对象访问。17.怎样反编译一个类?答:使用SDK提供的反编译器javap.exe文件可以实现将字节码文件反编译为源码文件。可查看源码中public方法和public成员变量的名字。如参加参数-private那么可列出其全部的成员方法和成员变量。如:Javap 那么可
49、以列出Button类中全部的方法和成员变量。第四章 作业题1.编写一个类,该类创立的对象可以计算等差数列的和。解:class DengCha int start,d; DengCha() DengCha(int start,int d) this.start=start; this.d=d; void setStart(int s) start=s; void setD(int d) this.d=d; int getSum(int n) int sum=0,i=1; while(i=0)n root1=(-b+Math.sqrt(disk)/(2*a);n root2=(-b-Math.sqrt(disk)/(2*a);n System.out.printf(方程的根:%f,%fn,root1,root2);n n elsen System.out.printf(方程没有实根n);n n n elsen System.out.println(不是一元2次方程);n n n public void setCoefficient(double a,double b,double c)n this.a=a;n this.b=b;n SquareEquation.c=c;n if(a!=0)n boo=true;n n elsen boo=false;n n nnpublic class ZuoYe4_3n public static void main(String args )n SquareEquation equation1=new SquareEquation(4,5,1);n SquareEquation equation2=new SquareEquation(3,5,-7);n equation1.getRoots();n equation2.getRoots();n n
《JAVA大学实用教程(第二版)附课后练习答案 第4章类与对象》由会员hs****ma分享,可在线阅读,更多相关《JAVA大学实用教程(第二版)附课后练习答案 第4章类与对象》请在金锄头文库上搜索。