第4章java类和对象.docx
《第4章java类和对象.docx》由会员分享,可在线阅读,更多相关《第4章java类和对象.docx(34页珍藏版)》请在冰豆网上搜索。
第4章java类和对象
本章要点:
1、了解了类和对象的基本概念
2、类头和类体的格式与内容
3、类、接接口、包之间的关系
4、类体中的成员数据和成员方法以及构造方法的应用。
第4章类和对象
Java语言是典型的面向对象程序设计语言。
本章将结合面向对象程序设计思想和Java语言,通过对类和对象的详细介绍,来阐述用Java语言实现面向对象思想中的抽象性和封装性这两大特性。
本章内容具体涉及到类和对象的概念、类的定义、对象的初始化和清除、一些特殊形式的类等。
4.1类和对象
在面向对象设计语言出现之前,是利用的过程程序语言如Pascal、C等来编写程序的,这些过程程序设计语言是将算法转化成程序代码,由于程序中数据和过程或函数是分开的,如果对程序的功能发生一点变化,假设新增一个功能函数,这可能需要程序员对程序做较大程度的修改。
这就使得过程程序设计语言的重用性、可用性、灵活性、适应性等方面不如人意。
面向对象程序设计语言是利用面向对象特性可以很好的改善过程设计语言中存在的问题。
面向对象语言是立足类和对象概念,能较好地反映和模拟现实世界,充分体现了程序的模块化、重用性、可用性。
4.1.1对象和类的基本概念
面向对象程序设计语言中是以类和对象为核心内容。
对象实际上就是对现实世界的存在实体的模拟,例如一本书、一双鞋子、一台电脑都可以视为一个对象,甚至一位学生也可以是一个对象。
对于每一个对象都有自己的状态和行为。
现在以某一学生为例,学生对象的状态可以通过姓名、出生日期、学号、籍贯、系别、专业、选修课程名等属性来说明,用注册学籍、选择选修课程、阅读书籍等动作说明该对象的行为。
假设一位名叫张三的学生是一个对象。
这一对象有学号(23232)、姓名(张三)、出生日期(1984年2月3日)等属性。
“张三”通过注册学籍动作,开始一个学期的学习生活,通过选修“Java语言”课程,可以使“张三”可以参加“Java语言”课程的学习。
从上述的简单描述可以知道,对象的状态实际上是描绘对象静态的属性特征,对象的行为是说明对象的会发生变化的动态行为。
为此,可以定义整型量表示学号、字符串量表示姓名等属性。
定义register()、chooseCourse()等方法表示注册、选修课程等动作。
面向对象程序设计是通过具体的数据来描绘对象的状态,而对象的行为往往是通过方法的调用来体现。
当该生发生“选择课程”动作的时候,对象“张三”调用方法“chooseCourse()”,方法的参数是“2006-2007学期”。
对于外界而言,张三同学基于什么考虑选择课程并不是问题的重点,即“chooseCourse()”方法是如何实现“选择课程”的动作并不重要,重点是通过调用“chooseCourse()”方法可以实现“选择课程”这一动作,改变了“张三”这一对象的内部状态“选修课程名”。
数据“选修课程名”隐藏在对象的内部,通过方法“chooseCourse()”实现对数据“选修课程名”的访问和修改。
这种外界通过调用对象的方法进行联系的方式体现了对象的信息封装。
因此,可以认为对象是数据以及相关操作封装在一起的实体。
类是面向对象程序设计中的另一个重要概念。
它是对一组具有相同属性、行为、关系以及语义的对象的描述。
对于每个类都有别于其他类。
在Java语言中,类是对具有相同类型对象的抽象,在一个类中可以用变量来表示对象的抽象状态,而用方法抽象出对象的行为特征。
简单的说,一个叫“张三”的学生个体是一个对象,而定义一个“Student”类可以泛指学生类型。
从图4-1中可以看到,“Student”类中用变量Id、name、birthday等分别表示学号、姓名、出生日期等静态属性,用register()、chooseCourse()等方法描绘学生的注册、选修课程等动态属性。
而“张三”是“Student”类的一个对象,具有的特征如学号(Id=23232)、姓名(name=“张三”)、出生日期(birthday=“1984年2月3日”)等。
在用Java语言编写程序的时候可以把类理解为数据类型,而把对象理解为数据类型中的变量实例。
图4-1类和对象的关系
4.1.2类的声明
类是面向对象的基础。
首先,类的声明格式如下:
[修饰符]class类名[extends父类][implements接口名1,…,接口名n]
{
类的成员
}
类的定义有两大部分组成:
类体和类头。
类体是用“{}”括起的部分,而其余部分是类头,规定类的一些基本性质。
“[]”包括的内容是可选项。
修饰符是一些关键字,用于说明类的可访问性(如public)和其他非访问性质(如final、static、abstract等)。
访问控制符限定了类的可访问性,即,对其他类是否可见。
非访问控制符是指用于限定类的性质的关键字,它们往往限定类是否是具有某些特征的类。
例如,关键字final可以定义一个最终类,关键字static可用于定义静态嵌套类(见4.6.1),而abstract用于抽象类(见第5章5.2)。
一些关键字是不能同时修饰类的。
例如final和abstract是不能同时定义类。
关于这些具有特殊性质的类将在第5章介绍。
关键字class表示开始定义一个类。
在class后的类名必须符合标识符的命名规则。
一般来说,类名可以有一个或多个英文单词构成,每个单词的第一个字符必须是大写,其他字符小写;例如,类名Student,类名JOptionPane。
关键字extends用来说明该类的父类。
也就是该类是指定父类的子类。
二者体现的是继承关系。
关键字implements定义了该类实现的接口表,在该接口表中说明可以实现的一个或多个接口。
类体说明的是类的成员。
类的成员包括两大部分:
类的成员变量和类的成员方法。
对于类的成员将在4.1.4详细说明。
下面有一个类Student声明的实例:
publicclassStudent{//定义一个Student类
//定义成员变量
privateintId;//定义学号属性
privateStringname;//定义姓名属性
privateDatebirthday;//定义出生日期属性
privateStringcourseName[];//定义课程名
...
//定义成员方法;
publicStudent(intstudentId){
…..}
publicbooleanregister(Dated){//定义注册学籍方法
...}
publicvoidchooseCourse(String[]cname){//定义选修课程方法
...}
....
}
4.1.3类的访问控制
类的访问控制是定义类的访问权限,它说明了其他类对本类的访问方式。
类的访问方式有两种,一种是由public关键字说明的公共访问方式,另一种是默认访问方式,即没有访问控制关键字修饰的类,有时也称为包私有(package-private)访问方式。
关键字public修饰的类,说明该类是公共类,该类能被所有的类进行访问和引用。
Java语言提供了大量的公共类,比如在前几章常用的几个类如java.util.Date、javax.swing.JoptionPane、java.lang.String等都是公共类。
公共类可处于不同的包,如Date类在java.util包,JOptionPane类在java.swing包里。
对于不同包中公共类,可以注明所在的包名直接引用公共类,也可以通过先导入包名再引用公共类。
关于包的介绍将在4.2中说明。
例如:
importjava.util.*;//导入java.util包
publicclassStudent{//定义一个Student类
privateDatebirthday;//定义出生日期属性,定义java.util.Date变量birthday;
privateStringcourseName[];//定义课程名
...
publicStudent(intstudentId){
…..}
publicbooleanregister(Dated){//定义注册学籍方法
...}
publicvoidchooseCourse(String[]cname){//定义选修课程方法
...}
}
在上面的程序段中,类Student是引用了java.util包的公共类Date。
另外,类Student也是一个公共类,可以为其他类所访问和引用。
默认访问方式,也称为包私有(package-private)访问方式。
这种访问方式只允许本包内的类进行访问,对于包外的类是私有的,无法进行访问。
对于包私有类,即使通过导入语句将类所在的包通过import关键字导入,其他包的类仍是无法访问。
例如图4-2中的访问控制示例。
图4-2展示的Example1包定义了两个类A和B,其中类A是公共类,B是默认的包私有类。
类A对于所有的类都是可见的,与类是否是处于同一个包无关。
因此,类B和类C均可以访问和引用类A。
而处于包Example2的类C需要导入类A所在的包Example1才可访问类A。
至于类B,只能对同一个包的类可见。
在这个图例中类B只对类A可见。
至于Example2包中的类C,它只可以访问类A而不能访问类B。
如果类C强行引用类B,会超出类B的可访问权限,导致编译错误。
图4-2类控制访问示例
4.1.4类的成员
类的成员包括类的成员变量和成员方法。
注意有时也可以称成员变量为数据成员。
用类的成员变量描绘类的属性,用成员方法描绘类的功能和操作。
1.成员变量的定义
[访问控制符][static][final][transient][volatile]数据类型变量名;
同上“[]部分”表示可选项,访问控制符包括了public、private、protected等关键字。
static、final、transient和volatile是非访问控制修饰符,用于说明类的成员变量的性质。
例如,关键static说明成员变量是静态数据,关键字final修饰符使得变量成为常量,transient变量说明成员变量不能被序列化,关键字volatile的修饰使得变量能从主存读取,进行异步修改。
对于数据类型,它可以是基本数据类型如int、char等,也可以是Java语言提供的类如java.util.Date、java.lang.String,也可以是用户自定义的类如上面定义的Student类。
变量名必须符合标识符命名规则。
在面向对象程序设计语言中,有一个默认规则就是变量名可以由一个或多个英文单词构成,其中第一个单词的第一个字符必须小写,如是由多个单词构成,其他单词的第一个字符必须大写,其他字符小写,例如变量名studentName。
表4-1基本类型的默认值
基本类型
默认值
基本类型
默认值
boolean
false
int
0
char
‘\u0000’(null)
long
0L
byte
(byte)0
float
0.0f
short
(short)0
double
0.0d
变量名在定义的同时可以进行初始化。
如果数据类型是基本数据类型,可以直接将初始值赋值给成员变量,要是没有声明初始值,系统会根据数据类型的不同自动为成员变量赋一个初始值,表4-1列出了各基本类型的默认值。
如果数据类型是一个类,可以通过操作符new创建一个对象赋值给成员变量,形如“类名成员变量=new类名([行参表])”例如:
name=newString("张三");
2.成员方法的定义
[访问控制符][static][final][abstract][native][synchronized]返回值数据类型方法名([参数表])[throws异常名表]
{方法体
}
类的成员方法的访问控制符决定其他类是否可以该方法,控制符有public、private和protected;其他非访问修饰符有static、final、abstract、native、synchronized等,这些修饰符说明了成员方法的某些特性。
例如,final关键字可以说明成员方法是一个不可以修改的最终方法;abstract关键字说明该方法是抽象方法,没有方法体;native可以说明方法是一个本地方法;synchronized说明成员方法是一个同步方法等。
返回值类型数据类型的要求同类的成员变量的数据类型,可以是基本数据类型,也可以是类。
方法名必须符合标识符命名规则。
方法名可以由一个或多个英文单词构成,其中第一个单词的第一个字符必须小写,如是由多个单词构成,其他单词的第一个字符必须大写,其他字符小写,例如方法名chooseCourse。
方法体包括方法的局部变量声明和执行语句。
例4.1定义一个圆形类,它可以实现圆面积的计算。
publicclassCircle{
doubleradius;
publicCircle(){}
publicCircle(double_radius){
radius=_radius;
}
publicdoublegetArea(){
return3.14*radius*radius;//返回面积;
}
publicstaticvoidmain(Stringargs[]){
Circlecircle=newCircle(3);//定义一个半径为3的circle对象
System.out.println("半径为3的圆面积为:
"+circle.getArea());//求面积;
System.exit(0);
}
}
3.成员访问控制
成员访问控制符有三种public、private和protected,它们和成员的默认访问方式(包私有:
package-private)一起构成了成员的访问方式。
通过它们,有效的控制其他类对类的成员变量和成员方法的访问。
(1)public
用public关键字修饰成员变量或成员方法,即为公有成员变量或共有成员方法。
所有的类可以对类的公有成员进行访问。
请观察例4.2的程序代码。
例4.2定义一个长方形的类Rectangle,利用一个测试主类RectangleTest求面积。
publicclassRectangle{//定义一个Rectangle
publicintlength;//定义长度,公共变量
publicintwidth;//定义宽度,公共变量
publicRectangle(){//无参构造方法
}
publicRectangle(intl,intw){//有参构造方法,l表示长度,w表示宽度
length=l;
width=w;
}
publicintgetArea(){
returnlength*width;
}
}
publicclassRectangleTest{//定义测试类
publicstaticvoidmain(Stringargs[]){
Rectanglerectangle=newRectangle(3,4);//初始化对象rectangle,长为3,宽为4
System.out.println("长="+rectangle.length);//输出长度
System.out.println("宽="+rectangle.width);//输出宽度
System.out.println("面积"+rectangle.getArea());//输出面积
System.exit(0);
}
}
观察程序RectangleTest.java,可以发现其中的main方法中创建了一个Rectangle的对象rectangle,由于rectangle对象的成员变量length和width是公共成员变量,所以在程序中rectangle.length和rectangle.width成员变量可以被直接引用。
同样,由于rectangle对象的成员方法getArea()也是共有的,因此在测试类RectangleTest.java中对该方法也可以直接调用。
(2)private
用关键字private修饰的成员变量是私有变量。
私有变量是不能被其他类和其他类的对象进行直接访问的,它只能被定义它的类直接访问。
一般,在设计类时推荐将数据成员定义为私有成员,这样数据成员的变化不会影响到其他类,有效的实现了数据的封装,数据对外界是不可见。
假设将例4.2的Rectangle.java进行修改,将表示长和宽的公共成员变量length和width改成私有变量,形式如下:
publicclassRectangle{
privateintlength;//定义长度,私有变量:
privateintwidth;//定义宽度,私有变量
publicRectangle(){}//默认构造方法
publicRectangle(intl,intw){//有参构造方法,l表示长度,w表示宽度
length=l;
width=w;
}
publicintgetArea(){
returnlength*width;
}
}
这时,调试测试主类RectangleTest,会发现程序出现编译错误,见下列程序代码。
原因在于定义的类Rectangle的两个私有数据成员(length和width)只在类Rectangle有效,其他类没有访问权限,不能直接访问。
publicclassRectangleTest{//定义测试类RectangleTest
publicstaticvoidmain(Stringargs[]){
Rectanglerectangle=newRectangle(3,4);//初始化对象rectangle,长为3,宽为4
System.out.println("长="+rectangle.length);//输出长度,编译错误
System.out.println("宽="+rectangle.width);//输出宽度,编译错误
System.out.println("面积"+rectangle.getArea());//输出面积
System.exit(0);
}
}
(3)protected
关键字protected是保护访问控制符。
用于定义保护访问成员,它不仅使得类成员对同一个包的类可见,而且对该类的不在同一个包的子类可见。
例如:
图4-3protected成员的示例
(4)默认访问方式
默认访问方式是指没有任何访问控制符的类成员,也称这种访问方式为包私有(package-private)访问方式。
对于这些类成员,它们对同一个包的类是可见的。
例如:
//A.java
packageP1;
publicclassA{
publicA(){}
voidtestA(){//包私有
System.out.println("TestA");
}
}
//B.java
packageP1;
publicclassB{
Aa=newA();
publicB(){}
voidtestB(){
a.testA();//合法
System.out.println("TestB");
}
}
观察上述两个文件A.java和B.java。
这两个文件分别定义了同在包P1中的类A和类B。
类B可以访问类A的默认访问成员方法testA()。
如果包P2中定义一个类C,形式如下:
packageP2;
importP1.*;
publicclassC{
Aa=newA();
publicC(){}
voidtestC(){
a.testA();//错误
System.out.println("TestC");
}
}
这时,可以发现在类C调用类A中的默认访问方式的方法testA()会发生编译错误。
因为,类A中的成员方法testA()仅在包P1中可见。
4.类静态成员
类的定义中可以看到,类的成员可以用关键字static修饰。
一旦用static关键字修饰类的成员,这些类的成员就是静态成员。
带有static的成员数据便成为静态成员数据。
同样,凡是用static关键字修饰的成员方法认为是静态成员方法。
无论是静态成员数据还是静态成员方法,它们的共同的性质是不能被实例化,可直接用类进行调用。
这是因为,static修饰符所表示的这些静态成员属于类并不属于类对象的特性,静态成员对于所有的类对象而言是共享的成员。
因此,静态成员方法中不能访问对象的状态,只能访问类的静态成员或显式提供的参数。
在具体使用类的静态成员可以通过类名直接调用,形如:
“类名.静态成员”。
这种调用方式与非静态成员只能通过创建对象来访问类的成员(形如:
“对象名.成员”)是完全不同的。
例4.3类的静态成员的示例。
publicclassStaticMember{
staticintcounter;
publicStaticMember(){
counter++;//定义计数器
}
publicstaticvoidshowMessage(){
System.out.println("信息输出"+counter+"次");
}
publicstaticvoidmain(Stringargs[]){
StaticMember.showMessage();//通过类名访问静态成员方法
StaticMembersm1=newStaticMember();
sm1.showMessage();//通过对象名访问静态成员方法
StaticMembersm2=newStaticMember();
sm2.showMessage();
sm1.showMessage();//访问同一个数据counter
System.exit(0);
}
}
图4-4例4.3的运行结果
5.本地方法
用关键字native修饰的方法是本地方法,它表示该方法并不是用Java语言编写,而是用其他语言如C/C++/汇编语言编写的方法。
这些方法通过JNI(JavaNativeInterface:
Java本地接口)与Java程序进行连接,扩展Java程序的功能。
本地方法概念的提出为解决Java语言无法处理的问题提供了新的思路。
例4.4本地方法的示例。
publicclassNativeExample{//NativeExample.java
static{
System.loadLibrary("NativeMethod");//装载库文件NativeMethod.dll
}
publicnativevoidshowMessage();//定义一个本地方法
publicstaticvoidmain(Stringargs[]){
NativeExamplene=newNativeExample();
ne.showMessage();