• 1. 第4章 类 (时间:4次课,8学时)
  • 2. 第4章 类 教学提示:培养面向对象的程序设计思维方式对掌握Java语言具有十分重要的作用。 本章主要介绍:利用Java语言进行面向对象编程的系统分析和程序设计方法。
  • 3. 第4章 类 4.1 面向对象编程 4.2 类的描述 4.3 类的成员变量 4.4 类的成员方法 4.5 类的继承 4.6 this和super变量 4.7 抽象类 4.8 内部类 4.9 Java程序的执行 4.10 课后练习
  • 4. 4.1 面向对象编程4.1.1 面向过程 4.1.2 面向对象
  • 5. 4.1 面向对象编程在介绍类之前,需要首先了解面向对象编程的基本思想,下面将分别介绍面向过程和面向对象的特点,从中了解面向对象编程的优点。
  • 6. 4.1.1 面向过程面向过程的程序设计思想在解决问题的时候,从问题的每个细节入手来展开系统流程,比较适用于解决简单的问题。“面向过程”是一种以事件为中心的编程思想。它并不关心整体,而是关心整体中的每个细节。
  • 7. 4.1.2 面向对象面向对象的程序设计(Object Oriental Programming,OOP)思想是最近十年发展起来的程序设计模式,其目标是将软件系统待处理问题或者事务抽象为对象(Object),由于对象本身具有一定的特征和行为,因此可以通过对象间的消息传递的方式驱动对象的动作,进而实现软件系统的功能。
  • 8. 4.1.2 面向对象面向对象方法提供了许多新的概念,如对象、方法、消息、类、实例、继承性、封装性等。这些概念是理解和使用面向对象方法的基础和关键。 1. 对象、方法、消息 对象(Object),在客观世界中指每一客观实体,如一本书,一台机器等。 对象的数据结构特征使用属性(名)表示,数据的属性值则描述对象的状态,如书的目录、正文等。对象的数据操作(也叫方法、处理),如增加、删除、查找数据等,可以操纵对象数据,改变对象的状态。 消息(Message)是用来请求对象执行某一操作或回答某些信息的要求。
  • 9. 4.1.2 面向对象2. 类、实例、继承性 在客观世界中,类是许多具有相同特征事物的总称,如字典、期刊、著作等统一归类为书。从对象角度看,具有共同属性、共同操作性质的对象的集合就是类(Class)。在类层次结构中,相对上层的是超类,相对下层的叫子类。 继承性(Inheritance)指对象继承其所属类定义的数据和数据操作,或者子类继承其所属超类定义的数据和数据操作。
  • 10. 4.1.2 面向对象3. 抽象与封装 (1) 抽象 面向对象程序设计具有抽象、封装、继承和多态4个特点。抽象去掉了被研究对象中与主旨无关的次要部分,而仅仅抽取出与研究工作有关的实质性的内容加以考虑。抽象有两类:一类是过程抽象,另一类是数据抽象。 面向对象程序设计强调数据抽象,数据抽象把系统中需要处理的数据和这些数据上的操作结合在一起,根据功能、性质、作用等因素抽象成不同的抽象数据类型。每个抽象数据类型既包含数据,又包含针对这些数据的操作,是相对于过程抽象更为严格合理的抽象方法。
  • 11. 4.1.2 面向对象(2) 封装 封装就是利用抽象数据类型把数据和基于数据的操作封装在一起,数据被保护在抽象数据类型的内部,系统的其他部分只有通过数据的操作,才能够与这个抽象数据类型进行交互。封装包含两层含义。 第一,把对象的全部属性及其行为结合在一起,形成一个不可分割的独立单位(即对象)。第二,信息隐蔽,即尽可能隐蔽对象的内部细节,对外形成一个边界(或者说形成一道屏障),只保留有限的对外接口,使之与外部发生联系。
  • 12. 4.2 类 的 描 述4.2.1 类的定义 4 2 2 类的构造及其实例化
  • 13. 4.2 类 的 描 述在Java中,新的类可以在已有类的基础上构造,这称为类的派生。大多数类都是派生得到的。派生得到的新类称为已有类的子类,而此已有类则称为父类。 类的结构分为两部分,一是类的声明,二是类体。其格式如下。 classDeclaration { classBody }
  • 14. 4.2.1 类的定义类的定义包括类的声明和类体的声明,下面分别介绍。 1. 类的声明 类的声明由关键字class、类的名字和类的属性3部分组成。关键字class用固定的小写格式,类的名字是由程序员起的,可以用任意一个名词,但书写格式须符合 Java 编码规定,这两部分是类的声明中必须有的内容。类的属性是可选的,用来说明此类有关的各种特性,包括说明这个类的父类是哪一个,访问这个类有什么限制等。
  • 15. 4.2.1 类的定义类的属性用来说明以下3方面的内容。 (1) 指出访问权限 已知由类创建出对象,而多个类组成包,同一个包中的类可以互相访问。但是有一种类,它们不但可以被同一个包中的类访问,还可以被包以外的其他类或对象访问,这些类被称为公共类。在类的声明中用public来说明公共类特性,public放在类属性的最前面。与public相对应,还有一些类只能被同一个包中的其他类访问,这种类用private来说明特性。
  • 16. 4.2.1 类的定义(2) 指出父类(extends部分) 前面已提到,大多数的类都是从父类派生得到的,父类也称为超类(SuperClass)。在类的属性中,用关键字extends和父类名构成一个语素来说明这一点。这个语素放在类名和类体之间,采用如下格式: extends SuperClassName
  • 17. 4.2.1 类的定义(3) 指出接口(implements部分) 接口是和类很相似的一种数据结构,接口专门供给类调用,本书后面的章节会专门介绍接口的结构和调用。这里要说明的是,如果类要调用一个接口,就应该按照如下格式: implements InterfaceList 其中,implements是专门用来调用接口的关键字,而InterfaceList是接口名字的列表。
  • 18. 4.2.1 类的定义综上所述,类的声明应该是按如下形式: [modifiers]class ClassName [extends SuperclassName][implements InterfaceList]{ } 上述表示中,带方括号的部分是可选的。格式说明如下。 modifiers:类的访问权限,具体用public,private和final。 className:类的名字。 extends:指出此类的父类,其中SuperclassName就是父类名。 implements:指出本类所继承的接口,其中的InterfaceList可以是一个由逗号隔开的接口名字的列表,也可以只有一个接口。 在这些成分中,只有关键字class和类名字是必须的,其他均为可选成分。如果没有某个可选成分,在编译时,Java编译器将赋予此类以相应的默认成分。比如:非公共类、非专用类、非最终类、不调用任何接口、父类为Object等。
  • 19. 4.2.1 类的定义2. 类体的声明 类体是类的主体内容,它包括两部分:变量声明和方法。 在前面已经讲到,在Java的类中,变量表明类的状态,方法实现类的行为,正是这两部分内容构成了类体。习惯上将类中的变量称为类的成员变量。成员变量的类型可为Java的任意数据类型。在一个类中,成员变量的名字是惟一的,但成员变量的名字可以和方法的名字相同。所以,将刚才列出的类的格式再具体化一些,如下: class className { memberVariableDeclarations methodDeclarations }
  • 20. 4 2 2 类的构造及其实例化在定义完类之后,需要进行类的构造及其实例化,下面分别介绍。 1. 类的构造 在每个类中,都有一种特殊的方法,称为构造方法。构造方法的功能是为从这个类新创建的对象分配内存空间和进行初始化。每次创建对象时,系统便自动调用相应类的构造方法。构造方法的特殊之处还在于它不能有独立的方法名字,而且只能有入口参数,没有返回值。但实际上,构造方法仍然是有名字的,构造方法的名字叫init,这是由编译器隐含提供的,但此名不允许程序员使用。所以,通常总是将类的名字作为构造方法的名字。
  • 21. 4 2 2 类的构造及其实例化在Java中调用构造方法时应遵循如下一些规则。 (1) 从一个类创建对象时,可以调用此类的父类的构造方法。调用父类的构造方法很容易,只要在类的构造方法的方法体中,第一条为super语句就可以了,super可以调用父类的任何一个带入口参数或不带入口参数的构造方法。 (2) 如果一个类的构造方法中第一个语句没有用super来调用其父类的构造方法,则编译器也会默认为在构造方法中用super()语句调用父类的不带参数的构造方法。但是,假如此时父类中所有的构造方法都是必须带有入口参数的,那就会使编译出错。
  • 22. 4 2 2 类的构造及其实例化(3) 如果某个类的构造方法第一个语句是用this来调用本类的另一个构造方法,那么Java系统就不会再默认这个构造方法调用父类的构造方法。 (4) 一个构造方法用this语句调用本类的另一个构造方法时,如果被调用的构造方法又是调用父类的构造方法而又没有用super语句,那么,Java编译器会默认它含有super()语句。此时,如果父类中不存在不带参数的构造方法,则编译将会出错。
  • 23. 4 2 2 类的构造及其实例化2. 类的实例化 在Java中,对象是从类创建出来的。 创建对象包括定义对象、建立对象和初始化对象3步。 (1) 定义对象 定义对象的格式为: type name;
  • 24. 4 2 2 类的构造及其实例化(2) 建立对象 一个对象必须配置相应的存储空间,才能产生功效。但是,定义对象时,并没有为对象分配内存,所以,要由建立对象这一步来为对象分配内存。建立对象实际上是将一个类进行实例化,这是通过关键字new来完成的。关键字new所对应的具体动作是调用对应类中的构造方法来完成内存分配,然后将分配的内存地址作为返回参数给所定义的对象。
  • 25. 4 2 2 类的构造及其实例化(3) 初始化对象 初始化对象就是指从一个类生成一个对象时,为这个对象确定初始状态。 实际上,初始化对象是在建立对象的同时完成的。当用关键字new调用构造方法时,构造方法不但为这个对象分配了内存空间,也实现了初始化,即给对象确定初始状态。程序员在程序设计时,一般将调用构造方法得到的状态结果直接赋给一个变量。
  • 26. 4.3 类的成员变量4.3.1 成员变量的定义 4.3.2 成员变量的访问权限 4.3.3 静态变量 4.3.4 常量
  • 27. 4.3 类的成员变量变量可以属于一个类,也可以属于一个方法,这是由变量的作用域决定的。本节重点介绍类的成员变量。
  • 28. 4.3.1 成员变量的定义类的成员变量必须放在类体中,但不能包含在某一个方法体中。最简单的成员变量表示如下: type variableName; type称为变量类型,可以是Java允许的任何数据类型,包括各种简单类型,如整型、浮点型等,也包括各种组合类型,如数组等。variableName是变量名,这是由程序员任意起的名字(必须符合命名规定)。
  • 29. 4.3.2 成员变量的访问权限访问权限表示满足什么条件时此变量可以被访问。访问权限用关键字public、private、protected或private protected表示。类的成员变量的访问权限分5种类型。 1. 公用(public)变量 凡是被冠以public的变量,都允许Java系统中所有的类访问,既允许此变量所属的类访问,也允许同一个包中的其他类访问,还允许其他包中的类访问。比如: class Alpha { public int xpub; }
  • 30. 4.3.2 成员变量的访问权限2. 专用(private)变量 专用变量即用private限定的类变量,凡是专用变量都只能被其所属的类访问。比如: class Alpha { private int xPrivate; }
  • 31. 4.3.2 成员变量的访问权限3. 保护型(protected)变量 保护型变量允许被其归属的类、由此类派生的子类以及同一包中的其他类访问。比如: package Greek; class Alpha { protected int xProtected; }
  • 32. 4.3.2 成员变量的访问权限4. 专用保护型(private protected)变量 同时冠以private和protected 的变量称为专用保护型变量。这类变量只允许它归属的类和由此类派生的子类访问。比如: class Alpha { private protected int xPriPro; }
  • 33. 4.3.2 成员变量的访问权限5. 默认型变量 这类变量也叫友好型变量。在定义时,默认型变量前面不用任何词来修饰,就是说,没有设置访问权限。这便是“友好”的含义。默认型变量除了可被所归属的类访问外,还可以被同一包中的其他类访问。比如: package Greek; class Alpha { int xFri; }
  • 34. 4.3.3 静态变量1. 实例变量 一个类的每个对象对于类定义中出现的每个实例变量都有自己的副本。每个对象对于这些实例变量都拥有它自己的值。“实例变量”这个名字来源于这样的事实,即对象是类的一个“实例”,并且是一个类的不同对象,实例变量中存储的值也不相同。在通常情况下,实例变量在类定义中声明,它应包括一个类型名和一个变量名,并且可以为它指定一个初始值。
  • 35. 4.3.3 静态变量2. 类变量 一个给定的类中的每个类变量只有一个副本,并且这些类变量被类中所有的对象共享。即使类中没有建立任何对象,类变量也存在。它们属于类并且可以由类或任何对象引用,而不仅仅是该类中的实例。如果一个类变量的值发生了改变,这个新值对于类中的所有对象都有效。这一点与实例变量完全不同,实例变量的值改变后对其他对象毫无影响。
  • 36. 4.3.4 常量 Java往往将常量也统称为变量,常量在程序中是不能被改变的,如果企图改变,则编译时会产生出错指示。如果一个变量是常量,则用final表示。习惯上用大写字母表示常量名字。 综合以上各节所讲,类的成员变量的定义格式如下: [variableModifier] type variableName; 方括号中为变量的属性,这是可选项,它可以是public、private、default、protected、private protected、static和final。type为变量类型,后面为变量名字。
  • 37. 4.4 类的成员方法4.4.1 静态方法 4.4.2 抽象方法 4.4.3 最终方法 4.4.4 本地方法 4.4.5 同步方法 4.4.6 形参和实参 4.4.7 成员方法重载
  • 38. 4.4 类的成员方法成员方法是类的行为,标志着类所具有的功能,是对类中成员变量的操作。Java中方法的一般格式如下: [方法修饰符] [返回值类型] <方法名> ([<形式参数列表>]) [throws <异常列表>] { <方法体> } 成员方法是具有相对独立性的功能模块,是一个类与外界进行通信的接口。成员方法也有一些修饰符:访问控制符public、protected和private,非访问控制符static、abstract、final、native 和synchronized。下面分别讨论这几个非访问控制符。
  • 39. 4.4.1 静态方法使用关键字static声明的成员方法称为静态方法。静态方法也称为类方法(class method),它与类关联,是属于整个类的,即使类中一个对象也不存在,也可以执行该类的类方法。正是因为在没有对象存在的情况下也可以执行类方法,因此它只能调用类变量,即静态方法只能处理静态变量,而不能处理类中的实例变量。很明显,实例变量是属于某个特定对象的,如果对象不存在,实例变量也就不存在,这时用类方法去操纵和处理一个可能不存在的变量肯定会出问题。实际上,Java 编译器根本就不允许做这样的尝试。如果在一个类方法中引用了一个实例变量,系统将拒绝编译,从而出现出错信息。
  • 40. 4.4.2 抽象方法 使用关键字abstract声明的成员方法称为抽象方法。抽象方法只有方法头,而没有方法体。抽象方法的声明以一个分号结束。
  • 41. 4.4.3 最终方法 使用关键字final声明的成员方法称为最终方法。最终方法的功能和内部语句不能再被更改,也就是说,该方法不能被当前类的子类重新定义。最终方法使得子类不能重新定义与父类同名的方法,而只能使用从父类继承来的方法,从而防止了子类对父类一些方法的错误重定义,保证了程序的安全性和正确性。
  • 42. 4.4.4 本地方法使用关键字native声明的成员方法称为本地方法,也称为自然方法。native方法实际上是用C、C++、汇编等其他编程语言编写的方法,而不是用Java语言编写的。因为native方法的方法体是用其他语言在Java程序外部实现的,所以native方法没有方法体,用一个分号结束。native方法充分利用了已经存在的程序模块,体现了软件开发的复用性,但是也使得Java的跨平台特性受到了限制和破坏。Java虚拟机中有一个JNI(Java Native Interface),称为Java本地接口,使Java虚拟机可以与操作系统交互,实现所有平台的线程。
  • 43. 4.4.5 同步方法使用关键字synchronized声明的成员方法称为同步方法,该方法主要用于多线程程序中的线程协调和同步。如果synchronized修饰的方法是一个类方法(静态方法),那么在被调用执行前,将把系统类Class中对应当前类的对象加锁。如果synchronized修饰的是一个实例方法(对象的方法),则这个方法在被调用执行前,将把当前对象加锁。
  • 44. 4.4.6 形参和实参 定义方法时指定了一个参数列表,当调用方法时,必须按照参数列表给出参数。但是要注意的一点是,Java中,在方法内部,对传来的参数实际上是使用它的一个副本,方法只能对这个副本进行操作。
  • 45. 4.4.7 成员方法重载方法重载是指多个方法享有相同的名字,但是这些方法的参数必须不同,或者是参数的个数不同,或者是参数类型不同。返回类型不能用来区分重载的方法。前面介绍的,在一个类中可以有多个构造函数,但它们的名字必须保持和类的名字相同,这也是一种重载。只不过构造函数与一般的方法的作用机制不同而已。 参数类型的区分度一定要足够,例如不能是同一简单类型的参数,如int与long。
  • 46. 4.5 类 的 继 承类的继承是面向对象的程序设计语言所具有的重要技术。有了继承技术,程序设计时,就可以先定义一个包含公用变量和公用方法的类作为父类,再在此基础上创建具有专用变量和专用方法的子类。子类一方面可以增加父类中没有的变量和方法,另一方面还可以在继承基础上再定义父类中已有的变量和方法。 Java系统要求应用程序中每个类都有父类,如果一个类的定义中没有用关键字extends明确指出父类名,则Java系统默认这个类的父类为系统软件包java.1ang中的Object类。父类中凡是公用型的、保护型的或者专用保护型的变量和方法均可由子类直接调用,只有父类的专用型变量和专用型方法不能被子类调用。
  • 47. 4.6 this和super变量this和super是Java的两个关键字,它们用在方法体中作为两个特殊的变量前缀和方法前缀。this用来指明当前对象的成员变量或方法,以区分于同名的局部变量和其他同名的方法,而super则用于指出父类的变量和方法。
  • 48. 4.6 this和super变量1. this的使用场合 一个对象中的方法一般可以直接访问同一对象的成员变量。但是,有时候方法体内部定义的变量和成员变量名字相同,还有时方法的入口参数和对象的成员变量名字相同,那么就需要将三者区别清楚。因此,专门用this来指明当前对象的成员变量或当前对象的方法。
  • 49. 4.6 this和super变量2. super的使用场合 在Java中,由父类派生子类,这样,子类的成员变量可能和父类的成员变量名字相同,子类的方法也可能和父类的方法一样。当需要调用父类的同名方法或使用父类的同名变量时,在子类中可用关键字super作前缀来指明父类的成员变量和方法。
  • 50. 4.7 抽 象 类在Java语言中,将abstract关键字修饰的类称为抽象类。与此相对应,用abstract关键字修饰的方法称为抽象方法。当一个类的定义完全表示抽象的概念时,它应该被实例化为一个对象,abstract类必须被继承,abstract方法必须被重写。 定义一个抽象类的格式如下。 abstract class ClassName{…} 抽象类中可以包含抽象方法,对抽象方法只需声明,而不需要实现,格式如下: abstract returnType MethodName([patamList]);
  • 51. 4.8 内 部 类JDK l.1版本之后,引入了内部类这个概念,所谓内部类,就是在某个类的内部嵌套定义的一个类,内部类可以是其他类的成员,也可以在一个语句块的内部定义,还可以在一个表达式内部匿名定义。
  • 52. 4.8 内 部 类内部类具有下面这些特性。 内部类可以定义为abstract。 内部类可以声明为private或protected。 内部类可以使用包含它的类的成员变量,包括静态和实例成员变量,也可以使用内部类所在方法的局部变量。 内部类不能与包含它的类名相同。 内部类如果被声明为static,就变成顶层类,这样就不能再使用局部变量,内部类是顶层类时,才可以声明static成员。 内部类可以像外部类那样被继承,同样也可以实例化。
  • 53. 4.8 内 部 类【例4.20】内部类运用举例,程序如下。 public class mainClass { public static void main(String []args) { mainClass obj=new mianClass(); obj.printMethod(); } void printMethod() { innerClass innObj=new innerClass(); innObj.outFun(); } class innerClass { public void outFun() { System.out.println("This is a inner class testing!"); } } }
  • 54. 4.8 内 部 类1. 内部类的实例化 参看下面的例子。 【例4.21】内部类的实例化举例,程序如下。 class Outerclass { private static int number=100; class innerclass { private int number=50; public void print() { System.out.println("下面的index是内部类的:"); System.out.println(this.number); // 访问内部类的成员 System.out.println("下面的index是外部类的:"); System.out.println(Outerclass.this.number);// 访问外部类的成员 } } }
  • 55. 4.8 内 部 类class Test { public static void main(String []args) { Outerclass oc=new Outerclass(); Outerclass.innerclass oi=oc.new innerclass(); } } 上面的例子中定义了一个外部类Outerclass,在这个类中有一个内部类innerclass,在类Test中将内部类进行了实例化。
  • 56. 4.8 内 部 类2. 内部类的继承 【例4.23】内部类的继承的举例,程序如下。 class Outer { class inner { inner() { System.out.println("内部类被派生了!"); } } } class innerclasschild extends Outer.inner { innerclasschild(Outer Outer) { Outer.super(); } }
  • 57. 4.8 内 部 类class Test { public static void main(String []args) { Outer o=new Outer(); innerclasschild ic=new innerclasschild(o); } } 在上述例子中,innerclasschild类由Outer的内部类innerclass派生。在innerclasschild类的构造函数中,就要接收一个Outer类型的参数。以通过该参数访问Outer的内部类。
  • 58. 4.9 Java程序的执行4.9.1 Java应用程序 4.9.2 用户界面 4.9.3 Object类
  • 59. 4.9.1 Java应用程序1. 源程序的编辑 Java源程序是简单的文本文件,以.java为扩展名,许多文本编辑工具都可以编辑Java源程序,现在各种Java集成开发环境都自带Java源代码编辑器。 【例4.24】简单的Java Application示例,程序如下。 //*********** HelloWorld.java********** //简单的Java Application示例程序 import java.io.*; public class HelloWorld { public static void main(String args[]) { System.out.println("Hello,World!"); } }// HelloWorld类结束
  • 60. 4.9.1 Java应用程序程序中的前两行是注释行,Java语言的单行注释同C++基本相同。第3行利用import语句加载Java系统类库中已经定义好的类或包。第4行声明类名为HelloWorld。类名是在源文件中指明的,它可在与源代码相同的目录上创建一个.class文件。在本例题中,编译器创建了一个称为HelloWorld.class的文件,它包含了公共类HelloWorld的编译代码。第6行的main方法是一个特殊的方法,所有的Java Application程序都必须有且只有一个main方法,该方法是程序的入口,并且main方法的方法头必须书写为public static void main(String args[ ])的格式,其各个关键字的含义如下所述。
  • 61. 4.9.1 Java应用程序public:表明main( )方法可被任何程序访问,包括Java解释器。 static:说明mian( )为静态方法。为使main( )在程序做其他事之前就开始运行,这一关键字是必要的。 void:表明main( )不返回任何信息。这一点是重要的,因为Java编程语言要进行谨慎的类型检查,包括检查调用的方法确实返回了这些方法所声明的类型。 String args[ ]:是一个String数组的声明,它将包含位于类名之后的命令行中的自变量。 第8行演示如何使用类名、对象名和方法调用。它使用由System类的out成员引用的PrintStream对象的println( )方法,将字符串“Hello World!”打印到标准输出上。 在一个源文件中可以定义多个类。下面的例子中定义了两个类,其中包含有main()方法的ClassDemo类是程序的主类。
  • 62. 4.9.1 Java应用程序2. 字节码的编译、解释与运行 Java语言中的源代码经编译后生成的目标代码为字节码。字节码是二进制文件,必须有Java语言的解释器来解释执行。在JDK软件包中的编译器为javac.exe,而解释器为java.exe,用来解释执行Java Application字节码。 现在可以运行该程序。首先把它放到一个名为HelloWorld.java的文件中,这里,文件名应和类名相同,因为Java解释器要求公共类必须放在与其同名的文件中。假设把HelloWorld.java放在“F:\java_world\java课程”路径下,然后对它进行编译: F:\java_world\java 课程>javac HelloWorld.java 编译的结果生成字节码文件HelloWorld.class。最后用Java解释器来解释运行该字节码文件: F:\java_world\java 课程>java HelloWorld 结果在屏幕上显示“Hello World!”。
  • 63. 4.9.2 用户界面1. 图形界面 Java Applet程序和Java Application程序都可以进行图形界面的输入/输出。图形用户界面(Graphics User Interface)简称GUI,是目前大多数应用程序使用的输入/输出界面。它在图形模式下工作,具有操作简便、美观易懂等优点。 Java Applet程序需要在WWW浏览器中运行,而浏览器本身是图形界面的环境,所以Java Applet程序只能在图形界面下工作。
  • 64. 4.9.2 用户界面【例4.26】Java Applet图形界面应用,程序如下。 //*********** AppletGUI.java********** // Java Applet图形界面应用 import java.awt.*; //加载awt包中的所有类 import java.awt.event.*; //加载event包中的所有类 import java.applet.*; //加载applet包中的所有类 public class AppletGUI extends Applet implements ActionListener //定义4个文本框和1个文本域 TextField tfName,tfPassword; //用于提示的文本框 TextField lbName,lbPassword; //用于用户输入的文本框 TextArea taContext; //文本域 public void init( ) {
  • 65. 4.9.2 用户界面 lbName=new TextField("用户名: "); //文本框 tfName=new TextField(30); //文本框的长度能容纳30个字符 lbPassword=new TextField("密码: "); //文本框 tfPassword=new TextField(30); //文本框的长度能容纳30个字符 tfPassword.setEchoChar('*'); //用户的输入显示为一系列的“*”号 taContext=new TextArea(5,30); //文本域的大小设为5行,每行30个字符 lbName.setEditable(false); //把文本框设置为不可编辑 lbPassword.setEditable(false); //把文本框设置为不可编辑 setLayout(new FlowLayout( )); //设置布局管理器为流式布局策略 add(lbName); add(tfName); add(lbPassword); add(tfPassword); add(taContext); tfPassword.addActionListener(this); } public void actionPerformed(ActionEvent event) { taContext.setText("用户名:" + tfName.getText( ) +"\n"+"\n" +"密码:" +tfPassword.getText( )); } }// AppletGUI类结束
  • 66. 4.9.2 用户界面运行结果如图4-8所示。 图4-8 运行结果(例4.26)
  • 67. 4.9.2 用户界面该例的功能是接收用户输入的用户名和密码两个字符串,当用户输入完毕并按Enter键时,程序获得这两个字符串并输出。 程序的3、4、5行分别加载了Java类库的3个包中的类:java.awt.*、java.awt.event.*和Java.applet.*。所有的Java Applet程序都必须加载java.applet包,使用图形界面的Java程序一般都要加载java.awt包,使用图形界面的事件处理机制一般还要加载java.awt.event包。
  • 68. 4.9.2 用户界面第6行定义了程序中惟一的类AppletGUI。根据Java Applet程序的规定,这个类必须是Applet类的子类,用“extends Applet”来声明。“implements ActionListener”说明这个类是动作事件(ActionEvent)的监听者,实现了ActionListener接口。有关接口的概念后面章节中将详细阐述。
  • 69. 4.9.2 用户界面第8~13行定义了4个文本框(TextField)对象tfName、tfPassword、lbName、lbPassword和一个文本域(TextArea)对象taContext。其中,lbName和lbPassword用于提示信息,tfName和tfPassword用于接收用户输入的信息,taContext用于输出程序处理的结果信息。 第14~31行定义了AppletGUI类中的init()方法来完成Applet的初始化工作。第30行的作用是把tfPassword对象注册给Action事件的监听者,否则程序将不能响应用户在tfPassword中按Enter键的操作。
  • 70. 4.9.2 用户界面第32~36行定义了AppletGUI类的另一个方法actionPerformed(),动作事件的监听者使用这个方法来处理动作事件。在程序中,当tfPassword中按Enter键引发动作事件时,利用taContext.setText()方法把用户输入的用户名和密码输出到taContext 文本域中。程序的第20行利用tfPassword.setEchoChar('*')把用户的输入显示为一系列的“*”号,但是在taContext 文本域中仍然能够正确显示输入的密码。
  • 71. 4.9.2 用户界面2. 字符界面 字符界面是指字符模式的用户界面,常称为控制台程序。在字符界面中,用户用字符向程序发出命令传送数据,程序运行的结果也用字符的形式表达。虽然图形用户界面已经非常普及,但是在某些情况下仍然需要用到字符界面的应用程序,例如字符界面的操作系统,或者仅仅支持字符界面的终端等。
  • 72. 4.9.2 用户界面【例4.28】Java Application字符界面应用,程序如下。 //*********** ApplicationConsole.java********** // Java Application字符界面应用 import java.io.*; public class ApplicationConsole { public static void main(String args[ ]) { String s=" "; System.out.print("输入字符串: "); try{ BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); s = in.readLine(); } catch(IOException e){ System.err.println(e); } System.out.println("输出字符串: " + s); System.out.println(" "); } }// ApplicationConsole类结束
  • 73. 4.9.2 用户界面该例的执行结果如图4-10所示。这个例子中使用了java.io包中两个关于输入/输出的类BufferedReader和InputStreamReader。这两个类是缓冲输入流类,有关流式输入/输出的内容在后面的章节中将详细阐述。第12行中的System.in 代表了系统默认的标准输入(即键盘),首先把它转换成InputStreamReader类的对象,然后转换成BufferedReader类的对象in,使原来的比特输入变成缓冲字符项输入。第13行利用readLine()方法读取用户从键盘输入的一行字符并赋值给字符串对象。
  • 74. 4.9.2 用户界面现在有很多集成开发环境一般都有自己的Java解释器和编译器,例如Visual J++,也有一些集成开发环境已经把JDK的解释器javac.exe和编译器java.exe集成到自己的软件中。
  • 75. 4.9.2 用户界面 图4-10 运行结果(例4.28)
  • 76. 4.9.3 Object类Object类是Java类库中的一个特殊的类,它是类库中所有类的父类,也是用户自定义的所有类的直接或者间接父类。也就是说,用户定义的所有类在默认情况下都是Object类的子类,无论用户是否显式声明Object类作为自己定义的类的父类。这是系统自动完成的,由此,通常把Object类称为通用超类。 Object类中的成员恰好都是方法,其中有7个为public类型的,2个为protected类型的。用户自定义的所有类都将继承这些方法。Object类中的7个public类型的方法分别是toString()方法、equals()方法、getClass()方法、hashCode()方法、notify()方法、notifyAll()方法和wait()方法,2个protected类型的方法是clone()方法和finalize()方法。
  • 77. 4.9.3 Object类下面主要讨论Object类中比较主要和常用的toString()方法和equals()方法。 1. toString()方法 Object类的toString()方法返回文本化描述当前对象的String 数据。默认情况下,该对象的表示形式是:类名后面跟一个“@”和该对象hash 码的十六进制表示。当然,用户可以在自己的类中重写该方法。toString()方法会在使用“+”号把一个对象与String类型的变量连接的时候自动调用。
  • 78. 4.9.3 Object类【例4.29】toString()方法示例,程序如下。 //*********** TesttoString.java********** //测试Object类的toString()方法 import java.io.*; class Father { protected String name; Father( ) { name = "Noname"; } Father(String s) { name = s; } public void setName(String s) { name = s; } public String getName( ) { return name; } }// Father类结束
  • 79. 4.9.3 Object类class Child extends Father { Child( ) { super( ); //调用Father类的无参构造方法 name = "Noname"; //有super( )的调用,这行代码可以去掉 } Child(String s) { super(s); //调用Father类的有参构造方法 name = s; //有super(s)的调用,这行代码可以去掉 } public String toString( ) { return "This is child,and his name is " + name; } }// Child类结束
  • 80. 4.9.3 Object类//主类 public class TesttoString { public static void main(String args[ ]) { Father f = new Father("John"); System.out.println(f); //System.out.println(f.toString( ));同上一行的执行效果一样 Child c = new Child("Joe"); System.out.println(c); //System.out.println(c.toString( ));同上一行的执行效果一样 System.out.println(" "); } }// TesttoString类结束
  • 81. 4.9.3 Object类该例中定义了3个类:Father类、Child类和TesttoString类。其中,Child类是Father类的子类,TesttoString类是程序的主类。TesttoString类中创建了Father类的一个对象f 和Child类的一个对象c。因为用户定义的所有类都是系统类Object 的子类,所以Father类也是Object类的子类。因为Father类中没有对Object类的toString()方法进行重写,所以输出的结果为Father类的类名跟一个“@”和该类对象hash码的十六进制表示,即图4-11所示中的Father@12498b5。而Child类中对Object类的toString()方法进行了重新定义,所以输出了“This is child,and his name is Joe”的结果。第47行System.out.println(f)的输出结果就是执行了f对象的toString( )方法。所以第47行和第48行的执行效果是一样的。因为输出某个对象时系统会自动调用该对象的toString( )方法。
  • 82. 4.9.3 Object类 图4-11 运行结果(例4.29)
  • 83. 4.9.3 Object类2. equals()方法 Object类的equals()方法用于比较以参数传递过来的对象和当前对象,如果它们是相同的对象(不仅是相等,而且必须是同一个对象),则返回true;如果它们是不同的对象,即使两者的数据成员相等,也将返回false。
  • 84. 4.9.3 Object类下面的例子测试了Object类中的equals()方法。 【例4.30】equals()方法示例,程序如下。 //测试Object类的equals()方法 import java.io.*; class Cylinder { // 常量 public static final double PI = 3.14; // 成员变量 private double height; //圆柱体的高 private double radius; //圆柱体的半径 Cylinder( )//无参数构造方法 { height = 0.0; radius = 0.0; } Cylinder(double r, double h) //有参数构造方法 { height = r; radius = h; }
  • 85. public void setRadius(double r) //设置圆柱体的半径 { radius = r; } public void setHeight(double h) //设置圆柱体的高 { height = h; } public double getRadius( ) //获取圆柱体的半径 { return radius; } public double getHeight( ) //获取圆柱体的高 { return height; } public double surfaceArea( ) //计算表面积 { return 2*PI*radius*height+2*PI*radius*radius; } public double volume( ) //计算体积 { return PI*radius*radius*height; } }// Cylinder类结束
  • 86. 4.9.3 Object类//主类 public class TestEqual { public static void main(String args[ ]) { //创建Cylinder类的对象c1,c2,c3,c4,c5 Cylinder c1 = new Cylinder( ); Cylinder c2 = new Cylinder( ); Cylinder c3 = new Cylinder( 5.0, 6.0); Cylinder c4 = new Cylinder( 5.0, 6.0); Cylinder c5 =null; c5 = c4; // 测试equals()方法 if (c1.equals(c2)) System.out.println("c1和c2是相同的对象"); else System.out.println("c1和c2是不同的对象"); System.out.println(" ");
  • 87. 4.9.3 Object类 // 测试equals()方法 if (c3.equals(c4)) System.out.println("c3和c4是相同的对象"); else System.out.println("c3和c4是不同的对象"); System.out.println(" "); // 测试equals()方法 if (c5.equals(c4)) System.out.println("c5和c4是相同的对象"); else System.out.println("c5和c4是不同的对象"); System.out.println(" "); } }// TestEqual类结束
  • 88. 4.9.3 Object类上例的执行结果如图4-12所示。该例中定义了一个圆柱体(Cylinder)类和一个TestEqual类。在主类中创建了Cylinder类的5个对象:c1、c2、c3、c4 和c5。虽然Cylinder类的对象c1和c2是使用同样的创建方法产生的,它们有相等的成员变量,但是c1和c2仍然是不同的对象。因为引用的是两块不同的内存。同理,c3和c4也是不同的对象。但c4和c5是同一个对象,因为执行语句“c5 = c4;”后,c4和c5引用的是同一块内存。
  • 89. 4.9.3 Object类例中Cylinder类没有自己定义equals()方法,所以Cylinder类的equals()方法是继承Object类的equals()方法。用户可以根据程序的需要在自己定义的类中重新定义equals()方法,以取代Object类的equals()方法。String类是系统定义的字符串类,该类已经重写了Object类的equals()方法。下面的例子说明了String类的equals()方法和运算符“==”的区别。
  • 90. 4.9.3 Object类 图4-12 运行结果(例4.30)
  • 91. 4.10 课 后 练 习1. 填空题 (1) 定义类的关键字是__________,一个类的实现包括两个部分:__________和__________。 (2) 成员方法的非访问控制符有__________、__________、__________、__________和__________。 2. 选择题 (1) 下列( )不是面向对象程序设计的特点。 A. 抽象 B. 封装 C. 连续 D. 继承 (2) abstract 能与( )并列修饰同一个方法。 A. static B. final C. private D. public 3. 判断题 (1) 不含任何抽象方法的类一定不是抽象类。 ( ) (2) 使用关键字static声明的成员变量称为静态变量。静态变量也称类变量,它与类关联,由类中的所有对象共享。 ( )
  • 92. 4.10 课 后 练 习4. 简答题 (1) 什么是抽象?什么是封装? (2) 类成员的访问控制符有哪些?说明各个访问控制符的含义。 (3) 什么是抽象类?什么是最终类?试举例说明抽象类和最终类的区别。 5. 操作题 (1) 编写一个名为Complex 的类,完成复数的数学运算。同时提供public 方法实现复数的加减乘除运算,并提供打印方法。 (2) 编写一个名为Date 的类,要求提供多个构造方法完成对实例变量year、month 和day 的初始化,提供分别设置和获取year、month 和day 实例变量的public 方法。
  • 93. Q & A? Thanks!