上节答案:A。解析:内部类也是一个类,可以有自己的成员方法和成员变量
3 - 1:Java中的继承
在前面的课程里面,对面向对象的三大特征之一,封装有了个基本的认识,那么我们现在再来看看什么是继承。
继承是类和类的一种关系,我们可以把它总结为“is a”的关系。例如,狗是动物,那么我们就可以描述,狗是继承动物。那狗类继承动物类,狗类就叫动物类的子类,或派生类,动物类就是狗的父类,或基类。这是他们两者之间的称呼。其实在生活当中,我们有很多继承的例子,例如,子女继承了父亲的财产,我们就称为富二代;子女拥有了父类的权力,我们就称这是官二代。那大家要注意,在我们Java中,是单继承的,就是说,一个类只有一个父类,和我们人一样,每个人只有一个亲爹。
继承的好处:我们想,生活当中,如果有一个好的父亲,我们通常可以说,可以少奋斗几年,也就意味着,父亲如果选得好的话,那么对于我们的成长是很有帮助的,我们自己就可以少干很多事情。在我们代码世界当中,也是这样的。如果两个类有了继承的关系,那么子类就直接拥有了父类的属性和方法,但是,父类的属性或方法的修饰符不能是private;如果我们父类实现了一些功能子类继承了父类,这样的话,我就可以复用父类所写的代码,我们把它称为代码的复用。
语法规则:
class 子类 extends 父类{
}
例:
class Dog extends Animals{
...
}
好,我们来写一个Demo。
首先,我们有一个父类,动物类,还有一个类为子类,狗类,它继承于动物类,继承于父类动物类,这样的话我们在子类里面就不用再写相应的代码,此时我们就实现了代码的复用。
我们先在包里面创一个类Animal,然后再类里面创建两个属性一个int年龄,和一个名称,同时,可以给这个类一个吃东西的能力(方法)eat,输出动物具有吃东西的能力,这样的话,我一个基本的父类就写好了;
那现在有这样一个子类,Dog类,那我们想想,Dog是动物,所以说,它肯定会继承Animal这个父类,按照我们以前的写法,在Dog类里面也要写这些内容,由于Dog类和Animal有一个继承关系,此时Dog类就可以继承Animal类里面的所有属性和方法,那么,我们就不需要再写这部分代码了,从而实现我们代码复用的能力。
再在这个包里创建一个Dog类,这里要注意,这个类应该与Animal创建关联,所以我们要创建时点一下Superclass后面点一下browse...,出现这个:
点OK,然后Finish,这就创建了一个Dog的子类:
我们只通过extends关键字,就将我们的Dog类和Animal类建立起关联来。那我们在子类里并没有写任何属性和方法,那此时我们再创建一个测试类,Initial类,加入main方法,执行,那么首先,我们来创建一个Dog对象:
那刚刚大家注意到,现在Dog子类里没写任何东西,那我们发现,此时,我们是可以调用dog的属性和方法的,显然这个属性是从父类继承来的,这样,子类就不用自己再写代码了。
那我们要注意一个问题,如果父类的属性是用我们的private修饰符修饰的,那么,private修饰的我们是不能继承的。你会发现,如你调用了一个private的age属性,我们是无法使用的。
思考:
在生活当中还有那些对象是继承关系,试用Java来描述。
3 - 2:Java中的方法重写
我们在使用继承的时候,经常还有一种情况, 就是子类虽然可以继承父类的方法,但对父类的方法不满意,我们想写一个子类自己有的一个方法,同时这个名跟父类方法名相同,此时我们就叫方法的重写。
1、什么是方法的重写
如果子类对继承父类的方法不满意,是可以重写父类继承方法的,当调用方法时会优先调用子类的方法。我们要注意,方法在重写的时候,要注意语法规则。
2、语法规则
返回值类型、方法名、参数类型及个数都要与父类继承方法相同,这才叫方法的重写。
我们可以通过Eclipse来看一下。
比如说这里,我们可以从父类继承一个eat方法,但是eat方法里仅仅是可以描述动物是可以吃东西的,而我们现在明明是创建了Dog类,我能不能突出Dog类这个特点呢?所以说,此时我对父类这个eat方法就不满意了。我想重写一个属于子类Dog的方法,那么我们就可以在Dog类写一个eat方法(注意语法规则),像下面这样:
但是,main函数里没有做任何改变,但是输出时把动物改成了狗:
思考
对于交通工具,具体其车辆有座位数,并提供一个print方法的能力可以输出具体交通工具的坐位数是否也可以重写呢?
3 - 3:练习题
Java 中实现继承的关键字是( )
A、extends
B、has
C、import
D、base
答案:A。解析:Java 中通过 extends 实现继承关系
3 - 4:Java中的继承初始化顺序
在前面的课程里面,我们已经详细学习了继承是什么。现在来看一下,当我们使用教程特性的时候,程序是如何执行的呢?也就是说,我们要关注一下,继承的初始化顺序:1、初始化父类再初始化子类,2、先执行初始化对象中属性,再执行构造方法中的初始化。
切换到我们的代码编辑模式下,按照我们刚才所说的,初始化其实就是相当于执行我们类的构造方法。所以说,我只需要在类的构造方法里面输出一句话,看看它到底是什么时候输出的,就知道它们的执行顺序了。
我在Animal类的构造方法输出Animal类执行了,在Dog类构造方法输出Dog类执行了,在主函数里,我只是创建了子类对象,这样我们来看一下,它的执行顺序是什么。下面的图大家点开来看。
显然大家发现,我仅仅是创建了子类对象,但是,它是先执行了父类的构造方法,然后又执行了子类的构造方法。这样的话,我们就可以证明,当创建对象的时候,它会优先创建我们的父类对象,然后才会创建我们的子类对象。
在创建对象的时候我们发现构造方法有这样的执行顺序,那么对象当中有属性,属性和我们的构造方法在初始化的时候哪一个先执行呢?
那我们可以做一个简单的例子,如果我在创建我们这个父类的时候给我们的属性赋一个初值,然后当我们在执行构造方法的时候再给这个属性赋一个值(不同于初值),拿么我们想想,如果我们在程序中输出这个属性的值,那么这个值是谁的,它其实是后执行的,因为后面的值会把前面的值覆盖掉。例如说,如果我们的最终输出age的值是10,那么显然,我们这个属性的初始化是后做的,而我们的构造方法里面的初始化是先做的,如果我们输出的值是20,那么显然我们属性的初始化是先做的,构造方法里的初始化是后做的,后面这个20会把前面这个10覆盖掉。
好,我们测试一下,我们先创建一下父类对象animai,然后直接输出一下age,看看属性值是多少:
是20,证明先执行的属性初始化,再执行的构造方法初始化。从这个角度来讲,属性的初始化和构造方法里的初始化属性的初始化是先执行的。
创建顺序:父类对象→父类属性初始化→父类构造方法→子类对象→子类属性初始化→子类构造方法。
3 - 5:Java中的final的使用
我们在写继承代码的时候,经常还会用到final关键字。
那什么是final关键字呢——final关键字从字面上理解就是“最终的”的含义,就是说,不可修改,不可变化。
final可以修饰类、方法、属性、变量。
final关键字修饰类,则该类不允许被继承。那此时,这个类就成了最终的类了。
final关键字修饰方法,则该方法不允许被覆盖(重写)。
final关键字可以修饰属性,则该类的属性不会进行隐式的初始化(类的初始化属性必须有值),或在构造方法中赋值。
final关键字修饰变量,则该变量的值只能赋值一次,即变为常量。
我们在代码中,如何使用呢:
首先我们在声明类的前面加一个final关键字:
我们会发现,这个类就不允许被继承,Dog类前面就会有错。提示:我们Dog不能继承父类Animal,因为Animal使用了关键字final来修饰。
我们刚才又说过,final关键字又可以修饰方法,我们在Animal类里的eat方法前面加个final,去掉类前面的final。如果final关键字修饰了方法,则子类不允许覆盖父类的方法。
我们还说过,final关键字可以修饰属性。我们给age前面加一个final,则这个属性不能在其他位置进行改值(在构造方法中也不能改)。不过要记得,要给它一个值才行!如果我们不初始化,我们必须在构造方法中初始化才行。
3 - 6:练习题
如果用 final 修饰一个类的话,代表此类
A、不可被继承
B、是静态类
C、不能被实例化
D、不能继承其他类
答案:A。解析:final 修饰的类不可被继承