继承的概念、特点,继承中方法覆盖的应用,this和super的使用方法
8.2 继承
8.2.1 生活中的继承
- 生活中的“继承”是施方的一种赠与,受方的一中获得;
- 将一方所拥有的东西给予另一方;
8.2.2 程序中的继承
- 程序中的继承,是类与类之间特征和行为的一种赠与或获得;
- 两个类之间的继承关系,必须满足“is a”的关系;
8.2.3 父类的选择
- 现实生活中,很多类别之间都存在着继承关系,都满足“is a”的关系;
- 狗是一种动物,狗是一种生物,狗是一种物质;
- 多个类别都可作为“狗”的父类,需要从中选择出最合适的父类;
- 功能越精细,重合点越多,越接近直接父类;
- 功能越粗略,重合点越少,越接近Object类;(万物皆对象的概念)
8.2.4 父类的抽取
- 可根据程序需要使用到多个具体类,进行共性抽取,进而定义父类;
8.2.5 继承
- 语法:
class 子类 extends 父类{} //定义子类时,显示继承父类 - 应用:
产生继承关系之后,子类可以使用父类中的属性和方法,也可定义子类独有的属性和方法; - 好处:
既提高代码的复用性,又提高代码的可扩展性;
public class TestExtends {
public static void main(String[] args) {
Dog dog = new Dog();
dog.breed = "哈士奇";//继承自父类
dog.age = 3;//继承自父类
dog.sex = "公";//继承自父类
dog.furColor = "黑白";//子类独有
dog.eat();//继承自父类
dog.run();//子类独有
}
}
//父类
class Animal{
String breed;//品种
int age;//年龄
String sex;//性别
public void eat() {}
public void sleep() {}
}
class Dog extends Animal{//完成继承父类
String furColor;//毛色
public void run() {}
}
public class TestExpents2 {
public static void main(String[] args) {
Car car = new Car();
car.type = "小汽车";
car.price = 1000000D;
car.speed = 120;
car.brand = "保时捷";
car.run();
Bus bus = new Bus();
bus.type = "公交车";
bus.price = 1500000D;
bus.speed = 60;
bus.seatNum = 20;
bus.run();
}
}
//交通工具类
class Vehicle{
String type;//类型
double price;//价格
int speed;//速度
public void run() {
System.out.println("一辆"+this.type+"以"+this.speed+"/h的速度行驶中。。。");
}
}
class Car extends Vehicle{
String brand;//品牌
}
class Bus extends Vehicle{
int seatNum;//座位数
}
8.2.6 继承的特点
- Java为单继承,一个类只能有一个父类,但可以多级继承,属性和方法逐级叠加;
8.2.7 不可继承
- 构造方法:
类中的构造方法,只负责创建本类对象,不可继承; - private修饰的属性和方法:
访问修饰符的一种,仅本类可见; - 父子类不再同一个package中时,default修饰的属性和方法:
访问修饰符的一种,仅同包可见;
8.2.8 访问修饰符
- | 本类 | 同包 | 非同包子类 | 其他 |
---|---|---|---|---|
private | √ | × | × | × |
default | √ | √ | × | × |
protected | √ | √ | √ | × |
public | √ | √ | √ | √ |
8.3 方法的覆盖
8.3.1 为什么要方法的覆盖
- 思考:子类是否可以定义和父类相同的方法?
- 思考:为什么需要在子类中定义和父类相同的方法?
- 分析:当父类提供的方法无法满足子类需求时,可在子类中定义和父类相同的方法进行覆盖;
8.3.2 方法的覆盖的特点
-
方法覆盖原则:
方法名称、参数列表、返回值类型必须与父类相同;
访问修饰符可与父类相同或是比父类更宽泛; -
方法覆盖的执行:
子类覆盖父类方法后,调用时优先执行子类覆盖后的方法;
public class TestOverride {
public static void main(String[] args) {
Dog2 dog = new Dog2();
dog.eat();//狗在吃骨头
Cat cat = new Cat();
cat.eat();//动物在吃
}
}
class Animal2{
String breed;//品种
int age;
String sex;
public void eat() {
System.out.println("动物在吃");
}
public void sleep() {
System.out.println("动物在睡");
}
}
class Dog2 extends Animal2{
String furColor;//毛色
//子类中定义和父类相同的方法进行覆盖
public void eat() {
System.out.println("狗在吃骨头");
}
public void run() {
}
}
class Cat extends Animal2{
}
8.3.3 super关键字
- 在子类中,可直接访问从父类继承到的属性和方法,但如果父子类的属性或方法存在重名(属性遮蔽、方法覆盖)时、需要加以区分,才可专项访问;
public class TestSuperKeyword {
public static void main(String[] args) {
B b = new B();
b.upload();
b.print();
}
}
class A{
int value = 10;
public void upload(){
System.out.println("父类代码");
//上传文件的100行代码
}
}
class B extends A{
int value = 20;//父子类的同名属性不存在覆盖关系,两块空间同时存在(子类遮蔽父类属性),需使用不同前缀进行访问
public void upload() { //super关键字可在子类访问父类的方法
super.upload();//上传文件的100行代码
System.out.println("子类添加的代码");
//修改文件名称的一行代码
} //使用“super.”的形式访问父类的方法,进而完成在子类中的复用
//再叠加额外的功能代码,组成新的功能
public void print() {
int value = 30;
System.out.println(value);//方法内的value
System.out.println(this.value);//子类属性的value
System.out.println(super.value);//父类属性的value
}
}
8.3.6 继承中的对象的创建
- 在具有继承关系的对象创建中,构建子类对象会先构建父类对象;
- 由父类的共性内容,叠加子类的独有内容,组合成完整的子类对象;
class Father{
int a;
int b;
public void m1(){}
}
class Son extends Father{//子类持有的属性和 方法:int a 、int b、int c、m1()、m2()
int c;
public void m1(){}
}
8.3.7 继承后的对象构建过程
8.3.8 super调用父类的构造方法
public class TestSuperKeyword2 {
public static void main(String[] args) {
new C();
new B1();
new B1(10);
}
}
class A1{
public A1() {
System.out.println("A()");
}
public A1(int vlaue) {
System.out.println("A(int value)");
}
}
class B1 extends A1{
public B1() {
super();//super():表示调用父类无参的构造方法。如果没有书写,隐式存在于子类构造方法的首行
System.out.println("B()");
}
public B1(int value) {
super(value);//super(实参):表示调用父类有参的构造方法
System.out.println("B(int value)");
}
}
class C extends B1{
public C() {
super();//super():表示调用父类无参的构造方法
System.out.println("C()");
}
}
8.3.9 this和super
public class TestSuperKeyword3 {
public static void main(String[] args) {
new B2(10);
}
}
class A2{
public A2() {
System.out.println("A-无参构造");
}
public A2(int value) {
System.out.println("A-有参构造");
}
}
class B2 extends A2{
public B2() {
super();
System.out.println("B-无参构造");
}
public B2(int value) {
this();//super();
System.out.println("B-有参构造");
}
}
- this或super使用在构造方法中时,都要求在首行
- 当子类构造中使用了this()或this(实参),即不可再同时书写super()或super(实参),会由this()执行的构造方法完成super()的调用;
8.3.10 总结
-
super关键字的第一种用法:
在子类的方法中使用“super.”的形式访问父类的书写和方法;
例如:super.父类书写、super.父类方法(); -
super关键字的第二种用法:
在子类的构造方法的首行,使用“super()”或“super(实参)”,调用父类构造方法。 -
注意:
如果子类构造方法中,没有显示定义super()或super(实参),则默认提供super();
同一个子类构造方法中,super()、this()不可同时存在。