Java基础之:OOP——接口
Java基础之:OOP——接口
usb插槽就是现实中的接口,可以把手机,相机,u盘都插在usb插槽上,而不用担心那个插槽是专门插哪个的,原因是做usb插槽的厂家和做各种设备的厂家都遵守了统一的规定包括尺寸,排线等等。
而在java中我们也可以实现类似这样的功能。
简单案例
package class_interface; public class Class_Test { public static void main(String[] args) { Computer computer = new Computer(); //使用USB接口,多态传入 //1. 在java中, 允许 将一个实现了某个接口的 类的对象,传递给该接口的一个引用 //2. 在接口使用过程中,仍然遵守我们的多态和动态绑定机制 computer.work(new Phone()); //匿名对象做传入参数 computer.work(new U_disk()); } } class Computer{ //Computer类使用了USB接口 public void work(USB usb) { //输入参数实现接口的多态 usb.start(); usb.stop(); } } //声明一个接口使用 interface 关键字 interface USB{ //对于接口内写的所有方法而言,都是默认带有abstract关键字修饰的,即抽象方法 public void start(); public void stop(); //在jdk8.0之后,接口中也可以实现方法,但必须是静态方法与默认方法,例如: //因为可能会出现一个接口我们会频繁的使用,且对于接口中的某一个方法都实现一样的作用。 //那么在接口中实现静态/默认方法后,在实现接口的类中,直接调用此方法即可。不需要再重写实现此方法 default public void hi() { System.out.println("say hi...."); } public static void hello() { System.out.println("say hello...."); } } //实现一个接口使用 implements 关键字,接口与抽象类很类似 //实现了接口的类,也需要实现接口中的所有抽象方法 class Phone implements USB{ @Override public void start() { System.out.println("手机开始工作...."); } @Override public void stop() { System.out.println("手机停止工作...."); hi(); } } class U_disk implements USB{ @Override public void start() { System.out.println("U盘开始工作...."); } @Override public void stop() { System.out.println("U盘停止工作...."); } }
程序输出
手机开始工作....
手机停止工作....
say hi....
U盘开始工作....
U盘停止工作....
接口介绍
接口就是将没有实现的抽象方法放在一起,当有类需要使用这些方法时,则根据实际情况将这个方法实现出来。
声明语法:
创建接口
interface 接口名{
//属性
//抽象方法
}
使用接口
class 类名 implements 接口名{
//类自己的属性
//类自己的方法
//必须实现接口中的抽象方法
}
小结:接口是更加抽象的抽象的类,抽象类里的方法可以有方法体,接口里的所有方法都没有
方法体。
接口使用细节
1) 接口不能被实例化
2) 接口中所有的方法是 public方法, 接口中抽象方法,可以不用abstract 修饰
3) 一个普通类实现接口,就必须将该接口的所有方法都实现。
4) 抽象类实现接口,可以不用实现接口的方法。
5) 一个类同时可以实现多个接口
6) 接口中的属性,只能是final的,而且是 public static final 修饰符。比如: int a=1; 实际上是 public static final int a=1; (必须初始化)
7) 接口中属性的访问形式: 接口名.常量名
8) 一个接口不能继承其它的类,但是可以继承多个别的接口
9) 接口的修饰符 只能是 public 和默认,这点和类的修饰符是一样的。
细节案例
package class_interface; public class InterfaceDetail { public static void main(String[] args) { } } //接口命名习惯: 大写I + 接口名 , 例如:IUser interface IA{ public void m1(); public void m2(); } interface IB{ public void m1(); public void m3(); } //细节1.一个普通类实现接口,就必须将该接口的所有方法都实现。 class CA implements IA{ @Override public void m1() { } @Override public void m2() { } } //细节2.抽象类实现接口,可以不用实现接口的方法。 abstract class CB implements IA{ //这点很容易理解,因为抽象类中允许继承下来的抽象方法不进行重写实现。 } //细节3:一个类同时可以实现多个接口 ,且必须实现多个接口中的所有抽象方法 //这里我们会发现,IA与IB接口中,m1()方法重名了,但在CC类中实现并没有报错。 //理解:因为m1()方法,仅是接口定义的一个规范,需要类来实现这个规范,而我们只要实现了m1()方法,则IA与IB接口可以使用 class CC implements IA,IB{ @Override public void m3() { } @Override public void m1() { } @Override public void m2() { } } //细节4:接口中的属性,只能是final的,而且是 public static final 修饰符。 //比如: int a=1; 实际上是 public static final int a=1; (必须初始化) interface IC{ int a = 1; // private int b = 2; /* * 这里使用private声明之后,报错: * Illegal modifier for the interface field IC.b; only public, static & final are permitted */ } //细节5:接口中属性的访问形式: 接口名.常量名 class CD implements IC{ //这点也很好理解,因为属性a是默认被static修饰的,所以只能使用接口名访问 public void say() { System.out.println(IC.a); } } //细节6:一个接口不能继承其它的类,但是可以继承多个别的接口 interface ID extends /*CD*/ IA,IB,IC{ //如果继承CD类的话,报错: //The type CD cannot be a superinterface of ID; a superinterface must be an interface /* * 这点容易出现混淆,因为我们之前说Java是单继承的,但接口这里好像又出现了多继承的情况 * 我们可以这样理解,电脑通过USB接口连接上了USB转换器,通过USB转换器,我们连接上了读卡器 * 那么就说,USB接口通过继承USB连接器扩展了可以连接读卡器的功能。 * 所以对于接口的继承而言,并不像是父类与子类的关系,而是使用继承机制,扩展单个接口的功能。 */ } //细节7:接口的修饰符 只能是 public 和默认,这点和类的修饰符是一样的。 /*private*/ interface IE { /* * 使用private 报错:Illegal modifier for the interface IE; only public & abstract are permitted * 这里可以看到只能使用public与abstract修饰,当然也可以不修饰(即默认)。 * 而使用abstract修饰又显得有一些多余,因为接口本来就是抽象的概念。 */ }
实现接口与继承父类之间的区别
继承的价值主要在于:解决代码的复用性和可维护性。
接口的价值主要在于:设计,设计好各种规范(方法),让其它类去实现这些方法。
接口比继承更加灵活,继承是满足 is - a的关系,而接口只需满足 like - a的关系。
接口在一定程度上实现代码解耦。
简单案例
package class_interface; public class ImplementsVSExtends { /* * 讨论实现接口 与 继承类,到底有什么样的区别 * 虽然两者都具有实现功能扩展的能力 */ public static void main(String[] args) { /* * 可以看到这里 对象a 即能够使用 父类 Person中的eat也能够使用接口IFish中的swimming * 但我们可以这样理解,为什么要使用接口来定义swimming方法。 * 人类与生俱来的能力就一定会吃东西,但游泳并不是与生俱来的能力。即继承Person * 那么运动员为了拥有游泳的能力就去向小鱼学习,即实现接口IFish。 * * 总结: * 继承:父类是通过子类扩展其已有的方法与功能。 * 实现:类通过接口扩展类所需要的方法与功能。 */ Athletes a = new Athletes("小范"); a.eat(); a.swimming(); } } class Person{ private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public Person(String name) { super(); this.name = name; } public void eat() { System.out.println(name + "吃东西...."); } } interface IFish{ public void swimming(); } class Athletes extends Person implements IFish{ public Athletes(String name) { super(name); } @Override public void swimming() { System.out.println(getName() + "游泳....."); } }
程序输出
小范吃东西....
小范游泳.....
接口的多态特性
在前面的Usb接口案例,Usb usb ,既可以接收手机对象,又可以接收U盘对象,就体现了 接口 多态 (接口引用可以指向实现了接口的类的对象)
简单案例
演示一个案例:给Usb数组中,存放 Phone 和 相机对象,Phone类还有一个特有的方法call(),请遍历Usb数组,如果是Phone对象,除了调用Usb 接口定义的方法外,还需要调用Phone 特有方法 call。以及U盘的特有方法read。
package class_interface.InterfacePolyArray; public class InterfacePolyArray { public static void main(String[] args) { USB[] u = new USB[2]; u[0] = new Phone(); u[1] = new U_disk(); for (int i = 0; i < u.length; i++) { work(u[i]); } } public static void work(USB usb) { //输入参数实现接口的多态 usb.start(); usb.stop(); if(usb instanceof Phone) { ((Phone) usb).call(); }else if(usb instanceof U_disk) { ((U_disk) usb).read(); } } } interface USB{ public void start(); public void stop(); } class Phone implements USB{ @Override public void start() { System.out.println("手机开始工作...."); } @Override public void stop() { System.out.println("手机停止工作...."); } public void call() { System.out.println("手机开始打电话......"); } } class U_disk implements USB{ @Override public void start() { System.out.println("U盘开始工作...."); } @Override public void stop() { System.out.println("U盘停止工作...."); } public void read() { System.out.println("U盘开始读取数据....."); } }
程序输出
手机开始工作....
手机停止工作....
手机开始打电话......
U盘开始工作....
U盘停止工作....
U盘开始读取数据.....
接口的多态传递
接口的多态传递解读:
当一个类实现了某个接口
这个类的对象可以赋给该接口的引用
如果这个类被继承,那么这个类的子类的对象,也可以赋给该接口的引用
如果这个接口是继承来的,那么这个对象也可以赋给该接口的上层接口的引用
不限于一级,可以多级传递.
简单案例
package class_interface.InterfacePolymorphicPass; /** 下面程序的继承关系: IC 继承于 IB ,IB 继承于 IA CA 实现了接口 IC,CB 继承于 CA show方法的实际传入参数: 传入参数是IC时,可以识别CA与CB的对象 ,因为CA实现了IC 且 CB继承于CA 而传入参数是IA时,也可以识别CA与CB的对象,因为CA实现的IC是继承于IA的(子类对象可以赋值给父类引用)。 */ public class InterfacePolymorphicPass { public static void main(String[] args) { CA ca = new CA(); CB cb = new CB(); show(ca); show2(ca); show3(ca); System.out.println("================="); show(cb); show2(cb); show3(cb); } public static void show(IC ic) { ic.m4(); } public static void show2(IB ib) { ib.m3(); } public static void show3(IA ia) { ia.m1(); ia.m2(); } } interface IA{ void m1(); void m2(); } interface IB extends IA{ void m3(); } interface IC extends IB{ void m4(); } class CA implements IC{ @Override public void m1() { System.out.println("CA--IA--m1"); } @Override public void m2() { System.out.println("CA--IA--m2"); } @Override public void m3() { System.out.println("CA--IB--m3"); } @Override public void m4() { System.out.println("CA--IC--m4"); } } class CB extends CA{ @Override public void m3() { System.out.println("CB--IB--m3"); } @Override public void m4() { System.out.println("CB--IC--m4"); } }
程序输出
CA--IC--m4
CA--IB--m3
CA--IA--m1
CA--IA--m2
============
CB--IC--m4
CB--IB--m3
CA--IA--m1
CA--IA--m2