日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > java >内容正文

java

Java接口的几种常见用法

發(fā)布時(shí)間:2025/3/12 java 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java接口的几种常见用法 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

接口(interface)對于面向?qū)ο缶幊虂碚f是一個(gè)非常重要的概念。它是一系列方法的聲明,卻沒有具體實(shí)現(xiàn)。有些編程語言,比如swift,把接口解釋成“協(xié)議(protocol)”,我覺得也是非常的恰當(dāng)?shù)?#xff0c;接口就是對方法制定的一套規(guī)范。

總結(jié)了以下幾點(diǎn)接口的常見用法

1. 作為對類內(nèi)執(zhí)行流程的具體描述

這是接口的最根本的作用。有時(shí)候類內(nèi)部流程的某一個(gè)環(huán)節(jié),并不是由此類自己決定的。類并不知道在這一步時(shí)具體會(huì)執(zhí)行什么內(nèi)容。所以需要在此處設(shè)置一枚接口,提供對外界的擴(kuò)展。

對于這個(gè)功能有一個(gè)非常好的范例。

一個(gè)秒表類:用于測量執(zhí)行某一段代碼執(zhí)行所需的時(shí)間。

初步的代碼類似于下面這樣:

public class Stopwatch {private long deltaTime;public void clear() {deltaTime = 0L;}public long getDeltaTime() {return deltaTime;}public void start() {long startTime = System.currentTimeMillis();// do somethingdeltaTime = System.currentTimeMillis() - startTime;} }

而使用Stopwatch的代碼類似于這樣:

public static void main(String[] args) {Stopwatch stopwatch = new Stopwatch();stopwatch.clear(); //時(shí)間清零stopwatch.start(); //開始運(yùn)行System.out.printf("time: %dms\n",stopwatch.getDeltaTime()); }

那么我們知道對于秒表這個(gè)類本身,它并不能決定自己在do something那個(gè)位置將會(huì)測量什么內(nèi)容的代碼。

也就是說此處代碼將會(huì)由Stopwatch的外部決定。所以此處可以商定一個(gè)協(xié)議,也就是接口。Stopwatch決定自己開放出一個(gè)接口叫NeedMonitoringProgram需要監(jiān)控的程序,其中doProgram()方法就是執(zhí)行需要被監(jiān)控的代碼。外部在使用Stopwatch時(shí)只需要去實(shí)現(xiàn)NeedMonitoringProgram接口也就定義好了需要監(jiān)測的代碼。

public interface NeedMonitoringProgram {void doProgram(); }

給Stopwatch賦予NeedMonitoringProgram對象

public class Stopwatch {private long deltaTime;private NeedMonitoringProgram program;public void setProgram(NeedMonitoringProgram program) {this.program = program;}public void start() {long startTime = System.currentTimeMillis();program.doProgram();deltaTime = System.currentTimeMillis() - startTime;}public interface NeedMonitoringProgram {void doProgram();}//省略clear()和getDeltaTime()方法 }

模擬測量1到1000000疊加求和所需時(shí)間

Stopwatch stopwatch = new Stopwatch(); Stopwatch.NeedMonitoringProgram program = new Stopwatch.NeedMonitoringProgram() {@Overridepublic void doProgram() {int sum = 0;int number = 1_000_000;for (int i = 0; i <= number; i++) {sum += i;}System.out.printf("sum: %d\n", sum);} }; stopwatch.setProgram(program); stopwatch.clear(); stopwatch.start(); System.out.printf("time: %dms\n",stopwatch.getDeltaTime());

假如說待測代碼是需要外部參數(shù)的,并且也需要返回給外部執(zhí)行結(jié)果的。也可以把接口方法改進(jìn)一下。

添加一個(gè)Param類來存儲(chǔ)參數(shù)。

private Param params = new Param();public void addParam(String key, Object value) {params.put(key, value); }public interface NeedMonitoringProgram<RETURN_OBJECT> {RETURN_OBJECT doProgram(Param params); }public class Param extends HashMap<String, Object> {}

start方法也可以直接加入NeedMonitoringProgram對象,減少使用時(shí)的步驟。 并且NeedMonitoringProgram類的泛型指定了返回類型。

public <T> T start(NeedMonitoringProgram<T> program) {long startTime = System.currentTimeMillis();T returnObject = program.doProgram(params);deltaTime = System.currentTimeMillis() - startTime;return returnObject; }

在執(zhí)行start()之前使用addParam()給代碼賦值。而start()也會(huì)返回代碼執(zhí)行的結(jié)果。

Stopwatch stopwatch = new Stopwatch(); stopwatch.clear(); stopwatch.addParam("number", 1_000_000); int sum = stopwatch.start(new Stopwatch.NeedMonitoringProgram<Integer>() {@Overridepublic Integer doProgram(Stopwatch.Param params) {int sum = 0;int number = (Integer)params.get("number");for (int i = 0; i <= number; i++) {sum += i;}return sum;} }); System.out.printf("sum: %d\n", sum); System.out.printf("time: %dms\n",stopwatch.getDeltaTime());

運(yùn)用JDK8的lambda表達(dá)式甚至可以縮寫為

int sum = stopwatch.start(params -> {int s = 0;int number = (Integer)params.get("number");for (int i = 0; i <= number; i++) {s += i;}return s; });

雖然java沒有函數(shù)對象這一概念,但是使用lambda可以充分表達(dá)一種函數(shù)式編程的思想,在這里接口即等同于代表了一個(gè)函數(shù)對象。

以上是接口最最根本的功能,廣泛運(yùn)用在AWT、Swing、Android這類圖形化程序中。像XXXListener這些處理控件事件的接口都是運(yùn)用了此功能。

2. 多態(tài)

可以把具體子類對象都當(dāng)作父類來看,屏蔽不同子類對象之間的差異。

public interface Animal {void sayHello(); } public class Cat implements Animal{@Overridepublic void sayHello() {System.out.println("I'm a cat.");} } public class Dog implements Animal{@Overridepublic void sayHello() {System.out.println("I'm a dog.");} } public static void main(String[] args) {Animal[] animals = new Animal[]{new Cat(), new Dog()};for (Animal animal : animals) {animal.sayHello();} }

在這里把Cat和Dog都一視同仁的放入了Animal的數(shù)組內(nèi),并且批量處理。多態(tài)的功能其實(shí)和抽象類(abstract class)相同。

3. 用于隱藏方法的具體實(shí)現(xiàn)過程

一個(gè)簡單的Dao

public interface UserDao {User findUser(int id);void addUser(User user);void updateUser(User user);void deleteUser(int id); }

這個(gè)DaoFactory工廠類代表某一框架內(nèi)部生成Dao的邏輯(超簡化)

public class DaoFactory {public <T> T getDaoInstance(Class<T> clazz) {if(clazz == UserDao.class) {return new UserDaoImpl();} else if(……) {}} }

那么我們在使用該框架時(shí),只需要從DaoFactory中通過Dao的類型獲得該Dao的具體實(shí)現(xiàn)對象。

我們只關(guān)心該Dao接口有哪些我們可以用的方法,而不會(huì)去關(guān)心這個(gè)Dao內(nèi)部是怎么實(shí)現(xiàn)增刪改查的。拿著這個(gè)Dao對象我們就可以去完成數(shù)據(jù)庫的操作。也就是說接口為我們屏蔽了方法的具體實(shí)現(xiàn),屏蔽了具體的實(shí)現(xiàn)類中一些雜亂無章的,對于使用者來說無用的中間方法。

4. 暴露分布式服務(wù)

public interface XXXService {}

在大型網(wǎng)站項(xiàng)目中,底層的服務(wù)都是基于分布式部署的。比如說Dubbo框架,在分布式項(xiàng)目中,接口和實(shí)現(xiàn)是分離于兩個(gè)子項(xiàng)目中的。分布式的優(yōu)勢在于,通過架設(shè)多臺(tái)服務(wù)提供者(provider)維持了服務(wù)提供的穩(wěn)定性。只要不是所有服務(wù)提供者掛機(jī),服務(wù)消費(fèi)者(consumer)依然可以得到穩(wěn)定的服務(wù)。對于服務(wù)消費(fèi)者來說它并不關(guān)心服務(wù)是由誰提供的,只關(guān)心有哪些服務(wù)可以用,所以接口既屏蔽了方法的具體實(shí)現(xiàn),甚至還可以接來自不同服務(wù)提供者的服務(wù)。在這里,接口起到了一個(gè)協(xié)議的作用,消費(fèi)者需要哪些服務(wù),由接口描述,同時(shí)提供者根據(jù)接口實(shí)現(xiàn)了自己的處理服務(wù)邏輯。

5. 賦予類某種能力

我們常常會(huì)遇到一些諸如XXXable,以able結(jié)尾的類

比如說java.io.Serializable這是賦予了類可序列化的能力

我們自己也可以寫給類賦予能力的接口以及實(shí)現(xiàn)。

做過微信支付的應(yīng)該都知道,對接微信支付需要發(fā)送包含xml字符串的HTTP請求。

那么就可以對微信支付功能封裝一個(gè)客戶端(Client)

那么大致步驟如下:

public class WechatClient{/*** 統(tǒng)一下單*/public void unifiedOrder() {//1. 生成xml//2. 發(fā)送HTTP請求//3. 處理請求結(jié)果} }

接下來給客戶端類賦予可發(fā)送HTTP請求的能力,聲明一個(gè)接口:

public interface HttpSendable {//發(fā)送GET請求HttpResponse getHttps(String url);//發(fā)送包含raw富文本的POST請求HttpResponse postHttps(String url, String raw); }

HttpSendable顧名思義就是可發(fā)送HTTP請求的能力

那么給客戶端加上這個(gè)能力

public class WechatClient implements HttpSendable

這個(gè)能力的實(shí)現(xiàn)可以使用抽象父類實(shí)現(xiàn),不會(huì)造成次要代碼污染主要類的邏輯

public abstract class HttpSender implements HttpSendable{@Overridepublic HttpResponse getHttps(String url) {return null;}@Overridepublic HttpResponse postHttps(String url, String raw) {return null;} }

HttpSender就是HTTP的發(fā)送者,當(dāng)然它也有發(fā)送HTTP的能力HttpSendable然后客戶端繼承了它

public class WechatClient extends HttpSender implements HttpSendable{/*** 統(tǒng)一下單*/public void unifiedOrder() {//1. 生成xmlString xml = "";//代碼略//2. 發(fā)送HTTP請求HttpResponse response = super.postHttps("https://", xml);//3. 處理請求結(jié)果//代碼略} }

像這樣寫代碼,是不是會(huì)增加代碼的可理解性了呢?

6. 作為常量接口

一般老java程序員都喜歡這么用,包括JDK內(nèi)部也有這么用的。把一些常量扔在接口里面。

//申請狀態(tài)常量 public interface ApplyStatusContants {public static final String STATIC_UNTREATED = "STATIC_UNTREATED";//未處理public static final String STATIC_ACCEPT = "STATIC_ACCEPT"; //通過public static final String STATIC_REJECT = "STATIC_REJECT"; //拒絕 }

不過自從JDK1.5以后新增了enum枚舉類型。我們就不需要常量接口了,可以如下方式:

public enum ApplyStatus {UNTREATED, ACCEPT, REJECT }

簡單粗暴。

接口的用法還是特別靈活多變的,也許還有沒有列舉的用法,歡迎大家補(bǔ)充。

總結(jié)

以上是生活随笔為你收集整理的Java接口的几种常见用法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。