类、继承与多态方案_第1页
类、继承与多态方案_第2页
类、继承与多态方案_第3页
类、继承与多态方案_第4页
类、继承与多态方案_第5页
已阅读5页,还剩71页未读 继续免费阅读

下载本文档

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

文档简介

2023/12/6

在面向对象程序设计中,继承是最为显著的一个特征。继承机制模仿了现实中IS-A关系(层次关系).继承就是以原有某个类为基础生成新的类,增加一些新的成员变量和方法,使新的类功能更趋完善的一种高效编程机制。新生成的类被称为子类(或派生类),原有的这个类被称为子类的父类(基类,也称为超类).通常把某一组相似对象的基础的、共有的、通用的属性设计成父类,再通过继承生成新的子类,代码重用性得到了提高.

例如,水果和梨,动物和乌龟,食品和罐头,交通工具和轿车等注意,Java顶层父类是Object.3.2继承2023/12/6类的定义语法是:[修饰符]class类名[extends父类][implements接口名]{

类成员变量定义类方法定义}类的修饰符用来说明类的特殊性质。分为三种:访问控制符:public或无抽象类说明符:abstract最终类说明符:final接口名跟在implements关键字后面,用来说明当前类中实现了哪个接口定义的功能和方法。接口是Java语言用来实现多重继承的一种特殊机制。3.2.1类的定义

2023/12/6如定义一个Person类和子类StudentclassPerson{ Stringname; intage;publicvoideat(){}publicvoidsleep(){}}classStudentextendsPerson{privateStringshoolNO;privatevoiddoHomework();}2023/12/63.2.2成员变量和方法成员变量用来描述类创建的对象的属性,而成员方法则刻画了对象特有的行为。

Java中的成员变量根据不同的修饰符有3种类型:

-实例变量,随对象被访问

-类变量,随类被访问

-常量注意,Java成员变量随对象被创建而产生,对于全局静态变量,则与类属于同等层次概念。2023/12/6举例说明,见【例3.3】2023/12/6就对象的方法而言,可分为构造方法和普通方法。而构造方法是在类创建对象时由系统自动调用。与成员变量一样,方法也有实例方法和类方法之分。

-实例方法,随对象而调用

-类方法,随类而调用 方法的定义语法是:

[修饰符][返回值]<方法名>([参数列表]){

方法体

}

其中,修饰符共4种情况:

public,protected,private或不提供.2023/12/6要使用对象,必须先创建对象。Java中的对象是通过构造方法来创建的。构造方法有以下特性:①构造方法的方法名与类名相同。②构造方法没有返回值,当然也没有返回类型。③构造方法的主要作用是完成对类对象的初始化工作。④构造方法一般不能由编程人员显式地直接调用。⑤在创建一个类的新对象的同时,系统会自动调用该类的构造方法,为新对象初始化。⑥一个类可以有多个构造方法,可以有0个、1个或多个参数。

⑦构造方法总是和new运算符一起被调用。

3.2.3对象的构造和初始化过程

*!*2023/12/6当没有为类提供一个构造方法时,则编译器会自动加入一个不带参数的构造方法,称为默认构造方法。例如,

classPerson{

Person(){super();} }classStudentextendsPerson{

Student(){super();} //系统自动行为

publicstaticvoidmain(String[]args){newStudent(); //(1)创建子类对象

}}问题,上述语句(1)会不会创建父类对象?要注意区分构造方法和new操作的不同作用!classObject{

Object(){}}2023/12/6

构造方法的执行过程当创建一个对象时,对象的各个变量根据其类型被设置为相应的默认初始值,然后调用构造方法。下面是执行步骤:①调用父类的构造方法,这个过程会重复下去.②按声明顺序对成员变量进行初始化.③执行构造方法中的各语句.

构造器调用的顺序保证所有的父类构造方法都得到调用,保证其基类的成员得到正确的初始化并执行相关语句,然后对本对象的域(变量)进行初始化。构造方法的作用就是初始化.

下面举例说明.【例3.1】构造方法和对象初始化2023/12/6程序运行结果是:?下面,将对继承情况下父-子类之间的初始化进行分析.2023/12/6publicclassaparent{intheight=170;intweight;aparent(){height=160;weight=130;}}classaboyextendsaparent{protectedintcomhei=120;aboy(){weight=(int)(120f/height*weight);}}当创建一个类型为aboy的对象时,其创建和初始化的步骤如下表所示。例如,创建一个子类对象时2023/12/62023/12/6Java的类加载过程和对象初始化顺序,按照如下步骤进行:首先,当类被加载时执行静态变量初始化、静态初始化块.

然后,非静态变量初始化、非静态初始化块被执行.

最后,构造方法被执行。从父类的构造方法递归执行.

即,依次执行:

(静态变量、静态初始化块)>(变量、初始化块)>构造方法

2023/12/6注意,(1)在继承情况下,并不是父类完全初始化完毕后才进行子类的初始化!

(2)静态变量和静态初始化块是依照他们在类中的定义顺序进行初始化的。同样,变量和初始化块也遵循这个规律.

下面举例说明.【例3.2】类加载和对象初始化2023/12/63.2.4上转型对象梨子-水果,乌龟-动物,学生-人等概念具有从属关系,前者是后者的一种。例如,对于Person类和子类Student;当创建Student子类对象时,并把这个对象的引用放到类Person声明的对象中,即:

Personp=newStudent();或者

Personp;Students=newStudent();p=s;则称对象p是子类对象s的上转型对象.

类似地,也可以将创建的间接子类Graduate对象放到Person对象引用中。对象的上转型对象的实体是子类负责创建的,只是失去了原对象的一些属性和方法,其特点如图所示:2023/12/6原对象和上转型对象之间关系上转型对象的特点是:a.上转型对象不能操作子类新增的变量和方法.b.上转型对象可以操作子类继承或隐藏的成员变量,也可以使用子类继承或重写的方法.c.可将上转型对象再转换到一个子类对象,这时该子类对象又具备了子类的所有属性和功能.【例3.3】上转型对象2023/12/6上转型对象应用举例.问题:下列语句正确吗?Students=newPerson();上转型对象是父类对象吗?2023/12/63.2.5this和superthis,super分别指代当前对象和父类对象,通常出现在构造方法中。例如,classPerson{Stringname=“zhangshan”;publicPerson(){//super(name); //显式调用父类带参的构造方法

this(name); //调用重载的构造方法,Person(name)?}publicPerson(Stringname){=name;//为同名的成员变量赋值

}…}2023/12/6注意以下几点:1)在一个构造方法中使用了this或super语句,那么它必须作为构造方法的第一条语句.2)只能在构造方法(非其他实例方法)中用this语句来调用类的其他构造方法,且不能通过方法名来直接调用构造方法.如果调用父类构造方法也只能用super而不是父类名.3)this,super对象不能出现在静态方法中.publicstaticvoidmain(String[]args){this.play();//×}2023/12/63.3多态多态是指一个名称具有多种功能。即同名但拥有不同的方法体。分重载(overloading)和覆盖(overriding)两种。重载,又称编译时多态,在一个类中通过不同参数个数或不同类型参数来体现。如:

sum(bytea,byteb);sum(inta,intb);sum(doublea,doubleb);…2023/12/6构造方法的重载构造方法重载的目的是以不同的方法对类进行初始化。例如,为类Person编写构造方法:publicPerson(){}publicPerson(Stringname){}publicPerson(intID){}publicPerson(Stringname,StringID){}…

为Student子类编写构造方法:publicStudent(){}publicStudent(Stringname,Stringno){}…如果构造方法有返回值类型(包括void)修饰,那它不再是构造方法而成了普通方法,一般不提倡这么做。构造方法可以被继承吗?可以用static修饰吗?2023/12/6方法覆盖,又称运行时多态,只有在运行时(非编译时)根据对象的类型来决定是调用父类的同名方法还是子类重写的方法。例如,狗叫,猫叫,老虎叫,狮子叫声都不一样!

方法覆盖条件:

1)方法名相同;2)方法的参数列表完全相同;3)返回值必须相同;举例说明如下:方法的访问修饰符有影响吗?对照想一想,方法重载的条件呢?【例3.4】方法重载2023/12/6【例3.5】方法覆盖2023/12/6下面修改一下上述main方法中的几个语句,如上图所示,则运行结果呢?Animala=newAnimal();Animalc=newCat();Animald=newDog();a.sound();c.sound();d.sound();2023/12/6关于方法覆盖(重写)Java运行时系统根据调用该方法的对象,来决定调用哪个方法。对于子类的一个对象,如果子类重写了父类的方法,则运行时系统调用子类的方法;如果子类继承了父类的方法(未重写),则运行时系统调用父类的方法。private方法可以被覆盖吗?final方法可以被覆盖吗?注意,方法覆盖还存在访问权限的问题。2023/12/6变量覆盖或称变量隐藏,只要变量名相同就实现了隐藏。其修饰符和类型可以不同。例如,问题,这样赋值可以吗?woman.aveHight=170.5f;2023/12/63.4修饰符3.4.1

访问修饰符在定义类,成员变量,方法时,可以在其前面加上修饰符。有访问修饰符和非访问修饰符之分。访问修饰符是一组限定类,成员变量或方法能在多大范围内被访问的修饰符。类的访问修饰符只有两种,而成员变量和方法可以拥有4种不同的修饰符.如图所示:2023/12/6

类的访问修饰符

(2种)

public(公共访问)缺省包访问成员变量与方法的访问修饰符

(4种)

符号publicprotected无private

含义公共访问保护访问缺省包访问私有访问

2023/12/6(1)公共访问修饰符-public用来修饰类时,即公有类,表明它可以被所有的其他类所访问和引用.

这里访问和引用是指这个类作为整体是可见和可使用的,可以创建这个类的对象、访问这个类内部可见的成员变量和调用它的可见的方法。一个类作为整体对程序的其他部分可见,并不能代表类内的所有属性和方法也同时对程序的其他部分可见,前者只是后者的必要条件,类的属性和方法能否为所有其他类所访问,还要看这些属性和方法自己的访问修饰符。

2023/12/6(2)缺省访问修饰符-default

假如一个类没有访问修饰符,说明该类只能被同一个包中的类访问。这种缺省的访问修饰规定该类只能被同一个包中的类访问和引用,而不可以被其他包中的类使用,这就是包访问特性。

类的默认访问修饰符是default.

通过声明类的访问修饰符可以使整个程序结构清晰、严谨,减少可能产生类间干扰和错误。2023/12/6(3)保护访问控制符-protected用protected修饰的成员变量或方法可以被三种类所引用:该类自身;

与它在同一个包中的其他类;

在其他包中的该类的子类;

使用protected修饰符的主要作用是允许其他包中的它的子类来访问父类的特定属性。2023/12/6(4)私有访问控制符-private用private修饰的成员变量或方法只能被该类自身所访问和修改,而不能被任何其他类,包括该类的子类,来获取和引用。

在下面的情况下可以选择私有方法:

1)与类的使用者无关的那些方法。

2)如果类的实现改变了,不容易维护的那些方法如果构造方法被声明为private型的,会发生什么情况呢?2023/12/6成员变量和方法的访问修饰符可以有4个,其访问特性如下表所示:注意,成员变量和方法默认修饰符是default,即具有包访问权限.下面举例说明.【例3.6】访问修饰符举例2023/12/6在同一个包中的访问情况程序运行结果?2023/12/6在不同包中的访问情况程序运行结果?2023/12/63.4.2非访问修饰符1.类的非访问修饰符可以使用abstract,final修饰一个类,当为内部类时,还可以用static予以修饰。2.成员变量和方法的非访问修饰符可以使用static,final来修饰变量,使用static,final和abstract修饰方法,具体如下表所示:

*2023/12/6static变量和static方法用static修饰的成员变量,也称类变量;相反,则为实例变量.

用static修饰的成员方法,也称类方法;相反,则为实例方法.它们是属于整个类的,使用类名作前缀进行访问,它们随类的装载而初始化,为该类的所有对象所共享.注意,在类方法中可以操纵类变量和调用其他类方法,但不能操纵实例变量和调用实例方法(当然可以通过对象名来操纵).同样地,在类方法中不能出现this,super的引用.static的作用体现在不必创建对象的前提下就可以调用那个方法.还有static常量!问题,实例变量和实例方法会共享吗?【例3.7】非访问修饰符2023/12/6abstract类和abstract方法当一个类被声明为abstract时,这个类被称为是抽象类。所谓抽象类就是没有具体实例对象的类。例如,

abstractclass{}

如果将抽象类中的方法声明为abstract,这个方法即为抽象方法。抽象方法只含有一个声明,没有方法体。例如,

abstractvoiddisplay();

abstract类不允许创建对象且必须被继承,抽象类允许方法拥有方法体,但抽象方法必须存在于抽象类中。例如,

abstractclassabsClass{abstractvoiddisplay();voidprintX(){System.out.println(“Thisisanabstractclass”);}}2023/12/6抽象类的例子1)用户类(管理员,VIP用户,普通用户,…)2)形状类(点,线,圆,…)3)工具类(轿车,汽车,火车,…)4)...

【例3.8】非访问修饰符2

2023/12/6非访问修饰符举例程序运行结果?2023/12/6final类,final方法,final变量如果一个类被声明为final,则称final类,意味着它不能被继承。若用来修饰一个方法,则称final方法,该方法不允许被覆盖!

若用来修饰一个变量,则称final变量,这种变量只能被赋值一次。例如,

finalclassfinalClass{finaldoublePI=3.1415926;...

}问题,一个类能不能既被声明为abstract又被声明为final型?【例3.9】非访问修饰符3

2023/12/63.5内部类和匿名内部类定义在一个类的类体中的类被称为内部类。内部类有静态内部类和匿名内部类等形式,内部类具有以下特点:

内部类相当于外围类的成员,可以访问外围类的成员!2023/12/6内部类更多的反映的是类/对象之间的关系,一般用来生成事件适配器,用于事件处理。其定义有三种方式:

(1)是其它类的成员; //(2)在一个语句块的内部定义; //(3)在表达式内部匿名定义; //匿名内部类注意,a.若内部类被声明为static,就变成了顶层类,不能再使用局部变量.b.若想在内部类中声明任何static成员,则该内部类必须声明为static.【例3.10】内部类及其创建1

2023/12/6内部类应用举例1在外围类方法中创建内部类对象.程序运行结果?2023/12/6内部类应用举例2由外围类对象创建内部类对象.程序运行结果?当一个类继承了内部类时,内部类的构造方法不会自动调用!如何完成子类对象创建?Java提供了enclosingClassReference.super();来说明内部类与外部类对象引用之间的关联.2023/12/6静态内部类

publicclassoutClass{//…publicstaticclassstatInnerClass(){…//不可以访问外部类的实例变量

}classinnerClass{

…//可以访问外部类的实例变量

}}

此时,与其他静态变量、静态方法一样与对象无关,静态内部类只可以访问外围类的静态变量和静态方法,而不能直接引用定义在外围类中的实例变量或者方法,但可以通过对象的引用来使用它们。2023/12/6匿名内部类(anonymousinner-class)

匿名类就是没有名字的内部类,将把继承类与实例化子类对象在一个表达式里完成。其定义语法如下:

new类或接口(){//类的主体}

这种形式的new语句声明一个匿名内部类,它对一个给定的类进行扩展,或者实现一个给定的接口;它还创建匿名内部类的一个对象,并把这个对象作为new语句的返回值.

匿名内部类有两种实现方式:第1种,继承一个类,重写其方法;

第2种,实现一个接口,实现其中的方法.

下面举例说明之.2023/12/6注意匿名内部类的定义方式.程序运行结果?2023/12/63.6接口接口类似抽象类,只包含常量和方法的声明,而没有方法的实现。接口是由常量和抽象方法组成的特殊类,接口的定义包括接口声明和接口体。接口声明的格式如下:

[public]interfaceinterfaceName[extendslistOfSuperInterface]{…}

extends子句与类声明的extends子句基本相同,不同的是一个接口可有多个父接口,用逗号隔开,而一个类只能有一个父类。例如,

interfacepower{booleanonoff=false;voidon();voidoff();}

interfacewater_powerextendspower{floatwaterline=139f;intadjust_waterline(floatnewvalue);}接口中方法和变量各有什么特点?2023/12/6接口的实现在类的声明中用implements子句来表示一个类实现某个接口.classpowerManagerimplementspower{…voidon(){…}voidoff(){…}}一个类可以实现多个接口,在implements子句中用逗号分开.classpowerManagerimplementswater_power,fire_power{…voidon(){…}voidoff(){…}intadajust_waterline(){…}…}一个类实现某个接口,就必须实现接口中声明的所有方法,包括继承的接口.interfacefire_powerextendspower{floatadjust_temperature(floatnewvalue);}2023/12/6接口的用处1)通过接口实现不相关类的相同行为,而无需考虑这些类之间的关系。2)通过接口指明多个类需要实现的方法。3)通过接口了解对象的交互界面,而无需了解对象所对应的类。与抽象类的比较抽象类必须被继承,接口必须被实现抽象类允许方法的实现,而接口只有方法的声明没有方法体类只有单根继承,而接口可以多重继承抽象类,接口可用作变量的类型。抽象类的维护比接口要简单些抽象类可以赋予方法默认行为.如果接口变动了?2023/12/6接口类型的使用作为一种引用类型来使用任何实现该接口的类的实例都可以存储在该接口类型的变量中通过这些变量可以访问类所实现的接口中的方法下面举例说明.【例3.11】接口应用

2023/12/6程序运行结果呢?2023/12/6接口举例2023/12/6接口举例2023/12/6一个类实现多个接口2023/12/61.包及其作用包是一组相关类和接口的集合,通常称为“类库”,是一个较为松散的集合。包提供了命名空间管理和访问保护,将实现某方面功能的一组类和接口组织在一起,形成包。Java语言提供了一些系统级基本包,例如:3.7程序包2023/12/62.自定义包创建一个包的方法非常简单,只要将一个包的声明放在Java源程序的第一个语句即可。其语法是:

packagebook;

package语句的作用范围是整个源文件,而且同一个package声明可以放到多个源文件中,所有定义在这些源文件中的类和接口都属于这个包的成员。这些源程序经编译后产生.class文件,它们属于同一个包,包名是book,这就是包book的作用.在Java中有“无名包”(default)和“有名包”之分,前者是系统的默认对待,即没有package语句。因为没有名字,所以它不能被其他包所引用,因此经常要求创建“有名包”.

2023/12/63.编译和生成包带有包名的源程序,在编译时需带上参数-d.,及生成对应包名的类文件。例如,2023/12/6当编译器在编译一个java源文件时,会自动在以下位置查找所要用到的类文件:当前目录系统环境变量classpath指定的目录,称之为类路径JDK的运行库rt.jar,该库在JDK安装目录的jre\lib子目录中也可以在编译时指定类文件的搜索路径,例如:E:\javapractice>javac–classpath.;D:\test.java2023/12/64.运行带包名的类要运行带有包名的类,有下面两种方法:

1)将当前目录设置为包名的上一级目录,然后以小数点作为连接符将包名作为Java类的前缀名,再运行。例如,

packagecom.mypackage;

将当前目录设置为com的上一级目录,然后输入命令:>Javacom.mypackage.类名

2)使用带参数的java命令运行之。例如,

>java-classpath.;com.mypackage类名当需要引入其他包中的类时,使用import语句即可。例如,

importcom.mypackage.*;//引入这个包中所有类 2023/12/65.嵌套包,是指一个包嵌套在另一个包中。例如,包java.util.Date嵌套在包java.util中。

注意,在引入包时,不会自动引入嵌套包中的类和接口!6.包中类的可见性一个包中的public类或public接口可以被包外代码访问;非public的类型则以包作为作用域,在同一包内可以访问,对外是隐藏的.2023/12/6选择题-1(1)程序test.java的代码如下,其中正确的是()classA{}classBextendsA{}publicclasstest{publicstaticvoidmain(String[]args){Aa=newA();Bb=(B)a;}A.通过编译并运行B.编译时出错

C.编译通过,但运行时出错

D.编译器报告找不到test.java练习题2023/12/6选择题-2(2)关于类demo的描述正确的是()publicclassDemoextendsBase{privateintcount;publicDemo(){System.out.println(“ADemoobjecthasbeencreated”);}protectedvoidaddOne(){count++;}A.当创建一个Demo类的对象时,count的值是0B.当创建一个Demo类的对象时,count的值不确定

C.Base类型的对象中可包含改变count值的方法

D.Demo的子类对象可以访问count2023/12/6(3)写出下列程序的运行结果正确答案:?2023/12/6(4)阅读下面的程序,其中正确的是()

classperson{Stringname;StringnickName;publicperson(Stringa,Stringb){name=a;nickName=b;

}publicStringtoString(){

returnname+"nickName="+nickName;

}}

2023/12/6publicclassemployeeextendsperson{

Stringrank;

publicemployee(Stringa,Stringb,Stringc){

super(a,b);

rank=c;}publicStringtoString(){

returnname+"nickName="+nickName+"rank="+rank;}

2023/12/6publicpublicstaticvoidmain(String[]args){personone=newperson("Wang","Zhang");persontwo=newemployee("Bob","Tom","manager");employeethree=newemployee("Jack","David","CEO");System.out.println("oneis"+one.toString());System.out.println("twois"+two.toString());System.out.println("threeis"+three.toString());}}

2023/12/6

A.编译时会出现错

温馨提示

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

评论

0/150

提交评论