为什么
我们知道,Java中只支持单继承的关系,当满足A is a B的时候,我们就可以限定,子类必须具有父类的通用特征。
什么?有的小萌新伙伴不知道什么事子类和父类,那我们可以这样理解,父类就是爸爸,子类就是儿子。当满足你是你爸的儿子后,那你就必须继承你爹的特性(基因🧬)可以理解了吧。这就是继承。
此时爱思考的小伙伴就会想问题了。
- 如何解决一个类型中需要兼容多种类型特征的问题呢?
- 以及多个不同类型具有相同特征的问题呢?
怎么理解
为了更好理解,我们创建一个场景
描述手机发展史
- 一代:最原始的一代手机只满足打电话的功能,比如大哥大
- 二代:增加了新的功能,可以发短信
- 三代:到了三代,我们的手机可以拍照,听音乐,等等
- 四代:当第四代手机出现,手机已经普及为个人掌上小电脑,可以浏览网页,玩游戏,看视频等等
那么针对这个场景描述,怎样实现合理的代码实现呢?
一,创建一代电话Telephone类
package com.immoc.tel;
/**
* Original phone
* @author kilig
*
*/
public class Telephone {
private String brand;
private int price;
public Telephone() {
}
public Telephone(String brand, int price) {
super();
this.setBrand(brand);
this.setPrice(price);
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public void call() {
System.out.println("The phone can Call!");
}
}
二,创建二代手机SecondTelephone,令它继承自第一代手机,可以发短信
package com.immoc.tel;
public class SecoundTelephone extends Telephone {
public void message() {
System.out.println("The Second Phone can send a message!");
}
}
三,创建三代手机Thirdtelephone, 使他继承自二代手机,可以看视频,听音乐
package com.immoc.tel;
public class ThirdTelephone extends SecoundTelephone {
public void video() {
System.out.println("The Phone can watch TV!");
}
public void music() {
System.out.println("The Phone can listen to music!");
}
}
四,创建四代手机FourthTelephone, 使他继承自三代手机,可以上网,玩游戏,自拍
package com.immoc.tel;
public class FourthTelephone extends ThirdTelephone{
public void photo() {
System.out.println("The Phone can take the photo!");
}
public void network() {
System.out.println("The phone can surf the internet!");
}
public void game() {
System.out.println("The Phone can play the game!");
}
}
五,创建测试类PhoneTest
我们可以看到,实例化四代手机后,可以调用之前所有手机的功能,没有问题,可以实现所有手机的能力。
纳新
在这个基础上我们增加新的场景,相机📷,电脑💻,智能手表⌚️。
- 📷相机也可以拍照
- 💻电脑也可以看视频,玩游戏,听音乐
- ⌚️智能手表也可以打电话,发短信
那么在程序中如果我们想继续满足这些要求时,该怎样去调整?
我们可以看到这些电子产品无法准确的用一个统一的公共父类去定义
六,创建Camera类
package com.immoc.tel;
public class Camera {
public void photo() {
System.out.println("The Camera can take the photo!!");
}
}
七,创建Computer类
package com.immoc.tel;
public abstract class Computer {
// public void network() {
// System.out.println("The Computer can surf the internet!");
// }
public void game() {
System.out.println("The Computer can play the game!!");
}
public void video() {
System.out.println("The Computer can Watch the video!");
}
public void music() {
System.out.println("The Computer can listen to the music!!");
}
八,创建SmartPhone类
package com.immoc.tel;
public class SmartPhone {
public static final int TEMP = 255;
public void call() {
System.out.println("The SmartPhone can make a call!");
}
public void message() {
System.out.println("The SmartPhone can send a message!!");
}
public void network() {
System.out.println("The SmartPhone can surf the internet!");
}
反思?
创建完成后,在测试类中编写各自的实例,然后调用每个类中的方法就可以实现输出了上面需求的场景需求了,但是这几款电子产品就没有办法创建一个关联关系么?然而这些类之间有相同的行为能力,那么是否可以通过关联这些行为能力去创建呢?在Java中,我们可以借用接口来实现。
怎么做?
首先尝试,右键目标文件,创建IPhoto接口
写出一个具有照相能力的接口,并且补充完拍照方法:
接下来利用该接口,让手机📱和相机📷产生关系!!找到Camera类,令该类实现接口的方法:
类实现接口的语法格式:
类名 implements 接口名{
}
可以看到系统提示:当类实现接口时,需要增加实现的方法,我们可以根据提示,快速重写Camera接口类方法:
同理,我们可以去四代手机FourthTelephone中添加拍照的接口进行修订。
此时在测试代码中,我们可以调用接口进行实现:
虽然这个实例指向的是第四代手机FourthTelephone,但是我们无法调用四代手机的上网,玩游戏,打游戏等等方法。
也就是我们可以借用接口来描述不同类型具有相似的行为特征的方法,从而建立关系后,通过类的实例来实现不同类型对于接口的实现。
定义
那么我们可以这样定义接口
- 接口定义了某一批类所需要遵守的规范
- 接口不关心这些类的内部数据,也不关心这些类的方法实现细节,它只规定这些类内必须提供的某些方法。
案例学习
为了方便小伙伴们的学习,我们在这儿还是结合具体情境进行学习。
九,在前面的案列中,电脑,智能手表,四代手机都具有上网的能力,那么我们编写一个上网的接口,设定这三个类之间的联系。按照前面的创建接口的方法,我们创建一个INet接口。
十,接着我们在Computer类中实现上网接口(注意访问权限的关系,子类重写父类的时候,要求子类权限不得高于父类,所以用public)
当接口包含多个方法时,作为实现类,就需要重写这些接口的方法,或者将该类设置为抽象类
接口中可以包含常量,默认是public,static,final。我们在类中定义一个常量通常这样写:
public static final int TEMP= 10;
但是在接口中,前面部分都是默认的自动加上的,可以直接 int TEMP = 10;
十一,在测试类中访问接口
接口名.常量名字就可以直接访问了
四,同理在智能手表中我们也继续上面的操作,我们可以执行同样的操作。
在测试中,我们进行接口的调用,并且查看输出结果!
【注意】如果接口和实现类中有同名的常量,那么在测试类中进行调用接口时,我们调用的都是接口中定义的常量名。
默认&静态方法
当我们不=不想在类中重写接口方法怎么办?我们可以在接口中写默认方法和静态方法来实现。值得注意的是这种方式只能在JDK版本1.8之后实现,静态方法只能在实现类中继承不能重写!!
通过 接口名. 只能调用当前接口中的静态成员,如果想访问待实现接口的默认成员,就必须 接口名.super. 的方式来进行