接口
接口的基础语法
- 接口是一种引用数据类型,编译后生成字节码文件。
- 接口是完全抽象的(类是半抽象的),或者说接口是一种特殊的抽象类。
- 接口与接口之间支持多继承。
- 接口中只包含常量和抽象方法(java7之前(包括7))。
- 接口中所有的元素都是被public修饰的。
- 接口中的抽象方法在定义时可以省略"public abstract"。
- 接口中的常量在定义时可以省略"public static final"。
- 一个非抽象类实现了接口,要求这个类重写接口中所有的抽象方法(抽象类可以不重写)
- 一个类可以实现多个接口
- extends和implements可以共存,语法格式是:[修饰符列表] 类名 extends 类名 implement 接口名{}
- 接口的定义:[修饰符列表] 接口名 {}
向下转型问题
类与类之间的向下转型
- 要求类与类之间必须有继承关系,没有继承关系编译器会报错
- 如果两个类之间有继承关系可以通过编译期,但是在运行期也可能出现ClassCaseException
public class Test2 {
public static void main(String[] args){
D d = new A();
B b = (B)d;
}
}
class A extends D{}
class B extends D{}
class D{}
在编译期,编译器检测到D的子类有A和B。所以将D类型的d转换成B类型编译器会认为是合法的(骗过编译器)。但是在运行期检测到d实际是A类型,而A类型与B类型没有继承关系(A不是B),无法转换。所以在此处抛出CaseException
接口与接口之间的向下转型
接口与接口之间没有继承关系也可以进行转型,只不过会在运行期可能会出现ClassCaseException
public class Test3 {
//接口与接口之间的转型
public static void main(String[] asrgs){
D d = new A();
E e = new B();
E e2 = (E)d;
}
}
class A implements D{public void method1(){}}
class B implements E{public void method2(){}}
interface D{void method1();}
interface E{void method2();}
运行结果如下,可以看出接口与接口之间没有继承关系可以通过编译期,但是在运行期间可能会出现ClassCaseException
在编译期,编译器检查到d是D类型;在运行期,检测到d实际是A类型,而A类型与E类型没有实现关系(A不像E),所以此处会出现异常。那么如果A类型与同时与D类型和E类型有实现关系在运行期间就不会出现ClassCase异常么,我们来看以下代码
public class Test3 {
//接口与接口之间的转型
public static void main(String[] asrgs){
D d = new A();
E e = new B();
E e2 = (E)d;
}
}
class A implements D,E{
public void method1(){}
public void method2(){}
}
class B implements E{public void method2(){}}
interface D{void method1();}
interface E{void method2();}
运行结果如下,可以看出如果一个类同时实现了多个接口,哪怕这些接口之间没有继承关系,这些接口之间也能彼此进行转型,同时能通过编译期和运行期
当然这么转型后实现类只能调用转型后接口中的方法,否则无法通过编译期,具体我们可以看下面的代码
public class Test3 {
//接口与接口之间的转型
public static void main(String[] asrgs){
D d = new A();
E e = new B();
E e2 = (E)d;
e2.method1();
}
}
class A implements D,E{
public void method1(){}
public void method2(){}
}
class B implements E{public void method2(){}}
interface D{void method1();}
interface E{void method2();}
类与接口之间的向下转型
- 如果类与接口之间没有实现关系编译期会报错
- 如果类与接口之间有实现关系,在运行期间可能会出现ClassCaseException
public class Test3 {
//类与接口之间的向下转型
public static void main(String[] asrgs){
E e = new A();
B b = (B)e;
}
}
class A implements D,E{
public void method1(){}
public void method2(){}
}
class B implements E{public void method2(){}}
interface D{void method1();}
interface E{void method2();}
interface F{}
抽象类与接口的区别
- 抽象类是半抽象的,接口时完全抽象的
- 抽象类中有构造方法,接口中不能有构造方法
- 接口与接口之间支持多继承,类与类之间只支持单继承
- 一个类可以实现多个接口,但一个类只能继承一个类
- 接口中只允许有常量和抽象方法(java7之前)
不同版本接口的特性
接口在开发中的作用
面向接口编程,降低程序之间的耦合度,提高程序的扩展力
面向接口开发案例
用接口模拟一个人去餐馆点餐场景,接口(菜单),接口的实现类(厨师),接口的调用者(客户)
//顾客
class Customer {
FoodMenu foodMenu; //菜单
public void order () {
foodMenu.xiHongShi();
foodMenu.rouSi();
}
public Customer(){}
public Customer(FoodMenu foodMenu){
this.foodMenu = foodMenu;
}
}
//菜单
interface FoodMenu{
//西红柿炒鸡蛋
void xiHongShi();
//香辣肉丝
void rouSi();
}
//中国厨师
class ChinaCook implements FoodMenu {
public void xiHongShi() {
System.out.println("中国厨师做的西红柿炒鸡蛋");
}
public void rouSi() {
System.out.println("中国厨师做的香辣肉丝");
}
}
//美国厨师
class AmericaCook implements FoodMenu {
public void xiHongShi() {
System.out.println("美国厨师做的西红柿炒鸡蛋");
}
public void rouSi() {
System.out.println("美国厨师做的香辣肉丝");
}
}
public class Test {
public static void main(String[] args) {
//厨师
FoodMenu cook1 = new AmericaCook();
FoodMenu cook2 = new ChinaCook();
//顾客找美国厨师
Customer customer = new Customer(cook1);
customer.order();
//顾客找中国厨师
customer.foodMenu = cook2;
customer.order();
}
}
通过上面的代码可以看出,通过接口(FoodMenu),降低了类(Customer)与类(AmericaCook/ChinaCook)之间的耦合度,程序的扩展力很高