- 抽象類
- 接口
- 抽象類與接口區別
1.抽象類
抽象類用abstract來修飾,例如:
package com.test.abstractaaa; public abstract class TestAbstract { }
抽象類是用來捕捉子類的通用性的,它不能被實例化,只能用作子類的超類,抽象類是被用來創建繼承層級里子類的模板,例如JDK中的GenericServlet類中部分代碼:
public abstract class GenericServlet implements Servlet, ServletConfig, java.io.Serializable{
public void init(ServletConfig config) throws ServletException { this.config = config; this.init(); } public void init() throws ServletException {} public abstract void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;
public void destroy() {} }
當HttpServlet繼承GenericServlet時,HttpServlet實現了GenericServlet類中的service方法
public abstract class HttpServlet extends GenericServlet { protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//... } }
2.接口
接口是抽象方法的集合,如果一個類實現了某個接口,那么它就繼承了這個接口的抽象方法,就像契約模式,如果實現了這個接口,那么就必須保證使用這些方法,並且實現這些方法,接口是一種形式,接口自身不能做任何事情,接口里面的方法默認都是abstract的,以Externalizable接口為例:
public interface Externalizable extends java.io.Serializable { void writeExternal(ObjectOutput out) throws IOException; void readExternal(ObjectInput in) throws IOException, ClassNotFoundException; }
當實現這個接口時,就要實現它里面的兩個方法:
public class ExteImpl implements Externalizable { @Override public void writeExternal(ObjectOutput out) throws IOException { // TODO Auto-generated method stub } @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { // TODO Auto-generated method stub } }
2.抽象類和接口的比較
參數 | 抽象類 | 接口 |
默認的方法實現 | 可以有默認的方法實現 | 完全抽象,根本不存在方法的實現 |
實現方式 | 子類用extends關鍵字來繼承抽象類,如果子類 不是抽象類的話,它需要實現父級抽象類中所有抽 象方法,父類中非抽象方法可重寫也可不重寫 |
子類用implements去實現接口,需要實現接口中所有方法 |
構造器 | 抽象類可以有構造器(構造器不能用abstract修飾) | 接口不能有構造器 |
與正常Java類的區別 | 正常Java類可被實例化,抽象類不能被實例化,其他區別見上下文 | 接口和正常java類是不同的類型 |
訪問修飾符 | 抽象方法可以用public、protected、default修飾 | 接口默認是public、不能用別的修飾符去修飾 |
main方法 | 抽象類中可以有main方法,可以運行它 | 接口中不能有main方法,因此不能運行它 |
多繼承 | 抽象類可繼承一個類和實現多個接口 | 接口只能繼承一個或者多個接口 |
速度 | 抽象類比接口速度快 | 接口稍微慢點,因為它需要去尋找類中實現的它的方法 |
添加新方法 | 如果在抽象類中添加新非abstract的方法,可以直接添加,因為非abstract方法無需在子類中實現,如果是abstact方法,則需要改變子類的代碼,也要實現這個方法 | 只要在接口中添加方法,實現它的類就要改變,去實現這個新添加的方法 |
2.1 設計層面上的區別
a. 抽象類是對一種事務的抽象,是對整個類進行抽象,包括屬性,行為(方法)。接口是對行為(行為)的抽象。如果一個類繼承或實現了某個抽象類,那么一定是抽象類的種類(擁有同一種屬性或行為的類)。
b. 設計層面不同,抽象類作為很多子類的父類,是一種模板設計,而接口是一種規范,它是一種輻射式設計,也就是說對於抽象類,如果需要添加新的方法,可以直接在抽象方法中添加實現,子類可以不用變更,
而對於接口不行,如果接口進行了變更,那么實現它的類都需要做變更。
2.2 接口和抽象類分別在什么時候使用
a. 如果擁有一些方法,並想讓他們中的一些有默認的具體實現,請選擇抽象類
b. 如果想實現多重繼承,那么請使用接口,由於java不支持多繼承,子類不能繼承多個類,但一個類可以實現多個接口,因此可以使用接口來解決。
c. 如果基本功能在不斷變化,那么就使用抽象類,如果使用接口,那么每次變更都需要相應的去改變實現該接口的所有類。
2.3 JDK8 中接口的默認方法和靜態方法
JDK8中,Oracle引入默認方法和靜態方法,用來減少抽象類和接口的差異,可以在接口中提供默認的實現方法並實現該接口的類不用強制去實現這個方法。JDK8中接口的靜態方法只能通過接口名直接去調用,接口中的默認方法因為不是abstract的,所以可重寫,也可以不重寫。