接口
接口
1. 概念
- 是一种标准、规范,是接口的使用者和接口的实现者都必须遵循的约定和规范。
2. 接口相当于一个特殊的抽象类
-
语法(基于JDK7.0版本)
- 关键字
interface
- 关键字
interface 接口名{}
- 接口在编译之后会生成独立的 .class 文件
- 接口不能创建对象,但是可以声明引用
接口名 变量名;
- 接口中属性都是公开、静态、常量(默认被
public static final
修饰) - 接口中的方法都是公开、抽象方法(默认被
public abstract
修饰) - 接口中没有构造方法
注意
接口从语法角度是一个抽象类,是对抽象类进一步的抽象;
接口从Java分类来看,不是类
//抽象类
/*
抽象类不能单独new对象,但可以声明引用
抽象类:编译后生成独立的 .class文件
*/
abstract class MyClass{
int a=1;//实例变量
static int b=2;//静态变量
}
mian(){
//接口类型的引用-->实现类的对象
MyInter mi=new MyClass();//多态
mi.m1();
mi.m2();
}
//接口:共语法角度,相当于特殊的抽象类
interface MyInter{ //定义MyInter接口
int m=1; //实例变量,默认被static修饰,同时被final修饰
static int n=2; //静态变量,默认被final修饰
public void m1(); //默认被abstract修饰
void m2(); //默认被public abstract修饰
}
3. 实现类
- 实现类语法
class 类名 implements 接口名{
public void m1(){//方法
syso();
}
}
- 注意
- 如果实现类不想成为抽象类,则必须覆盖接口中所有的抽象方法,同时给予实现,否则实现类也必须定义为抽象类
- 对接口中方法默认的访问权限为public,所以实现类覆盖接口中的方法时访问修饰符也是public。
- 因为类中方法如果不写访问修饰符。默认的访问权限是default
- 使用
接口类型的引用中可以存储实现类的对象,多态的应用 - 接口的使用语法
接口名 引用 = new 实现类类名(实参);
注意
如果以接口类型的引用调用方法,只能调用接口中有的方法
- 案例
public class TestInter{
public static void main(String[] args){
// 接口类型的引用 --》 实现类的对象
MyInter mi = new MyClass(); // 多态
mi.m1();
mi.m2();
//mi.m3();
}
}
// 接口
interface MyInter{
public void m1();// 默认被abstract修饰
void m2(); //默认被public abstract修饰
}
// 接口的实现类(从语法角度:类继承一个特殊的抽象类)
class MyClass implements MyInter{
public void m1(){
System.out.println("m1方法的实现....");
}
public void m2(){
System.out.println("m2方法的实现....");
}
public void m3(){}
}
4. java中接口的继承性
4.1 接口之间的继承性
- 接口与接口之间是多继承
- 语法
interface 接口名 extends 父接口1,父接口2{}
4.2 类和接口之间的关系
- 类和接口是实现关系,即一个类可以实现多个接口
- 语法
class 类名 implements 接口名1,接口名2{}
- 注意
如果实现类不想成为抽象类,必须覆盖所有接口中的所有方法
4.3 父类、子类和接口的关系
- 一个类继承一个父类的同时可以实现多个接口
- 语法
class 类名 extends 父类 implements 接口名1,接口名2{}
- 注意
必须先定义继承,再定义实现类
5. 接口多继承的影响
-
让多态的应用更加的复杂和多样性。
-
如果强制类型转换的双方有一方是接口类型,编译一定通过,运行有以下两种情况
- 如果实际存储对象类型和要转换的类型相兼容,则运行通过;
- 如果实际存储对象类型和要转换的类型不兼容,则运行报错,错误信息为:
java.lang.ClassCastException
(类型转换异常)注意
评判是否兼容:实际存储的对象类型是否为要转换类型一种
-
案例
public class Test6{
public static void main(String[] args){
MyClass mc = new MyClass();
/*System.out.println(mc instanceof ClassA);
System.out.println(mc instanceof IA);
System.out.println(mc instanceof IB);
System.out.println(mc instanceof IC);
System.out.println(mc instanceof ID);*/
/*IA ia = mc;
ia.m1();
ia.m2();
//ia.m3();*/
/*IB ib = mc;
ib.m3();*/
/*IC ic = mc;
ic.m1();
ic.m2();
ic.m3();
ic.m4();*/
/*ID id = mc;
id.m5();*/
ClassA ca = mc;
ca.m6();
}
}
interface IA{
void m1();
void m2();
}
interface IB{
void m3();
}
interface IC extends IA,IB{
void m4();
}
interface ID{
void m5();
}
// 类和接口的多实现
class MyClass extends ClassA implements IC,ID {
public void m1(){
System.out.println("m1()...");
}
public void m2(){
System.out.println("m2()...");
}
public void m3(){
System.out.println("m3()...");
}
public void m4(){
System.out.println("m4()...");
}
public void m5(){
System.out.println("m5()...");
}
}
class ClassA{
public void m6(){
System.out.println("m6()...");
}
}
6. 接口的应用场景
6.1 利用接口扩充子类的能力
- 子类之间是单继承,当子类通过继承关系,从父类继承的功能不满足子类的功能需求时,可以利用接口扩充子类的功能需求。
- 通常将主要功能定义在父类中,相对次要功能定义接口中
6.2 依赖倒转原则
- 当一个类和其他类建立联系时,尽可能和父类是接口建立联系,避开直接与其子类或是实现类建立联系
- 降低代码之间的耦合度,从而实现弱耦合
- 提高程序的可维护性
- 案例
public class TestComputer{
public static void main(String[] args){
// 创建电脑对象
Computer c = new Computer();
// 创建鼠标对象
//Mouse m = new Mouse();
//Keyboard k = new Keyboard(); // 实现类 对象对象
//Mouse m = new Mouse();
Fan f = new Fan();
c.useDevice(f);
}
}
// A类 --》使用者
class Computer{
// 鼠标
public void useDevice(USB usb){ //USB usb = f; --->体现的多态
usb.service();
}
}
// 对电子设备 和 电脑做一个标准和规范(接口)
interface USB{
void service();
}
// 实现类
// B类
class Mouse implements USB{
public void service(){
System.out.println("咔嚓...");
}
}
// C类
class Keyboard implements USB{
public void service(){
System.out.println("噼里啪啦...");
}
}
// D类
class Fan implements USB{
public void service(){
System.out.println("呼呼的...");
}
}
7. 接口回调
- 理解
将接口对应的实现类对象作为实际参数赋值给接口类型的引用,当接口类型的引用地哦啊用方法时,实际运行的是对应实现类中的方法(覆盖),实现类作为实际参数传递给引用类型,目的是让借口的使用者完成对应的功能,这种现象称为接口回调。 - 使用场景
通常接口制定好之后,接口的使用者先被定义,根据需求的不同,再定义接口的实现者(先有接口的使用者,再有接口的实现者),开发时一旦出现接口回调的现象,作为开发人员,通常关注的根据需求定义接口的实现类,无需关注接口的使用者。 - 案例
import java.util.Scanner;
public class Test_13{
public static void main(String[] args){
// 项目的整合
MathTool mt = new MathToolImpl();
MyClass mc = new MyClass(mt);
mc.chaiFen();
}
}
// 模块一:将一个 大于 6偶数进行拆分,列举出所有拆分结果,验证是否为质数(接口的使用者)
class MyClass{
private MathTool mt;
public MyClass(MathTool mt ){ // MathTool mt = new MathToolImpl();-->多态
this.mt=mt;
}
public void chaiFen(){
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个大于6的偶数:");
int n = sc.nextInt();
if(n>6 && n%2==0){
// 用循环变量控制 拆分前一项
for(int i=2;i<=n/2;i++){
// 拆分前一项为 i ;后一项为 n-i
// 验证 i 和 n-i是否为 质数
if(mt.isPrime(i) && mt.isPrime(n-i)){
System.out.println(n+"="+i+"+"+(n-i));
}
}
}else{
System.out.println("输入不合理....");
}
}
}
// 接口:制定模块一和模块二之间的标准
interface MathTool{
boolean isPrime(int n);
}
// 模块二: 判断一个数据是否为质数 -->接口的实现者
class MathToolImpl implements MathTool{
public boolean isPrime(int n){
System.out.println("~~~~~~~1~~~~~~~");
for(int i=2;i<n;i++){
if(n%i==0){
return false;
}
}
return true;
}
}
// 实现类:判断一个数据是否为 偶数
//如需使用此类,则必须将main()方法中的内容进行修改
class MathToolImpl2 implements MathTool{
public boolean isPrime(int n){
System.out.println("~~~~~~~~~~2~~~~~~~~~~~~~");
if(n%2==0){
return true;
}else{
return false;
}
}
}
- 案例:利用接口回调对学生按年龄进行排序
public class TestStudent{
public static void main(String[] args){
// 定义 一个 Student类型数组
Student[] ss = {
new Student("张三",18,99.0),
new Student("李四",38,89.0),
new Student("王五",35,78.0),
new Student("陆六",17,97.0)
};
// 对学生数组进行排序(按照什么进行排序)
java.util.Arrays.sort(ss);
for(int i=0;i<ss.length;i++){
System.out.println(ss[i].name+"\t"+ss[i].age+"\t"+ss[i].score);
}
}
}
class Student implements Comparable<Student>{
String name;
int age;
double score;
public Student(){}
public Student(String name,int age,double score){
this.name = name;
this.age = age;
this.score = score;
}
// 制定排序规则(按照 age)
public int compareTo(Student s){
/*
将 当前对象 和 指定的对象进行比较
this s
this.age 小于 s.age 负数,通常为 -1
this.age 等于 s.age 0
this.age 大于 s.age 正数 通常为 1
*/
if(this.age < s.age ){
return -1;
}else if(this.age > s.age){
return 1;
}else {
return 0;
}
}
}
8. 接口和抽象类的区别小结
抽象类 | 接口 | |
---|---|---|
关键字不同 | abstract class | interface |
extends(类继承抽象类) | implements(类实现接口) | |
属性 | 实例变量 静态变量 4个访问修饰符可以用于修饰属性 | 公开静态常量 |
方法 | 抽象方法 普通成员方法 | 抽象方法 静态方法(JDK8.0) 默认方法,带方法实现 私有方法(JDK9.0) |
构造方法 | 有 | 无 |
继承关系 | 单继承 | 多继承 |
9. 接口的分类【了解】
9.1 常量接口
- 接口中只有公开静态常量,没有定义任何方法
应用不广泛
9.2 标记接口
- 空接口,接口中没有定义任何的常量,也没有 定义任何的 方法,例如IO中对象序列化
9.3 普通接口
- 具有至少定义一个抽象方法。–》开发广泛应用
9.4 函数式接口
- 是一种特殊的普通接口,接口中只有一个抽 象方法,对静态方法和默认方法没有要求
10. JDK高版本对接口语法升级 【了解】
10.1 JDK8.0版本接口的升级内容
- 可以定义默认方法:
- 语法:
default 返回值类型 方法名(形参列表){}
注意
接口中默认方法中的default不再是访问修饰符,代表此方法可以写方法的实现部分
接口中默认方法访问权限为public
- 可以定义静态方法:
- 语法
public static 返回值类型 方法名(形参列表){}
注意
接口中静态方法默认访问权限也是 public,可以省略
- 使用
接口名.静态方法名(实参);
10.2 JDK 9.0版本接口中升级
- 可以定义 私有方法
- 语法:
private 返回值类型 方法名 (形参列表){}
整理不易,喜欢请点个赞!
编者微信:1014961803,添加时请备注"CSDN"