第3章 面向对象的编程基础.doc_第1页
第3章 面向对象的编程基础.doc_第2页
第3章 面向对象的编程基础.doc_第3页
第3章 面向对象的编程基础.doc_第4页
第3章 面向对象的编程基础.doc_第5页
已阅读5页,还剩43页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第3章 面向对象的编程基础面向对象程序设计(Object Oriented Programming)是目前主流的程序设计方法,它已经基本替代了1970年代初期发展的“结构化的”、基于过程的程序设计技术。Java语言是一种完全的面向对象的程序设计语言,它全面支持面向对象的程序设计方法。核心内容:1. 面向对象的基本概念2. 类的定义3. 对象的使用3.1 面向对象的基本概念所谓面向对象(object-oriented 简称: OO),就是一种一切从对象出发的思维方式,其主要思想为:现实世界是由一个个的对象组成的,并由此建立基于对象的概念模型,通过面向对象的理念使计算机软件系统能与现实世界中的系统一一对应。面向对象程序设计可以被视作一种在程序中包含各种独立而又互相调用的单位和对象的思想,这与传统的思想刚好相反:传统的程序设计主张将程序看作一系列函数的集合,或者直接就是一系列对电脑下达的指令。面向对象程序设计中的每一个对象都应该能够接受数据、处理数据并将数据传达给其它对象,因此它们都可以被看作一个独立的、负有特定责任的角色。与面向过程的程序设计方法不同:面向对象的程序设计方法更符合人们认识客观世界的思维习惯,降低了问题难度和分解问题的复杂度;提高了程序代码的重用性,简化了编程过程。目前已经被证实,面向对象程序设计推广了程序的灵活性和可维护性,并且在大型项目设计中广为应用。面向对象的程序设计方法主要涉及类、对象、封装、继承和多态等基本概念。3.1.1 对象和类面向过程的程序设计是以研究和实现解题过程为主体,而面向对象的程序设计是以研究各种对象为主体。对象是面向对象程序设计的核心,面向对象的程序是由若干对象组成的,通过对象的相互作用来实现整个程序的功能。类是面向对象程序设计的关键,类是同种类型的对象的抽象。1、对象对象是对问题领域中事物的抽象。对象具有三个要素,分别是状态、行为和标识。对象的状态是对象的静态属性,通常用变量来表示该对象的内部的各种信息。每个对象有其自己的内部变量,这些变量的值表示了该对象所处的状态。当对象的变量值发生了改变,则表示该对象状态发生了变化。例如,一部手机:品牌是诺基亚,价格是1500元, 颜色为银灰色,这些信息用对象中的内部变量保存,为对象的静态属性。对象的行为是对象的动态属性,也称为对象的功能。对象的行为在程序中用方法来表示,方法便是一种函数,对象的行为或功能被定义在一个个函数中。面向对象的程序设计方法中,对象内部包含了描述状态的各种属性和对其属性进行操作的若干方法。此外,还有对象与其它对象进行通信的接口,以便和其它对象协作完成某些功能。对象的标识是用来区分不同对象的标识符。每个对象都是惟一的,每个对象都具有一个仅属于它的惟一的标识,对象的标识是用对象名来表示的。对象的三个要素:状态、行为和标识,在计算机实现中分别用对象的变量、方法和对象名来表示。2、类类是一组具有相同属性和行为的对象的抽象。类是对现实世界中的实体的高度抽象,是对客观世界中某些实体的共性的提取。从程序设计角度来说,类是一种自定义的数据类型,通常称为类类型,类的某一个具体的对象被称为类的一个实例。类和对象是一般与个别的关系,或者说是抽象与具体的关系。类是一个模板,由它可以产生具有共同特性的不同的对象。类及类的关系构成了对象模型的主要内容,面向对象编程的主要任务就是定义对象模型中的各个类,最后将类实例化为对象。3.1.2封装性封装(Encapsulation)就是把对象的属性和行为结合成一个独立的单位,并尽可能隐蔽对象的内部细节。封装有两个含义:一是把对象的全部属性和行为结合在一起,形成一个不可分割的独立单位。对象的属性值(除了公有的属性值)只能由这个对象的行为来读取和修改;二是尽可能隐蔽对象的内部细节,对外形成一道屏障,与外部的联系只能通过外部接口实现。封装性具有以下优点:(1)封装的信息隐蔽作用反映了事物的相对独立性,可以只关心它对外所提供的接口,即能做什么,而不注意其内部细节,即怎么提供这些服务。(2)封装的结果使对象以外的部分不能随意存取对象的内部属性,从而有效地避免了外部错误对它的影响,大大减小了查错和排错的难度。另一方面,当对象内部进行修改时,由于它只通过少量的外部接口对外提供服务,因此同样减小了内部的修改对外部的影响。(3)封装机制将对象的使用者与设计者分开,使用者不必知道对象行为实现的细节,只需要用设计者提供的外部接口让对象去做。封装的结果实际上隐蔽了复杂性,并提供了代码重用性,从而降低了软件开发的难度。3.1.3 继承性继承性是面向对象方法中的重要特性。继承(Inheritance)反映了两个类之间的一种关系:一个类拥有了另一个类的所有数据和方法时,称该类继承了另一个类,这两个类具有继承关系。被继承的类称为父类或基类,继承父类所有成员的类称为子类或派生类。继承意味着“自动地拥有”,即子类中不必重新定义已在父类中定义过的属性和行为,而它却自动地、隐含地拥有其父类的属性与行为。继承允许和鼓励类的重用,提供了一种明确表述共性的方法。一个子类既有自己新定义的属性和行为,又有继承下来的属性和行为。尽管继承下来的属性和行为是隐式的,但无论在概念上还是在实际效果上,都是这个类的属性和行为。当这个特殊类又被它更下层的特殊类继承时,它继承来的和自己定义的属性和行为又被下一层的特殊类继承下去。因此,继承是传递的。继承可分为两种:单重继承和多重继承。单重继承是指只有一个父类的继承;多重继承是指有一个以上父类的继承。单重继承的程序结构比较简单,继承层次为树状结构;多重继承的程序结构相对复杂,其结构为网状。Java语言只支持单重继承,不支持多重继承,但Java语言可通过接口(interface)方式弥补由于不支持多重继承而带来的子类不可使用多个父类成员的不足。在软件开发过程中,继承性实现了软件模块的可重用性、独立性,缩短了开发周期,提高了软件开发的效率,同时使软件易于维护和修改。这是因为要修改或增加某一属性或行为,只需在相应的类中进行改动,而它派生的所有类都自动地、隐含地作了相应的改动。3.1.4多态性多态性(Polymorphism)也是面向对象方法的一个重要特性。多态是指程序中定义的引用变量所指向的对象的具体类型和通过该引用变量调用的实际方法在编程时并不确定,而是在程序运行期间才确定,即一个引用变量到底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。因为在程序运行时才确定具体的类,这样,不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,从而导致该引用调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。在Java语言中,多态性主要体现在以下方面:(1)方法重载。通常指在同一个类中,相同的方法名对应着不同的方法实现,但是方法的参数构型不同。在编译时根据实际调用方法的参数确定哪个方法被调用到。这种称为静态绑定。(2)成员覆盖。通常是指在子类中和父类中,有相同的变量名或方法名,但变量名的值、方法体的内容不同。当用超类类型的引用变量引用子类对象时,被引用对象的实际类型而不是引用变量的类型决定了调用哪个类的成员方法。这是在运行时动态确定的,称为动态绑定。Java中的多态性是通过综合运用向上转型、继承、覆盖,重载等实现的。多态性增强了软件的灵活性和扩展性,在面向对象程序设计中,为了提高程序的抽象程度和简洁程度,多态应用相当普遍。3.2类的定义Java程序的基本单位是类,Java所有的代码都是包含在一个个的类里面的。类可以认为是一种自定义的数据类型,是构造对象的模板,或者说对象是类定义的的数据类型的变量。一个类可以包含有成员变量、方法、初始化代码块,甚至还可以包含其它的类(内部类)。3.2.1类的定义形式定义类的形式如下所示: class extends implements ,其中,class,extends和implements是定义类时用到的关键字。关键字class用于定义一个新类,其后是所定义的类的类名。类名的命名方法同标识符,通常采用有意义的单词或者单词组合,首字母通常大写,如:Student,DbConn等。关键字extends用于说明定义的新类是某个已存在的类的子类,即指出新类的父类。这个已存在的父类可以是Java语言类库中已有的类,也可以是编程者已定义好的类。extends关键字体现了类之间的继承关系。关键字implements用于说明当前定义的新类实现了哪些接口(一个类可以实现多个接口)。接口是Java语言实现多重继承的一种特殊机制,将在4.3节中讲述。修饰符 是用来说明类的作用域和其它性质的。修饰符分为以下两类:l 访问修饰符:public、默认访问。l 非访问修饰符:abstract、final、strictfp。(1) public:说明该类为公共类,可以被所有包中的所有类所使用(不在同一包中时需要先导入)。(2) 默认访问:具有默认访问的类在定义时其前面没有任何访问修饰符,其只能被同一个包中的类所使用,而不能被其它包中的类所访问。(3) abstract:使用该修饰符的类被称为抽象类。抽象类是不能实例化的类,其存在的目的是用于扩展(即被子类继承)。通常抽象类是它的所有子类的属性的高度抽象。比如:如果我们进行一个图形编辑软件的开发,就会发现问题领域存在着圆、三角形这样一些具体概念,它们是不同的,但是它们又都属于形状这样一个概念,形状这个概念在问题领域是不存在的,它就是一个抽象概念,这样我们可以设计一个抽象类:形状类。(4) final:说明该类不能有子类,即任何其他类不能继承自(扩展)final类,故称为最终类。通常这种类的特点是用来完成某种标准功能的类。final与abstract不能同时修饰一个类。(5) strictfp:说明该类中的所有方法代码在处理浮点数时将遵守IEEE754标准。如果没有这个修饰符,则方法中所使用的浮点数操作方式可能与平台相关。【例3-1】下面程序定义了一个简单的类。/文件名:Student.javapublic class Student private String stuNumber;private String name; private String sex; public String getName() return name; public void printStuInfo() System.out.println(stuNumber+ +name+ +sex); 程序说明:1) 该类所在源文件的文件名为:Student.java 。2) 每个源代码文件只能有一个public类;如果文件中有一个public类,那么文件名必须与public类的名称一致。3) 一个源代码文件可以有多个非public类,不包含public类的源代码文件可以具有与该文件中任何类都不匹配的名称。下面介绍类体,类的定义是由类头和类体这两部分组成。类体中定义了类的具体内容,主要包括类的属性和功能,即类的成员变量和方法。3.2.2 成员变量类的成员分为成员变量和方法两种。类可以被看作是数据和操纵该数据的代码的集合,数据存放在成员变量中,操纵该数据的代码则存在于方法中。类的成员变量可以是简单变量,也可以是某个类的对象,还可以是数组和其它复杂数据结构。1、 成员变量的定义格式=;其中,同标识符,尽量做到“见名知义”;指变量的数据类型。和是不可省略的。对象成员的定义格式如下:=new ();其中,是另一个类的名字。一个类的成员变量可以是另一个类的对象,这反映了两个类之间的包含关系。2、 成员变量的修饰符成员变量的修饰符有访问控制修饰符和非访问控制修饰符两类。(1) 访问控制修饰符(4种)l public公共访问控制符。具有该修饰符的成员变量称为公共变量,如果该变量所在的类是公共类,则该成员变量可以被所有类所访问。l 默认的成员变量前如无访问控制符,称为默认访问控制,该成员变量具有包访问性,可以被同一个包中的其他类所访问。l private私有访问控制符。使用该修饰符说明的成员变量仅仅可被该类自身访问(即仅仅可在其所在类的内部被访问),任何其他类都不可访问,即使是该类的子类。l protected保护访问控制。使用该修饰符说明的成员变量可被该类自身、同包的其他类、其他包中该类的子类所访问。该修饰符与默认访问控制相比,它允许其他包中该类的子类所访问。表3.1 类成员的访问组合可见性public默认privateprotected从同一个类是是是是从同一个包中的任何类是是否是从同一个包中的子类是是否是从包外的子类是否否是,通过继承从包外的任何非子类的类是否否否(2) 非访问控制修饰符(4种)l staticstatic说明的变量称为静态变量,或者称为类变量。静态变量的特点是该变量是属于类的,而不是属于任何特定的对象(实例)。类的静态变量在内存中只有一个,Java虚拟机在加载类的过程中为静态变量分配内存,静态变量位于方法区,被类的所有实例共享,静态变量可以直接通过类名进行访问,也可以通过该类的对象(实例)来访问该类的静态变量(建议不要使用此方式)。l finalfinal说明的变量称为最终变量。最终变量一旦被一个显式值初始化之后,就不能再被重新赋值了(注意,用的是“显式值”而不是默认值),所以最终变量就是Java语言中的符号常量,符号常量通常用于定义一些固定的常数,因此通常也被说明为static的。例如,在java.lang包中的Math类中就定义了两个符号常量E和PI,对应于数学中的常量e和,符号常量通常全部使用大写字母。public class Math public static final double E = 2.7182818284590452354;public static final double PI = 3.14159265358979323846; l transienttransient 修饰的变量称为瞬态变量。transient告诉JVM,当试图序列化包含这个变量的对象时应跳过(忽略)它,当一个对象被串行化的时候,transient型变量的值不包括在串行化的表示中,然而非transient型的变量是被包括进去的。l volatilevolatile 修饰的变量称为易失变量。Volatile修饰的成员变量在每次被线程访问时,都强迫从主内存中重读该成员变量的值,而且,当成员变量发生变化时,强迫线程将变化值回写到主内存。而volatile关键字告诉JVM:对于这个成员变量不能保存它的私有拷贝,而应直接与共享成员变量交互。易失变量很少被使用。static 修饰的成员变量也常称为类变量,它不依赖于所在类的任何实例,其它成员变量都称为实例变量,实例变量一定是存在于该类的某个具体的实例(对象)中。【例3-2】类的成员变量使用示例。阅读下面的程序,分析程序的输出结果。/文件名:TestVarDemo.javaclass VarDemo public static int a;/静态变量 public final int x = 100; /最终变量 int b;/实例变量 private double d;/实例变量 public void printVar() int c = 9;/局部变量 a+; b+; c+; System.out.print(a= + a); System.out.print( b= + b); System.out.print( c= + c); System.out.print( d= + d); System.out.println( x= + x); public void setD(double y) d = y; public void twicePrint() printVar(); printVar(); public class TestVarDemo public static void main(String args) VarDemo v1 = new VarDemo(); VarDemo v2 = new VarDemo(); v1.setD(9.0); v1.twicePrint(); v2.setD(7.0); v2.twicePrint(); 程序运行输出结果如下:a=1 b=1 c=10 d=9.0 x=100a=2 b=2 c=10 d=9.0 x=100a=3 b=1 c=10 d=7.0 x=100a=4 b=2 c=10 d=7.0 x=100程序说明:该程序由两个类组成,其中TestVarDemo类包含main()方法。在VarDemo类中定义了4个成员变量,其中a为静态变量,x,b,d为实例变量(且x为最终变量)。在TestVarDemo类的mian()方法中,产生了VarDemo类的两个实例v1和v2,通过这两个实例调用twicePrint()方法。注意其中静态变量、实例变量、局部变量的使用。3.2.3 成员方法方法是类的另一个主要组成部分,是代码的集合,每个方法都属于特定的类,方法的声明必须位于类的声明之中。1、 方法的定义形式方法的定义形式通常包含方法说明和方法体两部分,具体形式如下: () throws 其中,方法说明中必须包含、和一对圆括号,可省略的有、和throws及后面的。方法名可以是任意合法的标识符。返回值类型是方法返回数据的类型,如果没有返回值,则返回值类型为void。方法体是由一对花括号括起来的若干条语句组成,其中包含说明语句和执行语句,也可以为空。方法的作用通常有如下两个:(1) 对该类体内的变量进行各种操作;(2) 与其它类的对象进行信息交流,作为类与外部进行交互通信的接口。2、 方法的修饰符方法的修饰符也分为访问控制修饰符和非访问控制修饰符两类,分别介绍如下。(1) 访问控制修饰符(4种)l public公开访问控制符。如果该方法所在的类是公共类,则该方法可以被所有类所访问。l 默认访问控制符方法前如无访问控制符,称为默认访问控制,该方法具有包访问性,可以被同一个包中的其他类所访问。l private私有访问控制修饰符。使用该修饰符说明的方法仅仅可被该类自身访问(即仅仅可在其所在类的内部被访问),任何其他类都不可访问,即使是该类的子类。l protected保护访问控制修饰符。使用该修饰符说明的方法可被该类自身、同包的其他类、其他包中该类的子类所访问。该修饰符与默认访问控制相比,它允许其他包中该类的子类所访问。这些访问控制修饰符对类的成员变量和方法的访问控制是一致的,参见表4-1。(2) 非访问控制符l abstractabstract 修饰的方法称为抽象方法,抽象方法是只有方法说明,没有具体实现的一种方法,换句话说,它没有方法体,如:public abstract void doIt();注意:抽象方法是以分号而不是花括号结尾的!包含有抽象方法的类必须声明为抽象(abstract)类。正如前面所介绍的, 抽象类体现了对某类事物的高度抽象,其中的抽象方法就是这类事物所共有的行为。l staticstatic修饰的方法称为静态方法,或类方法。静态方法和静态变量一样,不需要创建类的实例,可以直接通过类名来访问。静态方法不能访问非静态变量(实例变量)和非静态方法。l finalfinal修饰的方法称为最终方法,最终方法是不能被当前类的子类所覆盖(重新定义)的方法。这种做法可以防止子类对父类的方法的重定义,用以保证系统的安全性和正确性。l nativenative修饰的方法称为本地方法,当在方法中调用一些不是由Java语言写的代码(如C、C+、汇编语言等写成的代码)或者在方法中用Java语言直接操纵计算机硬件时要声明为native方法。 这种方法只在类体内给出说明,而方法体在类体外。使用本地方法可充分利用已有程序。l synchronized同步方法,synchronized关键字主要用于多线程程序中的协调和同步,详细内容在第7章“多线程”中介绍。3、 方法的参数和返回值定义方法时,参数列表可以包含零个或多个参数,参数之间以逗号“,”分隔,每个参数都由参数类型和参数名组成。如:public int add(int i, int j)return i+j;该方法有两个int型参数i和j。Java语言中,方法可以有返回值,也可以没有返回值。无返回值的方法在定义时返回值类,型为void,有返回值的方法的返回值类型为方法返回数据的类型,可以是简单类型,也可以是引用类型。方法的返回值是通过return来实现的,具体形式如下:return ;return后面的的类型与方法定义中返回值的类型必须相一致。这里的一致,对基本数据类型来说,可以是完全一致或者能自动转换到所定义的返回值类型;对于类类型,可以是完全一致或者类型为返回值类型的子类;如果返回类型为接口,则返回的数据类型必须实现了该接口。例如:class Demoint method1()boolean b;short s;int i;double d;return i; /对return s; /对,可自动转换return b; /错误return (int)d; /对, 经强制转换4、 方法的调用在Java语言中,静态方法可以直接使用类名加上成员运算符“.”被调用,如:d=Math.pow(x,y);实例方法必须通过方法所在类(或者所在类的子类)的实例(对象)加上成员运算符“.”被调用,例如,调用上例中的method1()方法必须按如下方式调用: Demo d = new Demo(); int i=d,method1();调用方法时必须为方法定义中的每个形参提供一个类型匹配的实参。在Java语言中,方法调用过程中,实参和形参之间采用的是“传值”的参数传递方式。当方法参数为基本数据类型时,参数传递是把实参的变量值传给形参,如果你在方法中修改了形参的值,方法调用结束后,实参的值没有改变。当方法的参数为引用类型时,实参的值为所引用的对象的地址值,方法调用时同样是把实参的值传递给形参,于是形参也具有与实参一样的地址值,即实参、形参指向了同一对象。如果在方法中改变了形参所引用的对象的内容, 那么实参所引用的对象的内容也发生了改变(他们引用的是同一对象)。【例3-3】分析Demo3.java程序的输出结果,并说明类中两个方法调用时参数的传递方式。/文件名Demo3.javapublic class Demo3 public static void main(String args) int array = 1, 2, 3, 4, 5 ;int a = 0, b = 0;changeA(a, b);changeB(array);System.out.println(a=+a+,b=+b);for (int i = 0; i array.length; i+)System.out.println(array+i+=+arrayi);static void changeA(int a, int b) a+;b+;static void changeB(int arr) for (int i = 0; i arr.length; i+)arri+;程序运行结果:a=0,b=0array0=2array1=3array2=4array3=5array4=6程序说明:类Demo3中除main()方法之外,还有2个方法changeA()和changeB()。changeA方法有两个int型参数,changeB方法的参数为数组类型(引用类型)。因此,调用changeA方法时,仅仅将实参的值传递给形参,实参和形参之间并无联系,而调用changeB方法时,同样是将实参的值传递给形参, 但由于实参和形参皆为引用类型,故传递之后,形参和实参引用的是同一个对象,对形参数组的改变,影响到了实参数组。【例3-4】分析ParameterTester.java程序的输出结果,注意方法调用参数的传递过程。/文件名:ParameterTester.javapublic class ParameterTester public static void main(String args) int a1 = 111;Num a2 = new Num(222);Num a3 = new Num(333);System.out.println(Before changing the values:);System.out.println(a1ta2ta3);System.out.println(a1 + t + a2 + t + a3);changeValues(a1, a2, a3);System.out.println(After changing the values:);System.out.println(a1ta2ta3);System.out.println(a1 + t + a2 + t + a3);public static void changeValues(int f1, Num f2, Num f3) f1 = 999;f2.setValue(888);f3 = new Num(777);class Num private int value;public Num(int update) value = update;public void setValue(int update) value = update;public String toString() return value + ;程序运行结果如下:Before changing the values:a1a2a3111222333After changing the values:a1a2a3111888333程序说明:这里有两个类ParameterTester 和Num。ParameterTester类中定义了一个方法:public static void changeValues(int f1, Num f2, Num f3),其参数分别为int、Num、Num类型,main()方法中构造了两个Num对象,并将它们作为实参,调用changeValues()方法。方法调用过程中的参数传递情形如图3-1所示。图3-1 方法调用中的参数传递过程5、 变长参数JDK1.5添加了一个新特性,可以创建带有数目可变的变元的方法,该特性称为var-arg,即变长参数。具有变长参数的方法,其声明规则如下:1、var-arg类型。当声明var-arg参数时,必须指定方法的这个参数可以接受的变元类型(可以是基本数据类型或引用类型)。2、基本语法。要使用var-arg参数声明方法,要求类型后面依次接省略号()、一个空格、以及用于保存接收到的参数的数组名称。3、其他参数。一个使用var-arg的方法中有其他参数是合法的。4、var-arg限制。var-arg必须是方法签名中的最后一个参数,且一个方法中只能有一个var-arg。例如:void method(int x) 方法method()的参数数目可以是零个、1个或者更多,x被隐式声明为一个int类型的数组。因此,在method()内,是通过使用正常的数组方式来访问x。【例3-5】可变长参数方法。/文件名:VarArgs.javapublic class VarArgs static void vaTest(int. x) System.out.println(Number of args: + x.length + Contents:); for (int v : x) System.out.println(v + ); public static void main(String args) vaTest(10); vaTest(1, 2, 3); vaTest(); 程序运行结果如下:Number of args:1 Contents:10 Number of args:3 Contents:1 2 3 Number of args:0 Contents:此程序有两个地方需要注意。首先,在vaTest()内,x是作为一个数组被操作的,因为x本来就是一个数组,语法只是告诉编译器将使用可变数目的参数, 且这些参数将存储到一个通过x引用的数组中。其次,调用vaTest()可带不同数目的参数,甚至可以不带参数。这些参数自动被置入一个数组并传递给x。在没有参数的情况下,数组的长度为零。一个方法既可以带正常参数,也可以带变长参数,但变长参数必须是该方法最后声明的参数。例如:下面的方法声明是合法的:int method(int a,int b,double c,int x) 3.2.4方法的重载Java语言支持方法重载(Overloaded),方法重载是Java 实现多态性的一种形式。方法重载是指在一个类中, 多个方法具有相同的方法名,但参数不同。同名的多个方法的参数必须在参数类型、参数个数和参数顺序上要不一致,以便作为选择某个方法的依据。通常只有功能相同的方法进行重载才有意义。例如,计算两个数之和的重载方法定义如下:int add(int i, int j) return i+j;float add(float i , float j) return i+j;double add(double i , double j) return i+j;这3个同名方法具有相同的功能,即求两数之和。3个重载的方法中,虽然参数个数相同,但参数的类型不同。重载方法必须满足以下条件:1. 方法名相同;2. 方法的参数类型、个数、顺序至少有一项不相同;3. 方法的返回类型可以不相同;4. 方法的修饰符可以不相同;5. 可以声明抛出新的或更广的异常。例如,要重载的方法:public void changeSize(int size, String name, float pattern) 如下列方法均为changeSize的合法重载:public void changeSize(int size, String name) public int changeSize(int size, float pattern) public void changeSize(float pattern, String name) throws IOException 重载方法的选择通常是在编译时进行。系统根据不同的参数类型、个数或顺序,寻找最佳匹配方法。匹配的原则如下:(1) 完全匹配为最佳方案。例如:int a=3,b=4;add(a,b);系统将选择两个参数为int型的方法 add(int i ,int j),因为这是完全匹配的方案。(2) 如果不能完全匹配时,则尽量选择类型转换代价最小的一种方案进行匹配。转换代价小的转换通常是指由低类型向高类型的转换。转换匹配时,应遵循以下规则:参数不能自动转换的重载方法不能参加匹配。比如,布尔型不能与其他类型转换。算术类型通常可以相互转换,选择转换代价最小的参加匹配。例如:char c1=a,c2=b;add(c1,c2);编译可将char转换为int,float, double型, 其中转换为int的转换代价最小,根据最小匹配原则,调用方法 add(int i, int j)。类类型做参数时,子类对象可转换为父类对象,子类层次最小的方法才会匹配。转换后出现两个以上的方法同时具有最小转换值时,编译出错。【例3-6】分析 TestAdder.java 程序的输出结果,并说明重载方法的选择规则。/文件名:TestAdder.javapublic class TestAdder public static void main(String args) int i1 = 3, i2 = 4;char c1 = a, c2 = b;float f1 = 3.0f, f2 = 4.0f;double d1 = 5.0d, d2 = 3.0d;System.out.println(add(i1, i2);System.out.println(add(c1, i2);System.out.println(add(c1, c2);System.out.println(add(i1, f2);System.out.println(add(f1, d2);System.out.println(add(d1, i2);public static int add(int x, int y) return x + y;public static float add(float x, float y) return x + y;public static double add(double x, double y) return x + y;程序运行结果如下:71011957.06.09.0程序说明:TestAdder类中有三个重载的方法, 方法名为add(),它们的参数构型不同。在调用重载的方法时,根据方法匹配原则选择相对应的方法。请根据输出结果,分析具体匹配情况。【例3-7】分析UseAnimals.java 程序的输出结果,注意重载方法的选择规则。class Animal class Horse extends Animal public class UseAnimals public void doStuff(Animal a) System.out.println(In the Animals version);public void doStuff(Horse a) System.out.println(In the Horse version);public static void main(String args) UseAnimals ua = new UseAnimals();Animal animalObj = new Animal();Horse horseObj = new Horse();ua.doStuff(animalObj);ua.doStuff(horseObj);animalObj = horseObj;ua.doStuff(animalObj);程序运行结果如下:In the Animals versionIn the Horse versionIn the Animals version程序说明:这里定义了三个类:Animal、Horse和UseAnimals,其中Animal是Horse的父类(关于继承,将在后面章节中详细讨论)。UseAnimals中有两个重载的方法doStuff(),参数分别为Animal、Horse类型。在UseAnimals的main()方法中,分别构造了Animal、Horse的实例:animalObj和horseObj,此时重载方法的匹配是根据引用变量的类型而不是引用的实际的对象的类型。重载方法的绑定是由编译器完成的,属静态绑定。3.2.5构造方法1、构造方法构造方法是一种特殊的方法,其功能是对创建的对象进行初始化。(1) 构造方法的特点:l 方法名同类名;l 无返回类型;l 一个类可以有多个构造方法(重载);l 构造方法可以有0个、1个或者多个参数;l 构造方法声明可以具有所有常规的访问修饰符,包括privte(只运行在该类自身内的代码才能实例化该类的对象)。l 构造方法是在创建对象时,系统自动调用为所创建的对象进行初始化的方法。(2) 构造方法的调用。构造方法和其他方法的一个重要的不同是:构造方法不能显式地被调用,而是用在运算符 new创建类的对象时,由系统自动调用。构造方法的参数传递和形实结合也在调用时同时完成。使用 new 运算符创建对象的形式如下: = new ();该语句完成如下两个任务(关于对象的创建过程在后面还会详细谈到):l 用new通知系统为所创建的对象在内存开辟一个单元;l 自动调用相应的构造方法使用给定的实参(如果有)为创建的对象进行初始化。(3) 构造方法的作用构造方法的主要作用是用来给创建的对象进行初始化。尽管Java语言中,对基本数据类型都指定了固定的默认值,但是还需要使所创建的对象处于正常合理的状态。 另外,常常需要创建不同属性值的对象,因此调用构造方法进行灵活初始化是十分必要的。构造方法的另一个作用就是在构造方法体内引入一些操作,除初始化功能以外,还具有更多的其他功能。(4) 默认构造方法在定义类时,如果不定义任何的构造方法时,系统会自动为该类提供一个默认的构造方法。该构造方法没有任何形参,也没有任何代码,使用它创建的对象使用的是默认值。要注意的是,一旦在类中定义了构造方法,系统将不再提供默认构造方法!2、对象的默认引用this当一个对象创建好后,Java虚拟机就会给它分配一个引用自身的指针:this。例如:public class A private int x; private int y; public void setX(int x) this.x = x; public void setY(int y) this.y = y; public int getX() return this.x; public int getY() return this.y; public class Demopublic static void main(String args) Demo a=new Demo(); a.setX(100); a.se

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论