接口的定义及使用

您所在的位置:网站首页 数据接口的作用包括 接口的定义及使用

接口的定义及使用

2024-07-14 02:39| 来源: 网络整理| 查看: 265

一、接口的基本定义

如果一个类之中只是由抽象方法和全局常量所组成的,那么在这种情况下不会将其定义为一个抽象类,而只会将其定义为接口,所以所谓的接口严格来讲就属于一个特殊的类,而且这个类里面只有抽象方法与全局常量。

要定义一个接口使用interface关键字完成。

范例:定义接口

interface A {// 定义了接口 public static final String MSG = "Hello";// 全局常量 // 抽象方法 public abstract void print(); }

由于接口里面存在有抽象方法,所以接口对象不可能直接使用关键字new进行实例化的操作,所以接口的使用原则如下:

· 接口必须要有子类,但是此时一个子类可以使用implements关键字实现多个接口;

· 接口的子类(如果不是抽象类),必须要覆写接口中的全部抽象方法;

· 接口的对象可以利用子类对象的向上转型进行实例化操作。

 

范例:实现接口

interface A {// 定义了接口 public static final String MSG = "Hello";// 全局常量 // 抽象方法 public abstract void print(); } interface B { public abstract void get(); } class X implements A, B {// X类实现A和B两个接口 @Override public void get() { System.out.println("B接口的抽象方法!"); } @Override public void print() { System.out.println("A接口的抽象方法!"); } } public class Demo { public static void main(String args[]) { X x = new X(); A a = x;// 向上转型 B b = x;// 向上转型 a.print(); b.get(); } }

以上的代码实例化了X类对象。由于现在X是A和B的子类,所以X类的对象可以变成A接口或者B接口类的对象。

public class Demo { public static void main(String args[]) { A a = new X(); B b = (B) a; b.get(); System.out.println(a instanceof A); System.out.println(a instanceof B); } }

在定义结构上来讲,A和B接口没有任何的直接联系,但是这两个接口却同时拥有一个子类:X子类,千万不要被类型和名称所迷惑。因为最终实例化的是X子类,而这个子类属于B类的对象,所以以上的代码成立。只不过从代码的编写上来讲并不是很好。

 

但是要知道一点,对于子类而言,除了接口之外,还可能会去继承抽象类,所以说一个子类既要继承抽象类又要去实现接口的话,那么请先使用extends继承,而后再使用implements实现。

interface A {// 定义了接口 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类实现A和B两个接口 @Override public void get() { System.out.println("B接口的抽象方法!"); } @Override public void print() { System.out.println("A接口的抽象方法!"); } @Override public void change() { System.out.println("C类的抽象方法!"); } }

对接口而言,发现里面的组成就是抽象方法和全局常量,所以很多的时候也有一些人为了省略编写,可以不用写上abstract或public static final,并且在方法上是否编写public结果都是一样的,因为在接口里面只能够使用一种访问权限——public。以下两个接口的定义效果是完全相同的:

interface A {

public static final String MSG = "hello";

public abstract void fun();

}

interface A {

String MSG = "hello";

void fun();

}

在接口里面没有写上public,其最终的访问权限也是public,绝对不是default。为了防止某些不熟悉语法的开发者出现错误,所以强烈建议在接口定义方法的时候一定要写上public。

interface A { String MSG = "hello"; public void fun(); }

对于接口的组成,99%的情况下都是以抽象方法为主,很少有接口只是单纯的去定义常量。

 

一个抽象类可以去定义一个抽象类,但是反过来,一个接口却可以使用extends关键字同时继承多个接口(但是不能继承抽象类)。

范例:观察接口的多继承

interface A { public void funA(); } interface B{ public void funB(); } //C接口同时继承了A和B两个父接口 interface C extends A,B{//此处使用的是extends public void funC(); } class X implements C{ @Override public void funA() {} @Override public void funB() {} @Override 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("Hello"); } class Y extends B {// 内部抽象类的子类 @Override public void funB() { } } }

范例:在一个接口内部如果使用了static去定义一个内部接口表示是一个外部接口。

interface A { public void funA(); static interface B {// 外部接口 public void funB(); } } class X implements A.B { @Override public void funB() { } }

大部分情况,只要求清楚内部接口的定义即可。

先期总结:接口在实际的开发之中有三大核心作用:

· 定义不同层之间的操作标准;

· 表示一种操作的能力;

· 表示将服务器端的远程方法视图暴露给客户端。

二、接口的实际应用——标准定义

电脑上可以使用U盘、Mp3、打印机,这些设备都是连接到USB设备上的。

所有的代码如果要进行开发,一定要首先开发出USB接口标准,因为有了标准后,电脑才可以去使用这些标准,设备厂商才可以设计USB设备。

范例:定义USB标准

//标准可以连接不同层的操作类 interface USB{//定义标准一定就是接口 public void start(); public void stop(); }

范例:定义电脑

class Computer{ public void plugin(USB usb){//插入 usb.start();//固定操作 usb.stop();//固定操作 } }

不管以后会有多少个设备,只要它是USB标准的实现子类,就都可以在电脑上使用。

范例:定义U盘

class Flash implements USB{ @Override public void start() { System.out.println("U盘开始使用"); } @Override public void stop() { System.out.println("U盘停止使用"); } }

范例:定义打印机

class Print implements USB{ @Override public void start() { System.out.println("打印机开始使用"); } @Override public void stop() { System.out.println("打印机停止使用"); } }

按照这样的方式,准备出几万个子类都可以,并且这几万个子类都可以在电脑的plugin()方法上使用。

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 { @Override public void eat() { System.out.println("吃苹果"); } } public class Demo { public static void main(String args[]) { Fruit f = new Apple(); f.eat(); } }

以上的程序可以通过主方法得到Fruit接口对象,但是有没有一些问题呢?

如果要想确认一个代码是否真的好,有这么几个标准:

· 客户端调用简单,不需要关注具体细节;

· 客户端之外的代码修改,不影响用户的使用,即:用户不用去担心代码是否变更。

本次的程序没有任何的语法错误,但是关键的问题就出在关键字“new”上。一个接口不可能只有一个子类,所以对于Fruit也有可能产生多个子类对象。

class Orange implements Fruit { @Override public void eat() { System.out.println("吃橘子"); } }

现在的客户端上要想得到这新的子类对象,需要修改代码,修改为:

public class Demo { public static void main(String args[]) { Fruit f = new Orange(); f.eat(); } }

发现如果现在直接在客户端上产生了实例化对象,那么每一次要想更换对象,都需要修改客户端上的执行代码,这样的做法明显是不好的。

在整个的代码过程之中,我们最需要关心的是如何取得一个Fruit接口对象,而后进行方法的调用,至于说这个接口对象是被谁实例化的,那不是客户端的工作。

所以经过分析发现,最大的问题就在于关键字new,而这一问题就可以理解为耦合度太高。耦合度太高的直接问题是代码不方便维护,就相当于A一直要与B绑定在一起。可以完全参考Java虚拟机的设计思想:

· 程序——>JVM——>适应不同的操作系统(A——>C——>B);

范例:增加一个过渡

class Factory { public static Fruit getInstance(String className) { 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[]) { Fruit f = Factory.getInstance("apple"); f.eat(); } }

现在的客户端不会看见具体的子类,因为所有的接口对象都是通过Factory类取得的,如果日后要扩充新的子类对象,则只需要修改Factory类即可,客户端的调用不会发生变化。

扩展题目:请编写一个Factory程序。(以上答案)

四、接口的应用——代理设计模式(Proxy)

范例:程序(皇帝宠幸妃子)

interface Subject {// 整个操作的核心主题 public void make(); } class RealSubject implements Subject { @Override 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("准备……"); } @Override public void make() { this.prepare(); this.subject.make(); this.destory(); } public void destory() { System.out.println("销毁"); } } public class Demo { public static void main(String args[]) { Subject sub = new ProxySubject(new RealSubject()); sub.make();// 调用的是代理主题的操作 } }

代理设计模式的核心精髓就在于有一个主题操作接口(可能有多种方法),核心业务主题只完成核心功能,例如:吃饭,而代理主题负责完成所有与核心主题有关的辅助性操作。

扩展题目:请编写一个Proxy程序。(以上答案)

五、抽象类与接口的区别

抽象类和接口在使用上是非常相似的,所以很多人很乐意去解释两者的区别。

No

区别

抽象类

接口

1

关键字

Abstract class

Interface class

2

组成

构造方法、抽象方法、普通方法、static方法、常量、变量

抽象方法、全局常量

3

子类使用

class 子类 extends 抽象类

class 子类 implements 接口,接口,……

4

关系

可以实现多可接口

不能够继承抽象类,却可以继承多个父接口

5

权限

各种权限

public

6

限制

单继承局限

没有单继承局限

7

子类

抽象类和接口都必须有子类,子类必须要覆写全部的抽象方法

8

实例化对象

依靠子类对象的向上转型进行对象的实例化。

经过比较可以发现,抽象类支持的功能绝对要比接口更多,但是只有一点不好,那就是单继承局限,这重要的一点就掩盖了所有抽象类的优点,即:当抽象类和接口都可以使用的时候,优先考虑接口。

一个参考(50%):

· 在进行某些公共操作的时候一定要定义出接口;

· 有了接口就需要利用子类完善方法;

· 如果自己写的接口,那么绝对不要去使用关键字new直接实例化接口子类,使用工厂类完成。

 

总结:

接口与抽象类定义的不同;接口作为标准用于解耦合以及不同层之间的连接桥梁;

 



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3