面向对象--继承,多态,封装

面向对象程序设计(Object-Oriented Programming—OOP)是目前占主流地位的编程技术,其变成思想就是将事物抽象成类和对象,由于对象具有自己的状态和行为,程序通过对象对消息的反映来完成特定的任务。

Java支持面向对象理论中的3种重要技术:封装(encapsulation),继承(inheritance)和多态(polymorphism)。

继承的概念

继承机制模仿了现实中IS-A关系(层次关系),如生物学界用界,门,纲,目,科,属,种来对生物进行分类,每一种分类都用若干特征来刻划,在每一个层次中,同一分类的生物具有共同的特征。

类继承,通过必要的说明能够实现某各类无需重新定义就拥有另一个类的某些属性和方法,一个新的类能继承原有类的基本特征。原有的类称为父类、超类(superclass)或基类,新派生的类称为原有类的子类或派生类。

在子类中包含父类的属性和方法,并可以增加新的属性和方法,这种子类继承父类的方式也称为类的派生(deriving)。

类的继承允许多层的继承关系,也就是子类也可以有它自己的子类,在下一层的继承关系中,原先的子类就变成了父类。

父类的基本特征可被所有子类所共享。注意:Java仅支持单一派生,即每一个子类的直接父类最多仅能有一个。(C++,VC++等支持多重继承)Java中通过接口实现多重继承的功能.

继承可提高代码的重用性,简化软件开发,提高了开发效率.

public class SonClass extends ParentClass{

      类体定义;

}

SonClass是正在定义的新类,也是子类;ParentClass是一个已经存在的类,是父类;这两个类名通过关键字extends联系在一起,形成继承关系。

类SonClass继承了类ParentClass;换句话说,类ParentClass派生了类SonClass。

继承能够使子类拥有(继承)父类的非私有属性和方法(即可以继承public、protected和默认访问属性的成员),而不需要在子类定义时重新定义父类中的这些同名属性和方法。

当我们改动父类中的一个属性和方法时,子类中也会同样得到修改。

成员的继承

◎属性的继承

子类继承了父类属性,表示子类在被创建时另开辟新的空间来存储从父类继承而来的属性,其初始值应该是父类中该属性的初值。从这以后,父类属性与子类属性分别独立存放,互不干扰。

◎方法的继承

方法的继承和属性的继承相同,子类不需要重新定义就可以拥有父类的非私有方法。

◎构造函数的继承

1、子类只继承父类的默认(缺省)构造函数,即无形参构造函数。如果父类没有默认构造函数,那子类不能从父类继承到任何构造函数。

2、子类从父类处继承来的父类默认构造函数,不能成为子类的默认构造函数。

3、在创建对象时,先调用父类默认构造函数对对象进行初始化,然后调用子类自身自己定义的构造函数。

4、如果子类想调用父类的非默认构造函数,则必须使用super来实现。

5、子类必须调用父类的构造函数。可以通过系统自动调用父类的默认构造函数,如果父类没有默认构造函数时,子类构造函数必须通过super调用父类的构造函数。

最终类和最终方法

我们可以从一个已有的类来派生出一个新类,但有时我们想阻止一个类被继承,不允许其派生新类,这时,我们就可以把类声明为final类——最终类。

语法格式:

[public] final class ClassName{

        类体定义;

}

最终类不能有子类。

我们也可以将一个方法声明为final——最终方法。最终方法表示该方法已经固定下来,在当前类和子类中都一样,所以不能被覆盖(但可以重载)。最终方法并非一定是在最终类中。

继承时候类的执行顺序是:
父类中被static关键字定义的部分是按所定义的顺序而最先被初始化的;
父类构造函数(按调用顺序);

子类中被static关键字定义的部分是按所定义的顺序而最先被初始化的;
子类构造函数(按调用顺序);
其他则按方法的调用顺序.

◎抽象类

某些类在现实世界中是不能直接找到其对应的实例的,例如车这个类,我们不能找到其对应的实例,只能找到他的子类,如汽车,自行车,火车等类的实例,我们把这种不能被实例化的类称为抽象类(abstract)。抽象类只是描述了其子类所共有的属性和方法。

语法格式:

[public] abstract class ClassName{

        类体定义;

}

抽象类不能有实例,不可以实例化(不能用new为抽象类对象名分配空间)。

以abstract修饰的方法称为抽象方法,抽象方法只有方法头,没有方法体,抽象方法仅仅定义了方法的名称,没有给出实现,其主要用于设计类所具有的能力,但并不给出实现这种能力的具体方法。

语法格式:

[访问控制符] abstract 返回值类型 methodname(参数列表) ;

抽象方法仅描述了方法的名字,返回值和参数,具体实现没有说明。

抽象方法定义完成后,需要在子类中具体实现抽象方法(覆盖)。例如:车这个抽象类具有行驶这个抽象方法(不同的车有不同的形式方式,在车类中,我们只能说车具有行使的能力,但怎样行使,还需要看不同的车),在汽车子类中,汽车的行驶,由发动机驱动行驶,在这就具体实现了行驶能力;在自行车类中,自行车的行驶,由人力驱动,在这又用另一种方式实现了行驶。

所有的抽象方法都必须放置在抽象类中。但抽象类可以包含抽象方法和一般方法,也可以不包含抽象方法。

抽象类中非抽象方法的继承与普通继承一样,子类继承父类中非private成员。而对于抽象方法的继承只能通过覆盖的形式来实现(不能通过重载),也就是在子类中定义一个与抽象方法有相同方法头,并有方法体的方法。我们称这一过程为“实现”,即子类实现了抽象类中的方法。

在派生体系中,父类中的抽象方法如果在子类中没有全部实现,则子类仍必须声明为抽象类。只有子类将父类的所有抽象方法全部实现了,才可以声明为非抽象类。

抽象类对象名虽然不能够分配空间,但其可以被非抽象的子类对象赋值。

abstractClass a=noabstractobj;//abstractClass为抽象父类,noabstractobj为非抽象子类的对象名.

对象在继承关系中的改变

对象的赋值是地址标识的传递,即两个对象名共同使用同一段内存地址。在Java中,对父类与子类对象之间的赋值作了如下规定:

1、子类对象名可以赋值给父类对象名;但父类对象名不可以赋值给子类对象名。

即:父类对象名=子类对象名;

2、如果一个父类对象名已经被子类对象名所赋值,那可以将父类对象名经强制转换赋值给子类对象名。

即:子类对象名=(子类类名)父类对象名;

常用的一种形式:方法中形参用父类型,实参用子类的对象名.

多态的概念

多态是指一个名称具有多种功能,即一棵继承树中的的类,可以有多个同名但不同方法体以及不同形参的方法。多态有两种实现方法:重载(overloading)和覆盖(overriding)。

重载(overloading)

重载(指方法重载)是指多个方法具有相同的名称,但各个方法的参数个数和参数类型不同,根据不同的参数个数和类型来选择执行不同的方法。

方法重载的条件:

1、方法名相同

2、参数列表不同

a、参数的个数不同:

b、参数的类型不同

c、参数类型的顺序不同

重载时,修饰符和返回值可以不同。

在Java中,系统根据方法名和参数列表来区分方法的。在选择重载方法是,首先寻找完全相同参数列表的方法,如果没有,则寻找类型相兼容的重载方法,如果还没有找到,则出错。

构造函数的重载:

构造函数重载的目的是以不同的方法对类进行初始化。构造函数的重载与其它方法相同,根据参数列表调用相同的构造函数。如果找不到相应的构造函数(包括兼容类型)则出错。

覆盖(overriding)

覆盖是在类派生体系中,子类中直接定义和父类同样的属性和方法(重新编写方法体)。Java虚拟机会根据调用这个方法的对象类型来确定哪个方法被调用。

属性覆盖的条件:只要属性名相同,就可实现覆盖,修饰符可以不同。

方法覆盖的条件:

1、成员名称相同

2、方法的参数列表完全相同

      a、参数的个数相同

      b、参数的类型相同

      c、参数类型的顺序相同

3、返回值必须相同

4、静态方法只能覆盖为静态方法

5、访问属性的要求:覆盖的方法必须至少提供与被覆盖方法一样的访问权限

      a、如果父类中的访问属性是public,则子类中的覆盖方法必须是public

      b、如果父类中的访问属性是protected,则子类中的覆盖方法是public和protected

      c、如果父类中方法的访问属性是默认类型,那么子类中的覆盖的方法的访问类型一定不能是private,其它的均可。

将子类对象名赋值给父类名,然后通过父类对象名引用存在覆盖关系的成员,这时系统会根据调用者引用内存空间的类型来动态调用内存空间对应类型的覆盖方法。

这种机制起作用的前提条件是:对象名的类型与所对应内存空间的类型不同时。换句话说,Java中方法的调用是根据内存的类型来决定调用哪个类中的方法。

在子类中,子类的成员将父类中同名的非私有成员覆盖(隐藏、屏蔽)了,如果需要引用父类的成员是,可以使用super来引用父类。

super引用父类,但super并不是父类对象的地址,是专门用来指代父类的一种结构。

this引用类本身,其引用对象本身的地址。

重载与覆盖的区别

1、方法的覆盖是子类和父类之间的关系,是垂直关系;方法的重载是同一个类中方法之间的关系,是水平关系。

2、覆盖只能由一个方法,或只能由一对方法产生关系;方法的重载是多个方法之间的关系。

3、覆盖要求参数列表相同;重载要求参数列表不同。

4、覆盖关系中,调用那个方法体,是根据对象的类型(对象对应存储空间类型)来决定;重载关系,是根据调用时的实参表与形参表来选择方法体的。

接口的概念

由于Java只支持单一继承,接口是Java实现多重继承功能的一种手段,一种结构。

接口只定义了与外界接触时输入、输出的格式。

Java通过接口使得处于不同层次甚至互不相同的类具有相同的行为。换句话说,通过在接口中定义一些方法(抽象方法),可以用接口大致规划出类的共同行为,而把具体的实现留给具体的类。

例如:Java中,java.appler.AppletContext定义了一个方法集,这些方法根据Applet的运行环境返回信息。如,AppletContext定义了一个getImage的方法,它是任何能够运行Applet的浏览器可以下载图片,但是,对于不同的浏览器他们的工作方式不同,并且可能运行在不同的操作系统平台上。这样,我们就要求每一个浏览器都实现AppletContext接口,而java.applet.ApplentContext类要依据在AppletContext接口中声明的方法工作,类无需考虑这些方法如何工作,也就是说可以在不同的环境和不同的浏览器中使用相同的applet类和相同的方法。

6.3.2 语法格式

[public] interface 接口名 [extends 父接口名1, 父接口名2, ...] {

        //接口体的定义

        [public static final] 类型 属性名=初始值;

        ...

        [public abstract] [native] 返回值类型 方法名(形参表) [throw 例外名利表];

        ...

}

接口在语法上与类非常类似,也有属性和方法,接口间也可以形成继承关系。但接口与类的区别是:接口的属性都是常量,接口的方法都是抽象方法,没有方法体。

接口与抽象类有些类似,有抽象的方法。接口与抽象类的区别是:接口中不能有非抽象方法(抽象类可以有非抽象方法);一个接口可以有多个父接口(抽象类只能由一个父类);接口中的属性的修饰符仅限于public static final;接口不属于继承结构,它与实际继承关系无关,因此无关的类也可以实现同一个接口。

[public]:接口的访问类型:public:任意类均可以使用这个接口;缺省:只有与该接口定义在同一个包中的类才可以访问这个接口。

interface:接口的关键字

接口名:命名规则遵守标识符命名规则。建议:接口名以able或ible结尾,表示接口所能实现的能力。

[extends 父接口名1, 父接口名2, ...]:接口可以有多个父接口,子接口继承父接口中所有的常量属性和方法。

扩展接口时要遵循以下原则:不可以定义方法体;接口不能由类派生。

[public static final] 类型 属性名=初始值; :接口的属性声明。接口的属性必须是public static final修饰的,所以在声明时可以不写,系统会默认声明这些修饰符,由于属性都是最终属性,所以声明时必须指定初始值。

[public abstract] [native] 返回值类型 方法名(形参表) [throw 例外名利表]; :接口的方法声明。接口中的方法必须是public abstract,所以声明时可以不写,系统会自动增加这些修饰。接口的方法没有方法体,以分号结束,是抽象方法。throw引导可能产生的例外。

如果在子接口中定义了和父接口同名的属性或方法,则也存在同类继承类似的覆盖和重载情况。

接口可以没有接口体,但{}必须有。

接口的实现

由于接口中的方法都是抽象方法,所以接口定义完成之后,必须在各类中对这个接口的方法进行具体化,就是在这个类中重新定义接口的所有方法,这时这些方法就不能是抽象的了,我们称这个过程为某各类实现了某个接口。

在声明类时,在声明中用implements子句表示该类实现该接口。在类中,必须将接口中所定义的所有抽象方法实现。一个类可以实现多个接口。

接口实现后,接口的属性在类中仍然是常量;我们可以通过覆盖将属性的常量特性去除。

Java的这种实现多重继承的方法,能够使新定义的类具有许多接口所具有的能力,但能力的实现需要在类中重新定义实现。

实现接口应注意:

1、一个类能够实现多个接口,一个接口可以被多个类实现。

2、一个类实现接口必须实现这个接口中的所有方法,包括父接口中的方法。被实现的方法必须和接口定义的方法有完全一样的方法名、返回值和形参表(否则就是重载)。

3、被实现的方法的访问控制类型必须是public。

适配器

使用一个接口时必须实现所有的方法,通常我们只需要使用接口中某些方法,如果也全部实现其他抽象方法非常不方便。在Java中,Java类库为所有接口提供了一个与接口相对应的抽象类(这个抽象类定义的内容与接口相同,只是一个是接口一个是抽象类),当我们只需要使用某个接口的少部分方法时,就可以继承与之相对应的抽象类,这个抽象类成为这个接口的适配器。

使用适配器的前提条件是,不需要继承其他的类(如果需要继承其他的类,这就成了多重继承)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值