打怪升级之小白的大数据之旅(十四)
Java基础语法之面向对象的接口
上次回顾:
上一章,对面向对象三大特性之一的多态,本章接口是基于多态的基础上进行展开,接口的概念比较抽象一些,不过没关系,多写写我在里面写的案例,慢慢就懂了
抽象类
概念
- 抽象:即不具体、或无法具体的类
例如:当我们声明一个几何图形类:圆、矩形、三角形类等,发现这些类都有共同特征:求面积、求周长、获取图形详细信息。那么这些共同特征应该抽取到一个公共父类中。但是这些方法在父类中又无法给出具体的实现,而是应该交给子类各自具体实现。那么父类在声明这些方法时,就只有方法签名,没有方法体,我们把没有方法体的方法称为抽象方法。Java语法规定,包含抽象方法的类必须是抽象类
语法格式
- 抽象类
抽象类的语法格式
【权限修饰符】 abstract class 类名{
}
【权限修饰符】 abstract class 类名 extends 父类{
}
- 抽象方法
【其他修饰符】 abstract 返回值类型 方法名(【形参列表】);
- 注意
- 抽象方法没有抽象体
- 示例代码 定义一个几何图形父类Graphic。所有几何图形都应该具备一个计算面积的方法。但是不同的几何图形计算面积的方式完全不同:
abstract class Graphic{ public abstract double getArea(); } class Circle extends Graphic{ private double radius; public Circle(double radius) { super(); this.radius = radius; } public Circle() { super(); } public double getRadius() { return radius; } public void setRadius(double radius) { this.radius = radius; } @Override public double getArea() { return Math.PI * radius * radius; } } class Rectangle extends Graphic{ private double length; private double width; public Rectangle(double length, double width) { super(); this.length = length; this.width = width; } public Rectangle() { super(); } public double getLength() { return length; } public void setLength(double length) { this.length = length; } public double getWidth() { return width; } public void setWidth(double width) { this.width = width; } @Override public double getArea() { return length * width; } }
抽象类特点
- 类不能创建对象,如果创建,编译无法通过而报错。只能创建其非抽象子类的对象。
理解:假设创建了抽象类的对象,调用抽象的方法,而抽象方法没有具体的方法体,没有意义。
- 抽象类中,也有构造方法,是供子类创建对象时,初始化父类成员变量使用的。
理解:子类的构造方法中,有默认的super()或手动的super(实参列表),需要访问父类构造方法。
- 抽象类中,不一定包含抽象方法,但是有抽象方法的类必定是抽象类。
理解:未包含抽象方法的抽象类,目的就是不想让调用者创建该类对象,通常用于某些特殊的类结构设计。
- 抽象类的子类,必须重写抽象父类中所有的抽象方法,否则,编译无法通过而报错。除非该子类也是抽象类。
理解:假设不重写所有抽象方法,则类中可能包含抽象方法。那么创建对象后,调用抽象的方法,没有意义。
接口(interface)
概念
接口是什么?在接口的定义中是这么说的:
接口的本质是契约,是一种标准规范
怎么理解它呢?请看下图:
就像上图中的情景,我们每天都在用USB接口,这个USB接口可以连接电脑,可以连接手机,连接键盘…电脑,手机,键盘,他们各自有自己的属性和方法,但当它们都支持USB接口的时候,我就可以通过USB接口连接并使用它们
接口的定义格式与特点
- 定义格式
接口是静态常量与抽象方法定义的集合。跟定义类的方式类似,接口使用关键字interface定义
示例代码:【修饰符】 interface 接口名{ // 接口的成员 }
interface Usb3{ //静态常量 long MAX_SPEED = 500*1024*1024;//500MB/s //抽象方法 void read(); void write(); //默认方法 public default void start(){ System.out.println("开始"); } public default void stop(){ System.out.println("结束"); } //静态方法 public static void show(){ System.out.println("USB 3.0可以同步全速地进行读写操作"); } }
- 接口的成员 (JDK8 之前只有前两种)
- 静态常量
在接口中定义的变量就是静态常量
因为默认自带修饰符public static final
- 抽象方法
在接口定义的没有方法体的方法就是抽象方法
因为默认自带修饰符public abstract
- 默认方法
利用 default关键字 实现默认方法
作用是实现类可以选择是否重写此方法(以前必须把所有重写方法都实现) - 静态方法(jdk8之后实现)
专门为此接口服务的工具类方法,可以写在接口内部 - 私有方法(jdk9之后支持此方法)
可以将接口内共用方法抽取到此方法中
- 静态常量
- 特点
- 接口定义的是多个类共同的公共行为规范,这些行为规范是与外部交流的通道,这就意味着接口里通常是定义一组公共方法。
- 接口没有构造方法,不能创建对象。
- 成员变量默认自带修饰符public static final,即为静态常量。
- 抽象方法默认自带修饰符public abstract(jdk8之前版本接口中方法只能是抽象方法)
- 接口是用来被实现的,其实现类必须重写它的所有抽象方法,除非实现类是个抽象类
- 接口可以多实现,一个类可以同时实现多个接口
- 接口可以继承接口,接口之间支持多继承
- 在JDK1.8时,接口中允许声明默认方法和静态方法:
- 公共的默认的方法:其中public 可以省略,建议保留,但是default不能省略
- 公共的静态的方法:其中public 可以省略,建议保留,但是static不能省略
- 在JDK1.9时,接口又增加了私有方法
实现接口
-
概念
-
接口是一套规范,是功能的拓展,使用接口,就需要类实现接口,理解为符合接口规范的类或额外拓展功能的类。
-
类与接口的关系为实现关系,即类实现接口,该类可以称为接口的实现类,也可以称为接口的子类。实现的动作类似继承,格式相仿,只是关键字不同,实现使用 implements关键字。
-
-
语法格式
【修饰符】 class 实现类 implements 接口{ // 重写接口中抽象方法【必须】,当然如果实现类是抽象类,那么可以不重写 // 重写接口中默认方法【可选】 } 【修饰符】 class 实现类 extends 父类 implements 接口1{ // 重写接口中抽象方法【必须】,当然如果实现类是抽象类,那么可以不重写 // 重写接口中默认方法【可选】 }
注意:
- 如果接口的实现类是非抽象类,那么必须重写接口中所有抽象方法。
- 默认方法可以选择保留,也可以重写。
重写时,default单词就不要再写了,它只用于在接口中表示默认方法,到类中就没有默认方法的概念了 - 不能重写静态方法
-
示例代码: 实现接口
class MobileHDD implements Usb3{ //重写/实现接口的抽象方法,【必选】 public void read() { System.out.println("读数据"); } public void write(){ System.out.println("写数据"); } //重写接口的默认方法,【可选】 //重写默认方法时,default单词去掉 public void end(){ System.out.println("清理硬盘中的隐藏回收站中的东西,再结束"); }
调用接口对应的方法
- 对于接口的静态方法,直接使用“接口名.”进行调用即可
- 也只能使用“接口名."进行调用,不能通过实现类的对象进行调用
- 对于接口的抽象方法、默认方法,只能通过实现类对象才可以调用
- 接口不能直接创建对象,只能创建实现类的对象
- 示例代码:
public class TestInteface { public static void main(String[] args) { //创建实现类对象 MobileHDD b = new MobileHDD(); //通过实现类对象调用重写的抽象方法,以及接口的默认方法,如果实现类重写了就执行重写的默认方法,如果没有重写,就执行接口中的默认方法 b.start(); b.read(); b.stop(); //通过接口名调用接口的静态方法 MobileHDD.show(); } }
- 案例:
package com.test01class;
/*
* 1、声明一个LiveAble接口
- 包含两个抽象方法:
- void eat();
- void breathe();
- 包含默认方法 default void sleep(),实现为打印“静止不动”
- 包含静态方法 static void drink(),实现为“喝水”
2、声明动物Animal类,实现LiveAble接口。
- void eat();实现为“吃东西”,
- void breathe();实现为"吸入氧气呼出二氧化碳"
- void sleep()重写为”闭上眼睛睡觉"
3、声明植物Plant类,实现LiveAble接口。
- void eat();实现为“吸收营养”
- void breathe();实现为"吸入二氧化碳呼出氧气"
4、在测试类中,分别创建两个实现类的对象,调用对应的方法。通过接口名,调用静态方法
* */
// 测试类
public class Demo2Interface2 {
public static void main(String[] args) {
// 测试接口方法,实例化动物类
Animal animal = new Animal();
animal.eat();
animal.breathe();
animal.sleep();
System.out.println("---------------------------------------------");
// 实例化植物类,进行光合作用
Plant plant = new Plant();
plant.eat();
plant.breathe();
}
}
// 定义LiveAble接口
interface LiveAble{
// 定义抽象方法
void eat();
void breathe();
// 定义默认方法
default void sleep(){
System.out.println("静止不动");
}
// 定义静态方法
static void drink(){
System.out.println("喝水");
}
}
// 定义动物类Animal并实现LiveAble接口
class Animal implements LiveAble{
@Override
public void eat() {
System.out.println("吃东西");
}
@Override
public void breathe() {
System.out.println("吸入氧气呼出二氧化碳");
}
@Override
public void sleep() {
System.out.println("闭上眼睛睡觉");
}
}
// 定义植物类Plant,并实现LiveAble接口
class Plant implements LiveAble{
@Override
public void eat() {
System.out.println("吸收营养");
}
@Override
public void breathe() {
System.out.println("吸入二氧化碳呼出氧气");
}
}
接口的多实现
- 在面向对象继承那里提到过,java面向对象中的继承,只有单继承,一个类只能继承一个父类,而对于一个接口而言,一个类可以实现多个接口,这叫做接口的多实现
- 在接口中,一个类能继承一个父类并且实现多个接口
- 实现格式:
【修饰符】 class 实现类 implements 接口1,接口2,接口3。。。{ // 重写接口中所有抽象方法【必须】,当然如果实现类是抽象类,那么可以不重写 // 重写接口中默认方法【可选】 } 【修饰符】 class 实现类 extends 父类 implements 接口1,接口2,接口3。。。{ // 重写接口中所有抽象方法【必须】,当然如果实现类是抽象类,那么可以不重写 // 重写接口中默认方法【可选】 }
接口中,有多个抽象方法时,实现类必须重写所有抽象方法。如果抽象方法有重名的,只需要重写一次
-
示例代码1: 多接口案例
/* * 1、声明第一个接口Runner,包含抽象方法:void run() 2、声明第二个接口Swimming,包含抽象方法:void swim() 3、声明兔子类,实现Runner接口 4、声明乌龟类,实现Runner接口和Swimming接口 * */ // 测试入口 public class DemoRabbitRunner { public static void main(String[] args) { // 实例化兔子类 Rabbit rabbit = new Rabbit(); // 执行接口方法 rabbit.run(); // 实例化乌龟类 Tortoise tortoise = new Tortoise(); // 执行接口方法 tortoise.run(); tortoise.swim(); } } // 定义接口Runner interface Runner{ void run(); } // 定义就扣Swimming interface Swimming{ void swim(); } // 定义兔子类 class Rabbit implements Runner{ // 实现接口的方法 @Override public void run() { System.out.println("兔子跑得快"); } } // 定义乌龟类 class Tortoise implements Runner,Swimming{ // 实现跑的接口 @Override public void run() { System.out.println("乌龟爬的慢"); } // 实现游泳的接口 @Override public void swim() { System.out.println("乌龟游得飞快"); } }
-
示例代码2: 继承父类并且多接口
/* * 定义一个抽象父类Animal,它有一个eat()方法 * 定义一个接口Jumpable,它有一个jump()方法 * 定义一个接口Play,它有一个play()方法 * 定义一个实现类Cat与Student类,Cat类继承自Animal父类 * 在测试类中创建对象,并邀请猫和学生调用jump方法 * */ public class Demo2Interface { public static void main(String[] args) { // 利用多态创建一个猫类,调用猫类的方法,并且邀请猫跳舞 Animal cat = new Cat(); cat.eat(); // 这是另外一只猫,除非向下转型 Jumpable catJump = new Cat(); catJump.jump(); System.out.println("-----------------------------------------------"); // 学生调用接口,学习完毕后进行跳舞,认识了新朋友,一起去玩游戏 Student stu = new Student(); stu.study(); stu.jump(); stu.playGame(); System.out.println("-----------------------------------------------"); // 创建另外一只猫,它边吃鱼,边跳舞,跳累了会去玩毛球 Cat tom = new Cat(); tom.eat(); tom.jump(); tom.playGame(); } } // 抽象类 abstract class Animal{ // 抽象方法 public abstract void eat(); } // 定义接口 interface Jumpable{ public void jump(); } interface Play{ void playGame(); } // 定义一个猫类,它继承自Animal类,并且具有接口的现实类 class Cat extends Animal implements Jumpable, Play{ // 重写父类方法 @Override public void jump() { System.out.println("猫跳舞"); } // 实现接口 @Override public void eat() { System.out.println("猫吃鱼"); } @Override public void playGame() { System.out.println("猫喜欢玩线球~~"); } } // 定义一个学生类并实现接口 class Student implements Jumpable,Play{ // 自己的方法 public void study(){ System.out.println("好好学习"); } // 实现接口 @Override public void jump() { System.out.println("学生跳广场舞"); } @Override public void playGame() { System.out.println("玩王者荣耀"); } } ```
-
看到这个实例,是不是觉得使用普通的类实例化更方便,多态反而不那么方便?这么来理解,多态的应用,是在未知的情况,普通类实现是在已知的情况
-
举个栗子,假设我有一个跳舞的方法,但并不知道谁会来参加,也并不知道他们每个人都会什么舞蹈,那么我就使用多态,如果我知道有谁参加,并且规定了舞种,那么我就直接使用普通类的调用
接口的多继承
- 一个接口能继承另一个或者多个接口,接口的继承也使用extends关键字,子接口继承父接口的方法
- 示例代码:
// 接口的多继承 public class Demo2 { public static void main(String[] args) { InsteranceSon jake = new InsteranceSon(); jake.aspect(); jake.height(); jake.fatherGene(); jake.motherGene(); } } interface Father{ void fatherGene(); public default void height(){ System.out.println("完美的身材"); } } interface Mother{ void motherGene(); public default void aspect(){ System.out.println("精致的面容"); } } interface Son extends Father,Mother{ } class InsteranceSon implements Son{ @Override public void fatherGene() { System.out.println("儿子继承了父亲的睿智"); } @Override public void motherGene() { System.out.println("儿子继承了母亲的气质"); } }
接口与实现类对象的多态引用
- 通过前面的例子,我们可以发现,接口的继承,类似于子类继承父类,因此,接口类型的变量与现实类之间也可以构成多态的引用,通过接口类型的变量调用方法,最终执行的是new的显示类对象实现的方法体
- 示例代码:
package com.test02Demo; /* * 接口与实现类对象的多态引用 * */ public class Demo3 { public static void main(String[] args) { // 实例化鸟类 Flyable bird = new Bird(); bird.fly(); // 实例化风筝类 Flyable kite = new Kite(); kite.fly(); } } // 定义飞的接口 interface Flyable{ // 抽象方法 void fly(); } // 定义鸟类 class Bird implements Flyable{ // 重写接口方法 @Override public void fly() { System.out.println("鸟儿展翅高飞在蓝天下"); } } // 定义风筝类 class Kite implements Flyable{ // 重写接口方法 @Override public void fly() { System.out.println("别拽我啦,我要飞向太空~"); } }
接口的默认方法冲突
亲爹优先原则
- 当一个类,既继承一个父类,又实现若干个接口时,父类中的成员方法与接口中的抽象方法重名时,子类就近选择执行父类的成员方法,称之为亲爹优先原则
- 示例代码:
// 定义接口 interface ImInterface{ // 定义抽象方法 public default void eat(){ System.out.println("我是接口的eat方法"); }; } // 定义父类 class Father{ public void eat(){ System.out.println("我是父类的eat方法"); }; } // 定义子类 class Son extends Father implements ImInterface{ // 未重写eat方法 } class Son2 extends Father implements ImInterface{ // 重写了eat方法 @Override public void eat() { System.out.println("我是子类的eat方法"); } } // 定义测试类 public class Demo { public static void main(String[] args) { // 实例化未重写eat方法的son类 Son son1 = new Son(); son1.eat(); // 实例化重写了eat方法的son2类 Son2 son2 = new Son2(); son2.eat(); } } // 结果: 我是父类的eat方法 我是子类的eat方法
必须做出选择
- 当一个类同时实现了多个接口,而且多个接口中包含方法签名相同的默认方法时,我们可以通过super进行选择,或者自己重写一个方法,如果都不选,计算机也不知道选那个,就会抛出异常
- 示例代码:
// 无论你多难抉择,最终都是要做出选择的
interface A{
public default void d(){
System.out.println("今晚7点-8点陪我吃饭看电影");
}
}
interface B{
public default void d(){
System.out.println("今晚7点-8点陪我逛街吃饭");
}
}
//选择保留其中一个,通过“接口名.super.方法名"的方法选择保留哪个接口的默认方法
class C implements A,B{
@Override
public void d() {
A.super.d();
}
}
// 如果都不选,就自己重写一个选择
class D implements A,B{
@Override
public void d() {
System.out.println("自己待着");
}
}
经典接口的介绍与使用
经典接口概念
- 我们知道基本数据类型的数据(除boolean类型外)需要比较大小的话,之间使用比较运算符即可,
- 但是引用数据类型是不能直接使用比较运算符来比较大小的。因为引用类型本身之间本身没有大小可言(包装类除外),需要- - 我们根据需求来决定那一个对象是大还是小,那么不同的引用类型就可能判断依据不一样。
- 我们一定义一个接口,给出比较两个对象大小的方法,但具体实现由不同的实现类完成
java.lang.Comparable
- Java给所有引用数据类型的大小比较,指定了一个标准接口,就是java.lang.Comparable接口
- 这个接口的方法仅限于比较同一个类下的两个对象进行比较
- 语法格式:
package java.lang;
public interface Comparable{
int compareTo(Object obj);
}
知道了这个接口之后,我们应该怎么使用它呢?步骤如下:
第一步:哪个类的对象要比较大小,哪个类就实现java.lang.Comparable接口,并重写方法
- 方法体就是你要如何比较当前对象和指定的另一个对象的大小
第二步:对象比较大小时,通过对象调用compareTo方法,根据方法的返回值决定谁大谁小。
- this对象(调用compareTo方法的对象)大于指定对象(传入compareTo()的参数对象)返回正整数
- this对象(调用compareTo方法的对象)小于指定对象(传入compareTo()的参数对象)返回负整数
- this对象(调用compareTo方法的对象)等于指定对象(传入compareTo()的参数对象)返回零
- 示例代码:
/* * 声明一个Employee员工类,包含编号、姓名、薪资,实现Comparable接口,要求,按照薪资比较大小,如果薪资相同,按照编号比较大小。 声明一个测试类Demo4类,在main中创建Employee[]数组,长度为5,并且存储5个员工对象,现在要求用冒泡排序,实现对这个数组进行排序,遍历结果。 * */ // 测试类 public class Demo4 { public static void main(String[] args) { // 创建员工数组对象并实例化员工类 Employee[] arr = new Employee[5]; arr[0] = new Employee(1,"张三",13000); arr[1] = new Employee(2,"李四",13000); arr[2] = new Employee(3,"王五",14000); arr[3] = new Employee(4,"赵六",7000); arr[4] = new Employee(5,"钱七",9000); // 原员工列表的顺序 System.out.println("员工列表"); for (int i = 0; i < arr.length; i++) { System.out.println(arr[i]); } // 利用冒泡排序对员工进行排序 for (int i = 0; i < arr.length - 1; i++) { for (int j = 0; j < arr.length -i -1; j++) { // 调用重写的Comparable接口方法进行排序 if (arr[j].compareTo(arr[j+1])>0){ Employee temp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = temp; } } } System.out.println("排序后的员工列表"); for (int i = 0; i < arr.length; i++) { System.out.println(arr[i]); } } } // 定义Employee员工类 class Employee implements Comparable { // 定义员工属性 private int id; private String name; private double salary; // 定义构造器 public Employee(int id, String name, double salary) { this.id = id; this.name = name; this.salary = salary; } // 定义getter方法 public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public double getSalary() { return salary; } public void setSalary(double salary) { this.salary = salary; } // 重写toString方法并自定义输出 @Override public String toString() { return "Employee{" + "id=" + id + ", name='" + name + '\'' + ", salary=" + salary + '}'; } // 调用Comparable接口,并定义比较规则 @Override public int compareTo(Object o) { // 因为知道类的类型,因此需要使用向下转换 Employee emp = (Employee)o; if(this.getSalary()!=emp.getSalary()){ return Double.compare(this.getSalary(), emp.getSalary()); } return this.id-emp.id; } }
java.util.Comparator
(1)如果一个类,没有实现Comparable接口,而这个类你又不方便修改(例如:一些第三方的类,你只有.class文件,没有源文件),那么这样类的对象也要比较大小怎么办?
(2)如果一个类,实现了Comparable接口,也指定了两个对象的比较大小的规则,但是此时此刻我不想按照它预定义的方法比较大小,但是我又不能随意修改,因为会影响其他地方的使用,于是,我们就要使用Comparator接口进行排序了,排序步骤如下:
第一步:编写一个类,我们称之为比较器类型,实现java.util.Comparator接口,并重写方法
- 方法体就是你要如何指定的两个对象的大小
第二步:比较大小时,通过比较器类型的对象调用compare()方法,将要比较大小的两个对象作为compare方法的实参传入,根据方法的返回值决定谁大谁小。
- o1对象大于o2返回正整数
- o1对象小于o2返回负整数
- o1对象等于o2返回零
- 示例代码:
//一个没有实现Comparable接口的学生类
class Student{
private String name;
private int score;
public Student(String name, int score) {
super();
this.name = name;
this.score = score;
}
public Student() {
super();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
@Override
public String toString() {
return "Student [name=" + name + ", score=" + score + "]";
}
}
//定义定制比较器类
class StudentScoreCompare implements Comparator{
@Override
public int compare(Object o1, Object o2) {
Student s1 = (Student) o1;
Student s2 = (Student) o2;
return s1.getScore() - s2.getScore();
}
}
// 测试类
import java.util.Comparator;
public class TestComparator {
public static void main(String[] args) {
Student stu1 = new Student("张三",89);
Student stu2 = new Student("李四",78);
StudentScoreCompare ssc = new StudentScoreCompare();
if(ssc.compare(stu1, stu2)>0){
System.out.println(stu1 + ">" + stu2);
}else if(ssc.compare(stu1, stu2)<0){
System.out.println(stu1 + "<" + stu2);
}else{
System.out.println(stu1 + "=" + stu2);
}
}
}
java.lang.Cloneable标记接口
- 标记接口:没有任何方法的接口。类似注解,注解我们下一章开详细介绍
- 在java.lang.Object类中有一个方法
protected Object clone()throws CloneNotSupportedException
- 所有类型都可以重写这个方法,它是获取一个对象的克隆体对象用的,就是造一个和当前对象各种属性值一模一样的对象。当然地址肯定不同
- 我们在重写这个方法后时,调用super.clone(),发现报异常CloneNotSupportedException,因为我们没有实现java.lang.Cloneable接口
- 示例代码:
class Teacher implements Cloneable{
private int id;
private String name;
public Teacher(int id, String name) {
super();
this.id = id;
this.name = name;
}
public Teacher() {
super();
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Teacher [id=" + id + ", name=" + name + "]";
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + id;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Teacher other = (Teacher) obj;
if (id != other.id)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
//测试类
public class TestClonable {
public static void main(String[] args) throws CloneNotSupportedException {
Teacher src = new Teacher(1,"苍老师");
Object clone = src.clone();
System.out.println(clone);
System.out.println(src == clone);
System.out.println(src.equals(clone));
}
}
后面我们提到序列化接口的时候就是这个标记接口,大家有个印象就好
总结
本章我们首先介绍了抽象类,接着主要围绕接口展开,个人理解,它的出现有两个目的,第一个就是解决java单继承无法多继承问题,第二个就是制定标准
接口在java8之前就是100%的抽象类,就如开篇的那个计算机的图所讲,它是一种规范,标准,有了它,我们可以连接到不同的实现类上,
为什么说它是100%的抽象类呢,因为在java8前,它的方法必须重写,并没有后来的default 静态方法乃至现在的私有方法
好了,今天的内容就是这些,下一期我会围绕面向对象基础的最后一点知识点,内部类,static关键字以及注解展开,欢迎大家后台吐槽~