Java 接口
Java 接口(重要)
基本定义:
如果一个类中只有抽象方法和全局常量所组成;在这类情况下不会将其定义为抽象类,而只会将其定义为“接口”;严格来讲:接口就属于一个特殊的类,而且这个类里面只有抽象方法和全局常量(无构造方法)
接口定义需要使用interface 关键字。
interface A { //定义接口【interface】 //接口中主要有全局常量和抽象方法组成 public static final String MSG = "Hello" ; // 全局常量 public abstract void print() ; // 抽象方法 } |
由于接口里面存在有抽象方法,所以接口不可进行对象实例化(new)
1、 接口必须要有子类,但是此时一个子类可以使用implements关键字实现多个接口
2、 接口的子类(不是抽象类),必须要覆写接口中的全部抽象方法
3、 接口的对象可以利用子类对象的向上转型进行实例化操作
interface A { //定义接口【interface】 //接口中主要有全局常量和抽象方法组成 public static final String MSG = "Hello" ; // 全局常量 public abstract void print() ; // 抽象方法 } interface B { public abstract void get() ; } class X implements A,B { //X类是实现了A和B两个接口功能 public void print() { System.out.println("A") ; } public void get() { System.out.println("B") ; } } public class Demo { public static void main(String [] args) { X x = new X() ; //实例化子类对象 A a = x ; // 向上转型 B b = x ; // 向上转型 a.print() ; b.get() ; } } |
public class Demo { public static void main(String [] args) { A a = new X() ;//实例化子类对象 B b =(B) a ; // 向下转型 b.get() ; } } |
实际上 A和B接口没有直接联系,但是两个接口拥有同一个子类X;因为最终实例化的是X子类,而子类属于B类的对象,所以以上的Demo代码是可行的。
对于子类而言除了接口之外,还可能会继承抽象类,所以说一个子类又要继承抽象类又要实现接口的化;先使用extends实现继承,再使用implements实现接口
interface A { //定义接口【interface】 //接口中主要有全局常量和抽象方法组成 public static final String MSG = "Hello" ; // 全局常量 public abstract void print() ; // 抽象方法 } interface B { public abstract void get() ; } abstract class C { public abstract void change() ; } class X extends C implements A,B { //X类是先继承C类再实现了A和B两个接口功能 public void print() { System.out.println("A-implements") ; } public void get() { System.out.println("B-implements") ; } public void change() { System.out.println("C-extends") } } |
对接口而言组成的内容就是抽象方法和全局常量,所以很多的时候也有一些人为了省略,可以不用写上 abstract 或 public static final 声明;并且再方法上是否写public结果都是一样的,因为再接口中只能够使用唯一的public访问权限。
接口定义的不同 |
|
完整 |
interface A { public static final String MSG = "Hello" ; public abstract void fun () ; } |
简短 |
interface A { String MSG = "Hello" ; public void fun () ; } |
**在接口定义抽象方法时可省去public但为了防止访问权限的报错和混淆,不建议省去**
一个抽象类只可以继承一个抽象类,但是反之:一个接口却可以使用extends关键字同时继承多个接口(接口不可以继承抽象类)
interface A { public void funA() ; } interface B { public void funB() ; } interface C extends A,B { // C接口同时继承了A和B两个接口 public void funC() ; } class X implements C { //由于 C接口包含了A和B接口,故X子类继承的接口包括A、B、C三个 //实现覆写 public void funA() { } public void funB() { } public void funC() { } } |
从继承关系角度:抽象类的限制比接口多;
一个抽象类只能够继承也给抽象的父类,而接口没有这个限制
一个子类只能够继承一个抽象类,却可以实现继承多个接口
【Java接口主要功能就是解决了继承的单继承局限问题】
虽然接口的定义是只包含定义抽象方法和全局常量,但是所有的限制是不受内部的影响;所以再接口中也可以定义普通内部类、抽象内部类、内部接口。
interface A { public void funA() ; abstract class B { public abstract void funB () ; } } class X implements A { // x实现A接口 public void funA() { System.out.println("A") ; } class Y extends B { //内部抽象类的子类 public void funB() {} } } |
**在一个接口的内部如果使用了static定义内部接口,等同一个外部接口
interface A { public void funA() ; static interface class B {//Static定义的内部接口 == 外部接口 public abstract void funB () ; } }
class X implements A.B { // x实现A.B接口 public void funB() { } } |
1)接口再实际开发中三大核心作用:
定义不同层之间的操作标准
表示一种操作的能力
表示将服务端的远程方法视图暴露给客户端
标准定义:(定义不同层之间的操作标准)
在Java中,也存在程序标准,而标准就是由接口定义的;通俗的理解为:接口类即是一个标准,子类则依靠接口类而产出的依赖(接口)
//标准可以连接不同层的操作类 interface USB { //定义标准一定就是定义接口 public void start() ; public void stop() ; } class Computer { public void plugin(USB usb) { //USB标准插入 usb.start() ; // 调用方法 usb.stop() ; } } class Flash implements USB { public void start() { System.out.println("U盘开始使用") ; } public void stop() { System.out.println("U盘停止使用") ; } } class Print implements USB { public void start() { System.out.println("打印机开始工作") ; } public void stop() { System.out.println("打印机停止工作") ; } }
public class Demo { public static void main(String [] args) { Computer com = new Computer() ; com.plugin(new Flash()) ; com.plugin(new Print()) ; } } |
工厂设计模式:Factory
interface Fruit { public void eat() ; } class Apple implements Fruit { public void eat() { System.out.println("eat...") ; } }
public class Demo { public static void main(String [] args) { Fruit f = new Apple() ; f.eat() ; } } |
interface Fruit { public void eat() ; } class Apple implements Fruit { public void eat() { System.out.println("Apple...") ; } } class Orange implements Fruit { public void eat() { System.out.println("Orange...") } } public class Demo { public static void main(String [] args) { Fruit f = new Orange() ; f.eat() ; } } |
在Java过程中,最需要关心的就是如何取得一个Fruit接口对象,而不是关心对象是被谁实例化的。
一旦子类进行扩充,main的操作和实例化+调用则会发生变化。
interface Fruit { public void eat() ; } class Apple implements Fruit { public void eat() { System.out.println("Apple...") ; } } class Orange implements Fruit { public void eat() { System.out.println("Orange...") } } class Factory { // 工厂类 public static Fruit getInstance(String className) {//static申明则不需要实例化 if ( "apple".equals(className)) { return new Apple() ; } else if ( "orange".equals(className)) { return new Orange() ; } else { return null ; } } } public class Demo { public static void main(String [] args) { // 借由调用工厂类,main看不见子类了,通过工厂类实现调用子类的功能 Fruit f = Factory.getInstance("apple") ; f.eat() ; } } |
子类对于mian完全透明,所有接口对象都是通过Factory类(工厂类)取得的,如果日后要扩展新的子类对象,则只需要修改工厂类即可,但是客户端调用则不会发生变化。
Fruit f = Factory.getInstance(****) ;中只需要给工厂类传递调用子类名即在工厂类通过if判断调用的子类名进行对子类进行调用操作。
main可以看见接口类和工厂类,接口类可以看见子类和子类方法,工厂类可以调用子类和子类方法;main通过调用工厂类而使用接口子类。
总结:即是通过工厂类实现对接口子类的操作,在子类发生变化时只需要改变工厂类代码即可,不需要对main客户端进行过多承重的代码设计(不需要再一一对接口子类声明实例化)
代理设计模式:
interface Subject { // 接口类核心 public void make() ; } class RealSubject implements Subject { //核心主题 public void make() { System.out.println("核心主题") ; } } class ProxySubject implements Subject { // 代理主题类 private Subject subject ; //子类构造 == 接收一个核心的操作对象 public ProxySubject(Subject subject) { this.subject = subject ; } public void prepare() { System.out.println("核心主题操作准备") ; } public void make() { this.prepare() ; this.subject.make() ; this.destroy() ; } public void destroy() { System.out.println("核心主题操作结束") ; } } public class Demo { public static void main(String [] args) { Subject sub = new ProxySubject(new RealSubject()); sub.make() ; } } |
代理设计模式的核心在于有一个主题操作接口(可能有多种方法);核心业务主题只完成核心功能;而代理主题负责完成与核心业务有关的操作。
抽象类与接口的区别:
区别 |
抽象类 |
接口 |
关键字 |
abstract class |
interface class |
组成 |
构造方法、普通方法、抽象方法、static方法、常量、变量 |
抽象方法、全局常量 |
子类使用 |
class 子类 extends 抽象类 |
class 子类implements 接口 |
子类关系 |
抽象类可以实现多个接口 |
接口不可以继承抽象类 但可以继承多个父类接口 |
权限 |
可以使用三类权限 |
仅可以使用public权限 |
限制 |
只能继承一个抽象类(单继承) |
可以实现多个接口 |
子类 |
抽象类和接口都必须有子类,子类必须要覆写全部的抽象方法 |
|
实例化对象 |
依靠子类对象的向上转型进行对象的实例化 |
经过比较发现:抽象类中支持的种类绝对要高过接口支持的种类;但是抽象类的单继承局限,导致抽象类的缺点大于优点以及接口的引用高于抽象类。
n 在进行公共操作的时候,一定要定义出接口
n 有了接口就需要利用子类完善方法
n 自己写的接口,不要关键字new直接实例化接口子类(用工厂类完成)