第二章 面向对象Word文档格式.docx

上传人:b****8 文档编号:22233604 上传时间:2023-02-03 格式:DOCX 页数:16 大小:21.71KB
下载 相关 举报
第二章 面向对象Word文档格式.docx_第1页
第1页 / 共16页
第二章 面向对象Word文档格式.docx_第2页
第2页 / 共16页
第二章 面向对象Word文档格式.docx_第3页
第3页 / 共16页
第二章 面向对象Word文档格式.docx_第4页
第4页 / 共16页
第二章 面向对象Word文档格式.docx_第5页
第5页 / 共16页
点击查看更多>>
下载资源
资源描述

第二章 面向对象Word文档格式.docx

《第二章 面向对象Word文档格式.docx》由会员分享,可在线阅读,更多相关《第二章 面向对象Word文档格式.docx(16页珍藏版)》请在冰豆网上搜索。

第二章 面向对象Word文档格式.docx

//现在假设有一个GameLauncher类,当我们进入这张地图的时候,它会把这些图形对象(即GameShape的子类)都载入进来。

//换句话说,GameLauncher的工作就是实例化这些XxxxPiece类,然后让他们调用父类GameShape的displayShape()方法。

classGameLauncher{

//这个方法并不关心参数是GameShape的哪个子类。

publicstaticvoiddoShapes(GameShapeshape){

shape.displayShape();

publicstaticvoidmain(String[]str){

PlayerPieceplayer=newPlayerPiece();

TilePiecetile=newTilePiece();

doShapes(player);

//体现了多态性的好处,加入后面又加入了新的Piece,

doShapes(tile);

//比如WeaponPiece,在doShapes中依然不用关心它是什么。

}只是输出GameShape.displayShape(),因为doshapes()的参数是GameShape,无论你传入的是哪个子类。

2.2.1IS-A关系

在OO中,IS-A的概念基于类继承和接口实现。

在Java中,使用extends和implements来表达IS-A关系。

2.2.2HAS-A关系

HAS-A关系基于引用。

类A中的代码具有对类B实例的引用,则“类AHAS-A类B”。

2.3多态性

考试目标5.2给定一个场景,编写代码,演示多态性的使用。

而且,要判断何时需要强制转化,还要区分与对象引用强制转换相关的编译器错误和运行时错误。

多态性:

可以传递多个IS-A测试的任何Java对象都可以被看作是多态的。

访问对象的唯一方式是通过引用变量。

关于引用,要记住:

引用变量只能属于一种类型。

一经声明,类型就永远不能再改变(尽管它引用的对象可以改变类型)。

引用是一个变量,因此它可以重新赋予给其他对象(除非该引用被声明为final)。

引用变量的类型决定了可以在该变量引用的对象上调用的方法。

引用变量可以引用具有与所声明引用的类型相同的任何对象,或者——最重要的一点是——它可以引用所声明类型的任何子类型。

引用变量可以声明为类类型或接口类型。

如果将变量声明为接口类型,它就可以引用实现该接口的任何类的任何对象。

前面2.2我们说到“在OO中,IS-A的概念基于类继承和接口实现”,2.2中基于类继承的说的比较多,接口同样可以表达IS-A的关系,实现多态。

多态方法调用仅使用于实例方法。

实例方法可以用更一般的引用变量类型(超类或者接口)引用一个对象,但是在运行时,基于实际对象(而不是引用类型)动态选择,静态方法和变量不是的。

而在继承中子类可以使用超类的方法,也可以自己来实现这一方法,这就涉及到了重写(override)。

多态性只是用于实例方法,不适用于静态方法,静态变量和实例变量。

2.4重写和重载

考试目标1.5给定一个代码示例,判断一个方法是否正确地重写或重载了另一个方法,并判断该方法的合法返回值(包括协变式返回值)。

考试目标5.4给定一个场景,编写代码,声明和/或调用重写方法或重载方法。

编写代码,声明和/或调用超类、重写构造函数或重载构造函数。

2.4.1重写方法(override)

重写的规则:

变元列表必须与被重写的方法的变元列表完全匹配。

返回类型必须与超类中被重写方法中原先声明的返回类型或其子类型相同。

访问级别的限制性一定不能比被重写方法的更严格。

访问级别的限制性可以比被重写方法的弱。

仅当实例方法被子类继承时,它们才能被重写。

与实例的超类同包的子类可以重写未标识为private或final的任何超类方法。

不同包的子类只能重写那些标识为public或protected的非final方法。

重写方法可以抛出任何未检验(运行时)异常,无论被重写方法是否声明了该异常。

重写方法一定不能抛出比被重写方法声明的检验异常更新或更广的检验异常。

比如,一个声明FileNotFoundException异常的方法不能被一个声明SQLException、Exception或任何其他非运行时异常的方法重写,除非它是FileNotFoundException的一个子类。

重写方法能够抛出更少或更有限的异常。

不能重写表示为final的方法。

不能重写标识为static的方法。

调用被重写方法的超类版本:

super关键字

2.4.2重载方法(overload)

重载的规则:

重载方法必须改变变元列表。

重载方法可以改变返回类型。

重载方法可以改变访问修饰符。

重载方法可以声明新的或更广的检验异常。

方法能够在同一个类或者一个子类中被重载。

调用重载方法:

调用哪个重载方法,取决于变元的类型。

而不是其引用的类型,重载的var-arg是最后的选择。

classAnimal{}

classHorseextendsAnimal{}

classUseAnimals{

publicvoiddoStuff(Animala){

System.out.print("

IntheAnimalversion"

publicvoiddoStuff(Horseh){

IntheHorseversion"

UseAnimalsua=newUseAnimals();

Animalobj=newHorse();

ua.doStuff(obj);

//在这里引用类型决定了调用哪个重载方法

//结果显示"

重载方法和重写方法中的多态性

用一个例子来说明:

publicclassAnimal{

publicvoideat(){

GenericAnimalEatingGenerically"

publicclassHorseextendsAnimal{

Horseeatinghay"

publicvoideat(Strings){

Horseeating"

+s);

//测试方法

publicclassTest{

//这里是下表中“方法调用的代码”

不同调用方法的结果:

方法调用的代码结果解释

Animala=newAnimal();

a.eat();

GenericAnimalEatingGenerically

Horseh=newHorse();

h.eat();

Horseeatinghay

Animalah=newHorse();

ah.eat();

Horseeatinghay此处是多态性起作用——确定调用的是哪个eat()时,使用的是实际的对象类型(Horse),而不是引用类型(Animal)

注意和前一个例子的情况相区分,前面的情况是选择用UseAnimals对象的哪个方法,由变元类型(或说引用类型)来决定(编译时);

现在的情况是选择用哪个对象的eat()方法,Animal里如果没有这个方法会报编译时错误,但是就算有,运行时还是由实际的对象类型来决定。

Horsehe=newHorse();

he.eat("

Apples"

HorseeatingApples调用重载方法eat(Strings);

Animala2=newAnimal();

a2.eat("

treats"

编译时错误Animal没有带String变元的eat()方法

Animalah2=newHorse();

ah2.eat("

Carrots"

编译时错误原因同上

重载方法和重写方法的区别:

重载方法重写方法

变元

必须改变一定不能改变

返回类型可以改变除协变式返回外,不能改变

异常可以改变可以减小或消除。

一定不能抛出新的或更广的检验异常

访问级别可以改变一定不能执行更严格的限制(可以降低限制)

调用

引用类型决定了选择哪个重载版本(基于声明的变元类型)。

在编译时刻做出决定。

调用的实际方法仍然是一个在运行时发生的虚拟方法调用,但是编译器总是知道所调

用方法的签名。

因此在运行时,不仅是方法所在的类,而且变元匹配也已经明确了。

对象类型(也就是堆上实际的实例的类型)决定了调用哪个方法。

在运行时决定。

2.5引用变量强制转换

向下转型:

把引用变量转换为子类类型。

如Horseh=(Horse)newAnimal();

但如果调用父类里没有的方法,可以通过编译,但运行时会抛出java.lang.ClassCastException异常。

一定要先定义好Animalanimal=newHorse();

这样才能进行Horseh=(Horse)animal;

否则编译可以通过,但是会有ClassCaseException。

或者在之前进行一次Instanceof的测试。

向上转型:

把引用变量转换为超类类型。

如Animala=newHorse();

不需要转化,这是天然的IS-A关系。

2.6实现接口

在第一章的“声明接口”里说过,接口就是一种契约,任何实现这个接口的实现类都必须同意为该接口的所有方法提供实现。

合法的非抽象实现类必须执行以下操作:

为来自所声明接口的所有方法提供具体(非抽象)的实现。

遵守合法重写的所有规则。

在实现方法上声明非检验异常,而不是在接口方法上声明,也不是在接口方法上什么异常的子类。

保持接口方法的签名,并且保持相同的返回类型(或子类型),但是不必声明在接口方法声明中声明过的异常。

两条规则:

一个类可以实现多个接口。

接口自身可继承另一个接口,而且接口可以继承多个接口。

2.7合法的返回类型

2.7.1返回类型的声明

哪些内容声明为返回类型,这主要取决于是在重写方法、重载方法还是在声明新方法。

重载方法上的返回类型

没有什么限制,重载方法关键是变元要变化。

重写、返回类型和协变式返回

从Java5开始,只要新的返回类型是被重写的(超类)方法所声明的返回类型的子类型,就允许更改重写方法中的返回类型(这就是传说中的协变式返回)。

以前的Java版本要求重写的方法返回类型一定要与原来的一致。

2.7.2返回值

六条规则:

1.可以在具有对象引用返回类型的方法中返回null。

2.数组是完全合法的返回类型。

3.在具有基本返回类型的方法内,可以返回任何值或变量,只要它们能够隐式转换为所声明的返回类型。

publicintfoo(){

charc='

c'

;

returnc;

4.在具有基本返回类型的方法内,可以返回任何值或变量,只要它们能够显式地强制转换为所声明的返回类型。

floatf=32.5f;

return(int)f;

5.一定不能从返回类型为void的方法返回任何值。

6.在具有对象引用返回类型的方法内,可以返回任何对象类型,只要它们能够隐式地强制转换为所声明的返回类型。

换句话说,能通过IS-A测试的(也就是使用instanceof运算符测试为true)任何对象都能够从那个方法中返回。

//声明返回超类,实际返回子类

publicAnimalgetAnimal(){

returnnewHorse();

//AssumeHorseextendsAnimal

//声明返回超级父类Object,实际返回数组

publicObjectgetObject(){

int[]nums={1,2,3};

returnnums;

//Returnanintarray,whichisstillanobject

//声明返回接口,实际返回接口的一个实现类

publicinterfaceChewable{}

publicclassGumimplementsChewable{}

publicclassTestChewable{

//Methodwithaninterfacereturntype

publicChewablegetChewable(){

returnnewGum();

//Returninterfaceimplementer

2.8构造函数和实例化

构造函数基础:

构造函数是用来创建新对象的,每当我们“new”的时候,JVM就会按照你所指定的构造函数来创建一个对象实例。

每个类都至少有一个构造函数。

构造函数都没有返回类型(有就成方法了)。

不同的构造函数通过不同的变元来区分(或者为空)。

构造函数链:

当Horseh=newHorse();

的时候究竟发生了什么?

(HorseextendsAnimal,AnimalextendsObject)

调用Horse构造函数。

通过一个对super()的(隐式)调用,每个构造函数都会调用其超类的构造函数,除非构造函数调用同一个类的重载构造函数。

调用Animal构造函数(Animal是Horse的超类)。

调用Object构造函数(Object是所有类的最终超类,因此,Animal类扩展Object)。

这时,我们处于栈的顶部。

为Object实例变量赋予显式值。

Object构造函数完成。

为Animal实例变量赋予显式值。

Animal构造函数完成。

为Horse实例变量赋予显式值。

Horse构造函数完成。

构造函数规则:

构造函数能使用任何访问修饰符。

构造函数名称必须与类名匹配。

构造函数一定不能有返回类型。

让方法具有与类相同的名称是合法的,但是建议不要这样做。

如果不在类代码中键入构造函数,编译器将自动生成默认构造函数。

默认构造函数总是无变元构造函数。

如果在类代码中已经有带变元的构造函数存在,而没有无变元的构造函数,那在编译时不会自动生成无变元构造函数。

每个构造函数都必须将对重载构造函数[this()]或超类构造函数[super()]的调用作为第一条语句。

如果没有,编译器会自动插入super();

只限于无参的Super(),或者this(),编译器不会加有参的。

如果第一个构造函数没有该两个方法(super或this的有参无参形式都可以,只要有一个就OK),编译器就要自动加上super(),去父类找无参构造函数(父类没有就编译错误),如果自己加上super(arg),则父类中需要有相应的构造函数。

this()同理。

除非在超类构造函数运行之后,否则不能调用实例方法或访问实例变量。

只能将静态变量和方法作为调用super()或this()的一部分进行访问。

例如:

super(Animal.NAME)

抽象类具有构造函数,这些构造函数总是在实例化具体子类时才调用。

接口没有构造函数。

接口不是对象继承树的一部分。

调用构造函数的唯一方法是从另一个构造函数内部进行调用。

关于Java私有构造函数,一般加上一个Public的静态方法来对该私有构造函数进行调用,典型的就是单例模式。

2.8.1判断是否会创建默认构造函数

如何证明会创建默认构造函数?

只有在类代码中没有构造函数的,才会生成默认构造函数。

如何知道它就是默认构造函数?

默认构造函数的特征:

具有与类相同的访问修饰符。

没有任何变元。

包含super();

publicclassFoo{

publicFoo(){

super();

如果超类构造函数有变元会怎样?

那在new的时候必须带参newAnimal(“monkey”);

2.8.2重载构造函数

重载构造的时候要注意:

this()或super()一定要在第一行。

不要写如下的死循环代码:

classA{

A(){

this("

foo"

A(Strings){

this();

2.9静态成员

2.9.1静态变量和静态方法

当方法永远与实例完全无关时,我们就将它声明为static。

访问静态方法和变量:

用“类名.静态变量/方法”来访问。

静态方法不能访问实例(非静态)变量。

静态方法不能访问非静态方法。

静态方法能够访问静态方法和静态变量。

static方法的重定义问题:

我们都知道静态方法是不能被重写的,但是可以被重定义。

这个问题很迷糊人,从代码上来看,重写和重定义没有区别。

那么重定义(redefine)和重写(override)有啥区别呢?

重定义操作的是静态方法,静态方法跟类有关;

重写操作的是非静态方法,跟实例对象有关。

看下下面的代码:

publicclassTenorextendsSinger{

publicstaticStringsing(){

return"

fa"

publicStringsing2(){

fa2"

publicstaticvoidmain(String[]args){

Tenort=newTenor();

Singers=newTenor();

System.out.println(t.sing()+"

"

+s.sing()+"

+t.sing2()+"

+s.sing2());

classSinger{

la"

la2"

//运行结果是:

falafa2fa2

2.10耦合与内聚

Java的OO设计目标:

紧封装、松耦合、高内聚。

以实现易于创建、易于维护、易于增强的目标。

耦合(Coupling):

耦合是指一个类了解另一个类的程度。

如果类A对类B的了解很少,仅限于类B通通过其接口公开的信息,类A并不知道B的更多具体实现,那就称类A和类B是松耦合的。

我们说类B做到了紧封装。

内聚(Cohesion):

内聚用于表示一个类具有单一的、明确目标的程度。

一个类的目标越明确,其内聚性越高。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 解决方案 > 学习计划

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1