5.11 接口
- 参考书籍:Java面向对象程序设计(第二版)--耿祥义 张跃平编著
- 内容有接口的声明和使用,接口的理解,接口的回调,接口与多态,abstract类和接口的比较
一:接口的声明和使用
因为Java不支持多继承性,即一个类只能有一个父类
为了克服单继承的缺点,Java使用接口,一个类可以实现多个接口
- 接口的声明
格式: interface 接口名字
- 接口体
接口体分为常量定义和接口定义
接口体的规则:
- 接口体只有抽象方法
- 接口体中所有常量的访问权限都是public(允许省略public,final修饰符)
- 接口体中所有抽象方法的访问权限都是public(允许省略public,final修饰符)
package lianxi4;
interface Computable {
public final int a=100; //等价写法:int a=100;
public abstract void b(); //等价写法:void b();
public abstract float c(float x,float y);
}
- 接口的使用
一个类通过使用关键字implements声明自己实现一个或多个接口。
如果实现多个接口,用逗号隔开接口名字
注意(重要)
- 一个类实现某个接口,这个类要重写这个接口的所有方法
- 重写接口方法的时候,接口中的方法一定是public abstract方法,所以类在重写接口方法时不仅要去掉abstract修饰,给出方法体,而且方法的访问权限一定要明显地用public来修饰(否则就降低了访问权限)
- Import java.io.*; 不仅引入了java.io包中的类,也引入了该包中的接口。
- 用户可以自己定义接口,一个Java源文件就是由类和接口组成的。
案例:同一个包
Computable接口
package lianxi5;
public interface Computable {
int MAX=99; //常量,等价于public final int MAX=100;
final int b=1; //常量
int f(int x);
}
China类,调用了接口Computable
package lianxi5;
public class China implements Computable{ //China类调用接口Computable
int number;
int c=1;
public int f(int x){ //不能忘记public关键字
return x;
}
}
主类
package lianxi5;
public class Lianxi5 {
public static void main(String args[]){
China china=new China();
/* Computable xx=new Computable();*/ //接口不能这样玩
//接口的常量
System.out.println("Computable"+Computable.MAX); //接口名字可以调用该接口的常量
System.out.println(Computable.b);
System.out.println("China"+China.MAX); //声明了这个接口的类的类名能调用这个接口的常量
System.out.println(China.b);
System.out.println("china"+china.MAX);
System.out.println(china.b); //声明了这个接口的类的对象能调用这个接口的常量,变量下面有波浪线
//@SuppressWarnings("static-access") //@预设警告("静态访问"),可以去掉波浪线
//接口的方法
//因为接口的方法都是抽象方法,所以不能调用
//声明了这个接口的类的常量
System.out.println("china"+china.c); //这个类的对象可以调用,接口名字和类名不可以
//声明了这个接口的类重写的方法(接口是抽象方法,要重写)
System.out.println("china"+china.f(1)); //这个类的对象可以调用,接口名字和类名不可以
}
}
案例:不同包,接口在上一个案例的包中
Japan类
package kuabao;
import lianxi5.Computable;
public class Japan implements Computable{ //Japan类调用接口Computable
int y; //不赋值,直接输出是0
int z=1;
public int f(int p){ //不能忘记public关键字,重写是方法名字,参数个数,参数类型一致
return p;
}
}
主类
package kuabao;
import lianxi5.Computable;
public class Lianxi6 {
public static void main(String args[]){
Japan japan=new Japan();
/* Computable xx=new Computable();*/ //接口不能这样玩
//接口的常量
System.out.println("Computable"+Computable.MAX); //接口名字可以调用该接口的常量
System.out.println(Computable.b); //附加:要导包import lianxi5.Computable;
System.out.println("Japan"+Japan.MAX); //声明了这个接口的类的类名能调用这个接口的常量
System.out.println(Japan.b);
System.out.println("japan"+japan.MAX);
System.out.println(japan.b); //声明了这个接口的类的对象能调用这个接口的常量,变量下面有波浪线
//@SuppressWarnings("static-access") //@预设警告("静态访问"),可以去掉波浪线
//接口的方法
//因为接口的方法都是抽象方法,所以不能调用
//声明了这个接口的类的常量
System.out.println("japan"+japan.y); //这个类的对象可以调用,接口名字和类名不可以
//声明了这个接口的类重写的方法(接口是抽象方法,要重写)
System.out.println("japan"+japan.f(1)); //这个类的对象可以调用,接口名字和类名不可以
}
}
注意(重要)
(1)声明接口时,如果关键字interface前加上public关键字,就称这个接口是public接口,public接口可以被任何一个类声明实现
(2)如果一个接口不加public修饰,就称为友好接口,友好接口可以被与该接口在同一个包中的类声明实现
(3)如果父类实现了这个接口,子类也就实现这个接口了,子类不用显式地使用关键字implements声明实现这个接口
(4)接口也可以被继承,即可以通过关键字extends声明一个接口是另外一个接口的子接口。由于接口中的方法和常量都是public的,子接口将继承父接口中所有方法和常量。
(5)如果一个类声明实现一个接口,但没有重写接口中的所有方法,那么这个类一定是abstract类
比如:
A类
package lianxi6;
interface A {
final int a=10;
void speak(String s);
int f(int x);
float g(float x,float y);
}
B类
package lianxi6;
abstract class B implements A{ //抽象类
public int f(int x){ //只重写了一个方法
return x+1;
}
}
二:接口的理解
如果A,B,C都是ZM的子类,其中ZM是一个抽象类
如果ZM有“我”,“你”,“他”三个抽象方法,那么所有的子类都要重写这三个抽象方法,即各自给出方法体,产生各自的行为
显然这不符合我们的思维逻辑
因为可能C类不用“你”,“他”的功能或者是不需要
接口可以增加很多类都需要的功能
不同的类可以实现相同的接口,同一个类也可以实现多个接口
当一个类不希望通过继承使自己具有某个方法时,可以考虑接口,而不是把自己声明为某个类的子类
接口只关心操作(即方法),不关心操作的具体实现
三:接口的回调
接口回调是指把实现某一接口的类创建的对象的引用赋给该接口声明的变量中,那么该接口变量就可以调用被类重写的接口方法
有点类似上转型对象调用子类的重写方法
例子:
ShowMessage 接口
package lianxi5;
interface ShowMessage {
/* int b;*/ //接口中不能直接声明变量
void a(String s);
}
Tv类,调用了ShowMessage 接口
package lianxi5;
class Tv implements ShowMessage{
public void a(String s){
System.out.println(s);
}
}
主类
package lianxi5;
public class Lianxi5 {
public static void main(String args[]){
ShowMessage sm; //声明接口变量
sm=new Tv(); //接口变量中存放对象的引用
sm.a("chy"); //接口回调,调用子类重写的方法
}
}
四:接口与多态
有了接口回调的基础,由接口产生的多态就是不同的类在实现同一个接口时可能具有不同的实现方式,那么接口变量在回调接口方法时就可能具有多种形态
案例:设计一个广告牌,展示许多公司的广告词
A类
package lianxi5;
public interface A { //接口
public void showA(); //展示A,抽象方法
public String getA(); //获得A,抽象方法
}
Show类
package lianxi5;
public class Show { //用来展示的
public void show(A a){ //接口A声明变量a
System.out.println("广告牌显示:"+a.getA()+"公司");
a.showA();
}
}
Cool类(Cool公司)
package lianxi5;
public class Cool implements A{
public void showA(){
System.out.println("选我们就是那么好");
}
public String getA(){
return "chy";
}
}
主类
package lianxi5;
public class Lianxi5 {
public static void main(String args[]){
Show show=new Show();
show.show(new Cool()); //Cool的对象的引用放进了变量a里面,可以调用Cool类重写接口的方法
}
}
结果是:
广告牌显示:chy公司
选我们就是那么好
五:abstract与接口
- 两者都可以有abstract方法
- 接口没有变量,abstract类既有常量也有变量
- abstract类可以有非abstract方法,接口不可以有
分析:abstract类给子类提供了抽象方法外,还提供了可以继承的变量和非抽象方法,具体问题具体分析