接口定义的是多个类共同的公共行为规范,这些行为规范是与外部交流的通道,这就意味着接口里通常是定义一组公共方法。可以理解为:接口是从多个相似类中抽象出来的规范,不需要提供具体实现
在JDK8之前,接口中只允许出现:
静态常量:接口中的变量,默认被 public static final 修饰,可以省略不写。我们可以使用接口名称.变量名 访问常量值。因为接口是标准规范,那么在规范中需要声明一些底线边界值,当实现者在实现这些规范时,不能去随意修改和触碰这些底线,否则就有“危险”。例如:USB1.0规范中规定最大传输速率是1.5Mbps,最大输出电流是5V/500mA
抽象方法:接口中的抽象方法 默认被 public abstract 修饰,可以省略不写。
在JDK1.8时,接口中允许声明默认方法和静态方法:
默认的方法:其中public 可以省略,建议保留,但是default不能省略。
我们要在已有的老版接口中提供新方法时,如果添加抽象方法,就会涉及到原来使用这些接口的类就会有问题,那么为了保持与旧版本代码的兼容性,只能允许在接口中定义默认方法实现。比如:Java8中对Collection、List、Comparator等接口提供了丰富的默认方法。
当我们接口的某个抽象方法,在很多实现类中的实现代码是一样的,此时将这个抽象方法设计为默认方法更为合适,那么实现类就可以选择重写,也可以选择不重写。
静态的方法:其中public 可以省略,建议保留,但是static不能省略
在JDK1.9时,接口又增加了:
除此之外,接口中不能有其他成员,没有构造器,没有初始化块,因为接口中没有成员变量需要初始化。
接口的使用
接口的使用,它不能创建对象,但是可以被实现(implements
,类似于被继承)。类与接口的关系为实现关系,即类实现接口,该类可以称为接口的实现类,也可以称为接口的子类。实现的动作类似继承,格式相仿,只是关键字不同,实现使用 implements
关键字。
实现接口语法格式
注意:
如果接口的实现类是非抽象类,那么必须重写接口中所有抽象方法。如果一个类实现了继承了多个接口的接口 那么 不仅要实现 此接口的抽象方法 也要实现继承接口的抽象方法
一个类实现接口后 如果不想实现接口中的抽象方法 则 自己必须变为抽象类。
默认方法可以选择保留,也可以重写。重写时,default单词就不要再写了,它只用于在接口中表示默认方法,到类中就没有默认方法的概念了
不能重写静态方法
package demo02; public class DemoClass implements DemoInterface { @Override public void read() { System.out.println("我会读"); } @Override public void write() { System.out.println("我会写"); } }
如何调用对应的方法
对于接口的静态方法,直接使用“接口名.”进行调用即可。也只能使用“接口名."进行调用,不能通过实现类的对象进行调用
对于接口的抽象方法、默认方法,只能通过实现类对象才可以调用。接口不能直接创建对象,只能创建实现类的对象
package demo02; public class Test { public static void main(String[] args) { //创建实现类对象,多态 DemoInterface b = new DemoClass(); //通过实现类对象调用重写的抽象方法,以及接口的默认方法, // 如果实现类重写了就执行重写的默认方法,如果没有重写,就执行接口中的默认方法 b.start(); b.read(); //通过接口名调用接口的静态方法 DemoInterface.show(); } }
接口的多实现
之前学过,在继承体系中,一个类只能继承一个父类。而对于接口而言,一个类是可以实现多个接口的,这叫做接口的多实现。并且,一个类能继承一个父类,同时实现多个接口。
其他注意事项:
一个类可以先继承一个父类 再去实现多个接口 顺序不能改变
当一个类,既继承一个父类,又实现若干个接口时,父类中的成员方法与接口中的抽象方法重名,子类就近选择执行父类的成员方法
当一个类同时实现了多个接口,而多个接口中包含方法签名相同的默认方法时.。要么选择保留其中一个,通过“接口名.super.方法名"的方法选择保留哪个接口的默认方法,要么选择自己完全重写。
class C implements A,B{ @Override public void d() { A.super.d(); } }
一个接口能继承另一个或者多个接口,接口的继承也使用 extends
关键字,子接口继承父接口的方法。
实现类实现接口,类似于子类继承父类,因此,接口类型的变量与实现类的对象之间,也可以构成多态引用。通过接口类型的变量调用方法,最终执行的是你new的实现类对象实现的方法体。
我们知道基本数据类型的数据(除boolean类型外)需要比较大小的话,之间使用比较运算符即可,但是引用数据类型是不能直接使用比较运算符来比较大小的。那么,如何解决这个问题呢?Java给所有引用数据类型的大小比较,指定了一个标准接口,就是java.lang.Comparable接口:
public interface Comparable{ int compareTo(Object obj); }
那么我们想要使得我们某个类的对象可以比较大小,怎么做呢?步骤:
**第一步:**哪个类的对象要比较大小,哪个类就实现java.lang.Comparable接口,并重写方法。方法体就是你要如何比较当前对象和指定的另一个对象的大小
**第二步:**对象比较大小时,通过对象调用compareTo方法,根据方法的返回值决定谁大谁小。
this对象(调用compareTo方法的对象)大于指定对象(传入compareTo()的参数对象)返回正整数
this对象(调用compareTo方法的对象)小于指定对象(传入compareTo()的参数对象)返回负整数
this对象(调用compareTo方法的对象)等于指定对象(传入compareTo()的参数对象)返回零
案例:
声明一个Employee员工类,包含编号、姓名、薪资,实现Comparable接口,要求,按照薪资比较大小,如果薪资相同,按照编号比较大小。
package com.wrg.oop5; public class Employee implements Comparable { private int id; private String name; private double salary; public Employee(int id, String name, double salary) { super(); this.id = id; this.name = name; this.salary = salary; } public Employee() { 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; } public double getSalary() { return salary; } public void setSalary(double salary) { this.salary = salary; } @Override public String toString() { return "Employee [id=" + id + ", name=" + name + ", salary=" + salary + "]"; } @Override public int compareTo(Object o) { //这些需要强制,将o对象向下转型为Employee 类型的变量,才能调用Employee 类中的属性 Employee emp = (Employee) o; //排序规则 if(this.getSalary() != emp.getSalary()){ return Double.compare(this.getSalary(), emp.getSalary()); } return this.id - emp.id; } }
声明一个测试类TestEmployee类,在main中创建Employee[]数组,长度为5,并且存储5个员工对象,现在要求用冒泡排序,实现对这个数组进行排序,遍历结果。
package com.wrg.oop5; public class TestComparable { 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 = 1; i < arr.length; i++) { for (int j = 0; j < arr.length-i; j++) { //因为Employee类型实现了Comparable接口,所以有compareTo()方法 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]); } } }
**自定义一个数组工具类MyArrays,**它包含一个静态方法,可以给任意对象数组用冒泡排序实现从小到大排序,该怎么定义这个方法呢?
/** * 接收所有引用类型数据 * 通用的排序方法, * * @param objArr */ //实现了Comparable接口一定是其子类 public static void sort(Comparable[] objArr) {//Comparable arr = student; //冒泡排序 for (int i = 0; i < objArr.length - 1; i++) { for (int j = 0; j < objArr.length - 1 - i; j++) { //当前一个数大于后一个数 if (objArr[j].compareTo(objArr[j + 1]) > 0) { Comparable temp = objArr[j]; objArr[j] = objArr[j + 1]; objArr[j + 1] = temp; } } } }
如果一个类,没有实现Comparable接口,而这个类你又不方便修改(例如:一些第三方的类,你只有.class文件,没有源文件),那么这样类的对象也要比较大小怎么办?如果一个类,实现了Comparable接口,也指定了两个对象的比较大小的规则,但是此时此刻我不想按照它预定义的方法比较大小,但是我又不能随意修改,因为会影响其他地方的使用,怎么办?JDK在设计类库之初,也考虑到这种情况了,所以又增加了一个java.util.Comparator接口
public interface Comparator{ int compare(Object o1,Object o2); }
那么我们想要比较某个类的两个对象的大小,怎么做呢?步骤:
第一步:编写一个类,我们称之为比较器类型,实现java.util.Comparator接口,并重写compare方法。方法体就是你要如何指定的两个对象的大小
**第二步:**比较大小时,通过比较器类型的对象调用compare()方法,将要比较大小的两个对象作为compare方法的实参传入,根据方法的返回值决定谁大谁小。
o1对象大于o2返回正整数
o1对象小于o2返回负整数
o1对象等于o2返回零
/* 如何使用外部比较器比较: 外部比较器: 因为在 比较对象类的外面 新建了一个类专门用于比较 1.定义一个类 实现 Comparator接口 public class PersonSortOfAge implements Comparator {} 2.重写compare()传递两个参数 3.制定比较规则 4.先去创建 比较规则的对象 # 最后总结 ## ActiveMQ+Kafka+RabbitMQ学习笔记PDF ![image.png](https://www.www.zyiz.net/i/ll/?i=img_convert/a571de6e16a673744c81f4d5a9ff13d2.png) * ### RabbitMQ实战指南 ![image.png](https://www.www.zyiz.net/i/ll/?i=img_convert/7c25c504f090c3248a54e76e3c87081f.png) * ### 手写RocketMQ笔记 ![image.png](https://www.www.zyiz.net/i/ll/?i=img_convert/f1c25f3af6b2e3e4ccbe7acb34d65a58.png) * ### 手写“Kafka笔记” ![image](https://www.www.zyiz.net/i/ll/?i=img_convert/0bdb34f66f242377af352f1789bba63e.png) 关于分布式,限流+缓存+缓存,这三大技术(包含:ZooKeeper+Nginx+MongoDB+memcached+Redis+ActiveMQ+Kafka+RabbitMQ)等等。这些相关的面试也好,还有手写以及学习的笔记PDF,都是啃透分布式技术必不可少的宝藏。以上的每一个专题每一个小分类都有相关的介绍,并且小编也已经将其整理成PDF啦 sonSortOfAge implements Comparator {} 2.重写compare()传递两个参数 3.制定比较规则 4.先去创建 比较规则的对象 # 最后总结 ## ActiveMQ+Kafka+RabbitMQ学习笔记PDF [外链图片转存中...(img-Hfy9AS0V-1628224994169)] * ### RabbitMQ实战指南 [外链图片转存中...(img-ZWpjp2cg-1628224994171)] * ### 手写RocketMQ笔记 [外链图片转存中...(img-DeSoqKkQ-1628224994173)] * ### 手写“Kafka笔记” [外链图片转存中...(img-x9ufpzqQ-1628224994175)] 关于分布式,限流+缓存+缓存,这三大技术(包含:ZooKeeper+Nginx+MongoDB+memcached+Redis+ActiveMQ+Kafka+RabbitMQ)等等。这些相关的面试也好,还有手写以及学习的笔记PDF,都是啃透分布式技术必不可少的宝藏。以上的每一个专题每一个小分类都有相关的介绍,并且小编也已经将其整理成PDF啦 **[资料领取方式:戳这里免费领取](https://gitee.com/vip204888/java-p7)**