1. 什么是接口
(1)在生活中:
接口泛指實體把自己提供給外界的一種抽象化物(可以為另一實體)税手,用以由內(nèi)部操作分離出外部溝通方法雅镊,使其能被內(nèi)部修改而不影響外界其他實體與其交互的方式。
人類與電腦等信息機器或人類與程序之間的接口稱為用戶界面捺信。電腦等信息機器硬件組件間的接口叫硬件接口酌媒。電腦等信息機器軟件組件間的接口叫軟件接口。
在計算機中迄靠,接口是計算機系統(tǒng)中兩個獨立的部件進行信息交換的共享邊界秒咨。這種交換可以發(fā)生在計算機軟、硬件掌挚,外部設備或進行操作的人之間雨席,也可以是它們的結(jié)合。
(2)在Java中:
- 接口是interface吠式,相當于抽象類陡厘,在繼承關系中充當父類的角色,在接口中通過定義抽象方法來指定規(guī)范特占,子類去實現(xiàn)接口糙置,要實現(xiàn)接口中的所有抽象方法。
2.接口有什么作用
在Java中是目,類是單繼承的谤饭,怎么才能讓類多繼承呢?
家里房檐上的那只燕子是會飛的懊纳,天上的那架飛機也是會飛的揉抵,他們有相同的行為,但是他們是毫不相關的兩個子類嗤疯,是否需要讓讓多個子類繼承同一個抽象類冤今?
此時,可以通過接口茂缚,定義一個飛的接口戏罢,燕子能實現(xiàn),飛機也能實現(xiàn)阱佛,實現(xiàn)了相同的接口帖汞。
所以接口解決的問題是
- 多繼承
- 不同子類實現(xiàn)相同的行為
3.定義和實現(xiàn)一個簡單的接口
接口的定義與類的定義是相似的。
public interface 接口名 {
//接口成員
}
- 和類不同的是凑术,定義接口用的是interface修飾符
- 接口的訪問權限是public和默認權限翩蘸,與類的訪問權限類似
- 一個接口可以繼承其他父接口。它將繼承父接口中聲明的常量和抽象方法
接口實現(xiàn)語法格式
class 類 implements 接口 {
重寫接口中方法
}
實現(xiàn)一個簡單的接口
interface IShout extends IFly{
class Rabbit implements IShout{
//實現(xiàn)shout()方法
@Override
public void shout() {
}
//實現(xiàn)fly()方法
@Override
public void fly() {
}
}
實現(xiàn)接口就是遵循接口的規(guī)范
- 實現(xiàn)接口使用implements關鍵字
- 一個類可以實現(xiàn)多個接口淮逊,各接口之間用逗號分隔
- 實現(xiàn)接口的類必須實現(xiàn)接口定義的所有抽象方法催首,即使類中不使用某個抽象方法也必須實現(xiàn)它,通承古簦空方法體實現(xiàn)子類不需要的抽象方法郎任,如果抽象方法有返回值,可使用默認值备籽。
- 接口的實現(xiàn)類允許包含普通方法
- 在實現(xiàn)抽象方法時需要指定public權限舶治,否則會產(chǎn)生編譯錯誤
- 接口和類分井,抽象類是同一層次的概念,命名規(guī)則相同
接口的成員特點:
- 成員變量:只能是常量 默認有修飾符:public static final
- 構造方法:接口沒有構造方法霉猛,因為接口主要是對行為進行抽象的尺锚,是沒有具體存在。
- 成員方法: 只能是抽象方法 默認修飾符:public abstract
4. 接口的多實現(xiàn)
接口最重要的體現(xiàn):解決多繼承的弊端惜浅。將多繼承這種機制在java中通過多實現(xiàn)完成了瘫辩。
interface Fu1
{
void show1();//接口定義規(guī)范show1()
}
interface Fu2
{
void show2();//接口定義規(guī)范show2()
}
class Zi implements Fu1,Fu2// 多實現(xiàn)。同時實現(xiàn)多個接口坛悉。
{
public void show1(){}//子類實現(xiàn)show1()規(guī)范
public void show2(){}//子類實現(xiàn)show2()規(guī)范
}
多繼承的弊端是什么伐厌?
- 在多繼承時,當父類之中有相同的功能時裸影,子類調(diào)用這個功能會產(chǎn)生不確定性
- 核心問題在于父類之中有主方法體挣轨,導致了調(diào)用運行的時候不確定運行哪個主體。
多實現(xiàn)是怎么解決的這個弊端轩猩?
- 在接口之中的功能都是沒有方法體的刃唐,由子類來實現(xiàn)。
5.類繼承類的同時也可以實現(xiàn)接口
在子類繼承父類的同時界轩,也可以實現(xiàn)接口画饥,方法如下
class Father{
public void getOne(){ }
}
interface Inter {
void getTwo();
}
interface Outer{
void getThree();
}
class Son extends Father implements Inter,Outer{
@Override
public void getTwo() {
}
@Override
public void getThree() {
}
}
接口的出現(xiàn)避免了單繼承的局限性。父類中定義的事物的基本功能浊猾。接口中定義的事物的擴展功能抖甘。
- 接口和類之間可以通過實現(xiàn)(implements)產(chǎn)生關系
- 類與類之間可以通過繼承(extends)產(chǎn)生關系
- 當一個類已經(jīng)繼承了一個父類,它又需要擴展額外的功能葫慎,這時接口就派上用場了衔彻。
- 子類通過繼承父類擴展功能,通過繼承擴展的功能都是子類應該具備的基礎功能偷办。如果子類想要繼續(xù)擴展其他類中的功能呢艰额?這時通過實現(xiàn)接口來完成。
6. 接口和接口之間的繼承
接口和接口之間也是可以繼承的
public interface IFu1 {
void show1();
}
public interface IFu2 {
void show2();
}
public interface IZi extends IFu1,IFu2{
void show3();//接口繼承了IFu1,IFu2兩個父類接口
}
public class Demo implements IZi{
@Override
public void show3() {
}
@Override
public void show1() {
}
@Override
public void show2() {
}
}
接口與接口之間的繼承是可以多繼承的
在開發(fā)中如果多個接口中存在相同方法椒涯,這時若有個類實現(xiàn)了這些接口柄沮,那么就要實現(xiàn)接口中的方法,由于接口中的方法是抽象方法废岂,子類實現(xiàn)后也不會發(fā)生調(diào)用的不確定性祖搓。
7. 接口的規(guī)定
- 接口中可以定義變量,但是變量必須有固定的修飾符修飾湖苞,public static final 所以接口中的變量也稱之為常量拯欧,其值不能改變。
- 接口中可以定義方法财骨,方法也有固定的修飾符镐作,public abstract(寫代碼時可以省略藏姐,默認有public abstract)
- 接口不可以new,即不可以實例化该贾。
- 子類必須覆蓋掉接口中所有的抽象方法后包各,子類才可以實例化。否則子類是一個抽象類靶庙。
- 接口不能繼承類,接口可以繼承接口
- 接口沒有最高層娃属,類的最高層是Object
- 接口中不允許有普通方法六荒,所以接口中的方法都是抽象(jdk1.8后可以有default方法和static方法)
- 接口不是類,所以沒有構造
8. jdk1.8接口的新特性
在1.8版本之后矾端,接口內(nèi)不只可以定義抽象方法掏击,還能定義static以及default修飾的實例方法。
static方法:
public interface IDemo {
public static void demo1(){
System.out.println("static方法...");
}
}
public static void main(String[] args) {
IDemo.demo1();//直接使用接口名.方法名使用
}
}
default方法
public interface IDemo {
default void demo2(){
System.out.println("default方法......");
}
}
public class Demo implements IDemo{
public static void main(String[] args) {
Demo demo = new Demo();
demo.demo2();
}
}
public class Demo implements IDemo{
@Override
public void demo2() {//子類可以直接使用秩铆,也可以重寫
System.out.println("重寫后的default方法...");
}
public static void main(String[] args) {
Demo demo = new Demo();
demo.demo2();
}
}
9.面向接口編程
接口有多種用法:
- 接口可以作為子類的實現(xiàn)
- 接口可以作為類的屬性
- 接口可以作為方法的參數(shù)
- 接口可以作為方法的返回值
(1) 接口可以作為子類的實現(xiàn)
public interface IFu1 {
void show1();
}
public class Demo1 implements IFu1{
@Override
public void show1() {
System.out.println("demo1 is running...");
}
}
(2) 接口作為類的屬性
創(chuàng)建接口
public interface IFu1 {
void show1();
}
創(chuàng)建兩個子類實現(xiàn)接口
public class Demo1 implements IFu1{
@Override
public void show1() {
System.out.println("demo1 is running...");
}
}
public class Demo2 implements IFu1{
@Override
public void show1() {
System.out.println("demo2 is running ...");
}
}
將接口作為屬性
public class Demo {
private IFu1 iFu1;
public IFu1 getiFu1() {
return iFu1;
}
public void setiFu1(IFu1 iFu1) {
this.iFu1 = iFu1;
}
}
使用接口的屬性
public class Test {
public static void main(String[] args) {
Demo demo = new Demo();
IFu1 iFu1 = new Demo1();//創(chuàng)建IFu1接口的子類Demo1對象
demo.setiFu1(iFu1);//將IFu1接口的子類Demo1對象傳入Demo的屬性iFu1
demo.getiFu1().show1();//調(diào)用的是Demo1的show1()
}
}
結(jié)果:demo1 is running...
(3)接口可以作為方法的參數(shù)
public interface IFu1 {
void show1();
}
public class Demo1 implements IFu1{
@Override
public void show1() {
System.out.println("demo1 is running...");
}
}
public class Demo2 implements IFu1{
@Override
public void show1() {
System.out.println("demo2 is running ...");
}
}
public class Demo {
public void testInterface(IFu1 iFu1){
iFu1.show1();
}//接口作為方法的參數(shù)
}
public class Test {
public static void main(String[] args) {
Demo demo = new Demo();
IFu1 iFu1 = new Demo1();//創(chuàng)建IFu1接口的子類Demo1對象
demo.testInterface(iFu1);//使用的Demo1的方法
iFu1 = new Demo2();
demo.testInterface(iFu1);//使用的Demo2的方法
}
}
結(jié)果為:
demo1 is running...
demo2 is running ...
(4)接口可以作為方法的返回值
public interface IFu1 {
void show1();
}
public class Demo1 implements IFu1{
@Override
public void show1() {
System.out.println("demo1 is running...");
}
}
public class Demo {
public IFu1 testInterface(String type){
IFu1 iFu1 = null;//定義接口對象
if(type==null){
throw new RuntimeException("非法參數(shù)異常");
}
if(type.equalsIgnoreCase("demo1")){
return new Demo1();
}else if(type.equalsIgnoreCase("demo2")){
return new Demo2();
}else{
return null;
}
}//接口作為方法的返回值
}
public class Test {
public static void main(String[] args) {
Demo demo = new Demo();
IFu1 iFu1 = demo.testInterface("demo1");
iFu1 = demo.testInterface("demo2");
}
}
- 接口作為屬性砚亭、方法的參數(shù)、方法返回值時殴玛,可以返回任何實現(xiàn)了該接口的子類實例捅膘,接口對象調(diào)用方法時,調(diào)用的是傳入子類的方法滚粟。
- 這種設計的原理是里氏替換原則寻仗,即父類引用指向子類實例。
面向接口編程的核心是:父類引用指向子類對象凡壤,換個角度來理解就是凡是使用父類的地方都可以使用子類替換父類署尤。
面向接口編程的好處
- 降低了程序的耦合性,其能夠最大限度的解耦亚侠,所謂解耦既是解耦合的意思曹体,它和耦合相對。耦合就是聯(lián)系硝烂,耦合越強箕别,聯(lián)系越緊密。在程序中緊密的聯(lián)系并不是一件好的事情滞谢,因為兩種事物之間聯(lián)系越緊密究孕,你更換其中之一的難度就越大,擴展功能和debug的難度也就越大爹凹。
- 易擴展厨诸,我們知道程序設計的原則是對修改關閉,對新增開放.面向接口編程擴展功能只需要創(chuàng)建新實現(xiàn)類重寫接口方法進行升級擴展就可以,達到了在不修改源碼的基礎上擴展的目的.
- 易維護