接口
一、普通类、抽象类、接口之间的联系与区别
-
结构上的异同:
普通类:只有具体实现
抽象类:具体实现和规范(抽象方法)都有
接口 :只有规范!自己无法写方法~专业的约束!约束和实现分离:面向接口编程。
-
实例化
普通类可以被实例化
抽象类只能被继承不能被实例化
接口只能有实现类,不能被继承或实例化,但是有一种接口在匿名内部类(假象的所谓内部类)实例化现象 参考博文 Java 接口实例化
二、接口
-
接口关键字:interface
-
接口就是规范:
定义的是一组规则,体现了现实世界中”如果你是···则必须能···“的思想。
如果你是天使,就必须能飞;如果你似乎汽车,就必须能跑;如果你是好人,就必须干掉坏人···
-
接口的本质是契约:
就像我们社会的法律一样,制定好之后大家必须要遵守。
-
OO的精髓:
OO精髓是对对象的抽象,最能体现这一点的就是接口。
为什么我们讨论设计模式都只针对具备了抽象能力的语言(比如C++/Java/C#等),因为设计模式所研究的,实际上就是如何合理的去抽象。
三、接口的作用:
-
约束
-
接口中的所有方法的默认类型 public abstract (公开的、抽象的)
-
接口中的所有属性的默认类型 public static final(公开的、静态的、常量)
① 数据类型
② 引用类型:其地址值也不能被更改 -
接口不能被实例化,接口中没有构造器,通过类去实现(implements)的方式来使用。
① 实现类覆盖接口中的所有抽象方法,则此实现类可以实例化
② 实现类没有覆盖接口中所有的抽象方法,则此实现类仍为一个抽象类 -
一个类可以实现多个接口,相当于伪多继承,弥补了Java单继承的局限性
class A extnds B inmlements C,D,E{ }
-
接口和接口之间可以多继承
interface AA{ void method1(); } interface BB{ void method2(); } //CC继承了AA,BB,那么CC的实现类必须重写AA和BB中的所有方法 interface CC extends AA,BB{ }
-
与继承关系类似,接口与实现类之间存在多态性
public class CarTest { public static void main(String[] args) { Made m = new Made(); // 非匿名实现类的非匿名对象 Audi audi = new Audi(); m.show(audi); // 非匿名实现类的匿名对象 m.show(new Byd()); // 匿名实现类的非匿名对象 Car dazhong = new Car() { @Override public void method() { System.out.println("生产五菱神车"); } }; m.show(dazhong); // 匿名实现类的匿名对象 m.show(new Car() { @Override public void method() { System.out.println("生产小鹏新能源"); } }); } } // 接口实现类多态性的体现 class Made{ public void show(Car c){ c.method(); } } // 接口 interface Car{ public void method(); } // 实现类一 class Audi implements Car{ @Override public void method() { System.out.println("生产奥迪"); } } // 实现类二 class Byd implements Car{ @Override public void method() { System.out.println("生产比亚迪"); } }
四、重点:
是要锻炼自己的抽象思维,Java 架构师:把一个系统的结构全部抽象成一个接口
五、面向接口编程
- 接口的主要用途就是被实现类实现
- 项目的具体要求是多变的,我们必须以不变应万变才能从容开发,此处的不变就是“规范” 。因此,我们开发项目往往都是面向接口编程。
- 接口和类是并列关系,或者可以理解为一种特殊的类。从本质上讲,接口是一种特殊的抽象类,这种抽象类中只包含常量和方法的定义(JDK7.0之前),而没有变量和方法的实现。
六、关于实现类对 ” 接口与父类 “ 内属性和方法的调用问题
-
调用接口与父类中有同名属性
interface A{ int a = 1; int b = 4; } class B{ int a = 2; int c = 5; } public class C extends B implements A{ public static void main(String[] args) { int a = 3; new C().show(); } public void show(){ // 调用接口中的同名属性(该属性为全局静态常量) System.out.println(A.a); // 调用直接父类中的同名属性 System.out.println(super.a); // 调用子类自身的同名属性 System.out.println(a); // 调用父类中的属性 System.out.println(b); // 调用接口中的属性 System.out.println(c); } }
-
两个接口中可以有同名方法,不影响实现类对它的重写。
interface X{ void play(); } interface Y{ void play(); } interface Z extends X,Y{ // 接口中的成员变量都是默认public static final Ball ball = new Ball("接口Z的引用类型成员变量"); } class Ball implements Z{ String name; public String getName(){ return name; } public Ball(){ } public Ball(String name){ this.name = name; } @Override public void play(){ // ball是接口Z中的引用类型成员变量,可直接使用去调用方法或属性 System.out.println(ball.getName()); } } class PlayTest { public static void main(String[] args) { Ball b = new Ball("自身实例化"); // 输出为: 接口Z的引用类型成员变量,b 是带参实例化对象,但对play方法内的ball造成影响 b.play(); } }
七、接口在java8后新特性(静态/默认方法)
-
接口中定义的静态方法,只能通过接口来调用(static)
-
通过实现类的对象,可以调用接口中的默认方法(default)
如果实现类重写了接口中的默认方法,调用时用的是重写后的方法
-
如果子类(实现类)继承的父类和接口中声明了同名同参数的方法,那么在没有重写该方法的情况下,默认调用父类的同名同参方法。——>类似优先原则
-
接口冲突:
① 如果实现类实现了多个接口,而这些多个接口中定义了同名同参的默认方法,并且有方法体,那么在实现类没有重写该方法的情况下,就会报错,这种情况被称为接口冲突
② 解决接口冲突的方法,必须在实现类中重写此方法。
-
子类调用父类、接口中的各种方法示例
public class PriorityPrinciple { public static void main(String[] args) { SubClass sub = new SubClass(); // 实现类调用重写父类的方法 sub.method1(); // 接口调用其自身静态方法,不可通过实现类调用 CompareA.method2(); // 实现类调用重写的接口默认方法,执行重写方法 sub.method3(); // 实现类调用接口的未被重写默认方法,执行接口中的默认方法 sub.method4(); // 实现类调用父类与接口同名同参的方法,执行父类的同名同参方法 sub.method5(); // 实现类调用重写的父类与接口同名同参的方法,执行子类重写方法 sub.method6(); // 实现类调用重写的接口冲突方法,执行子类重写方法 sub.method7(); } } class SubClass extends SuperClass implements CompareA,CompareB{ @Override public void method1(){ System.out.println("子类重写的父类方法"); } @Override public void method3() { System.out.println("子类重写的接口默认方法"); } @Override public void method5() { System.out.println("子类重写父类/接口共有的同名同参方法"); } @Override public void method7() { System.out.println("解决接口冲突问题,子类重写的接口方法"); } } class SuperClass{ public void method1(){ System.out.println("父类自身独有方法"); } public void method5(){ System.out.println("父类中与接口的同名同参方法,被重写"); } public void method6(){ System.out.println("父类中与接口的同名同参方法,未被重写"); } } interface CompareA{ static void method2(){ System.out.println("接口中的静态方法"); } default void method3(){ System.out.println("接口中的默认方法"); } default void method4(){ System.out.println("接口未被重写的默认方法"); } default void method5(){ System.out.println("接口中与父类的同名同参方法,被重写"); } default void method6(){ System.out.println("接口中与父类的同名同参方法,未被重写"); } default void method7(){ System.out.println("A/B接口中的同名同参方法,被重写"); } } interface CompareB{ default void method7(){ System.out.println("A/B接口中的同名同参方法,被重写"); } }