一篇文章快速了解Java中的抽象類,接口和內部類

2020-09-05 無碼可編

一 .抽象類

1. 介紹

1.1基本用法

隨著繼承層次中一個個新子類的定義,類變得越來越具體,而父類則更一般,更通用。類的設計應該保證父類和子類能夠共享特徵。有時將一個父類設計得非常抽象,以至於它沒有具體的實例,這樣的類叫做抽象類。

  • 用abstract關鍵字來修飾一個類,這個類叫做抽象類。 比如:abstract class A{ }
  • 用abstract來修飾一個方法,該方法叫做抽象方法。 抽象方法:只有方法的聲明,沒有方法的實現。以分號結束:比如:public abstract void talk();

1.2 抽象類的匿名子類

以下代碼中的Person類是一個抽象類

① 非匿名的類非匿名的對象

Worker worker = new Worker(); method1(worker);//非匿名的類非匿名的對象複製代碼

② 非匿名的類匿名的對象

method1(new Worker());複製代碼

③ 匿名子類的對象

Person p = new Person(){//Person是一個抽象類,不能實例化,這兒運用了多態的性質 @Override public void eat() { System.out.println(&34;); } }; method1(p);複製代碼

④ 匿名子類的匿名對象

method1(new Person(){ @Override public void eat() { System.out.println(&34;); } });複製代碼

2. 注意事項

  • 抽象類中一定有構造器,便於子類實例化時調用(涉及:子類對象實例化的全過程)
  • 抽象方法不能包含在非抽象類中。如果抽象父類的子類不能實現所有的抽象方法,那么子類也必須定義為抽象的。換句話說,在抽象類擴展的非抽象子類中,必須實現所有的抽象方法。還要注意到,抽象方法是非靜態的。
  • 不能用abstract修飾變量、代碼塊、構造器。
  • 不能用abstract修飾私有方法、靜態方法、final的方法、final的類。但是可以有靜態方法,靜態方法的好處是不實例化就可由抽象類或子類類名直接調用
  • 可以定義一個抽象類的對象變量,但是他只能引用非抽象類的對象。 如下代碼,這裡的p是一個抽象類Person的變量,Person引用了一個非抽象子類Student的實例。

Person p = new Student(&34;);複製代碼

  • 即使子類的父類是具體的,這個子類也可以是抽象的。
  • 不能使用 new 操作符從一個抽象類創建一個實例,但是抽象類可以用作一種數據類 型。因此,下面的語句創建一個元素是 CeometricObject 類型的數組是正確的:

GeometricObject[] objects = new CeometricObject[10];複製代碼

然後可以創建一個 CeometricObject 的實例,並將它的引用陚值給數組,如下所示: 複製代碼

objects[0] =new Circle();複製代碼

關於構造器與靜態方法的代碼如下:

abstract class AbstractClass{ /** * 輸出 */ abstract void print(); /** * */ public AbstractClass() {//抽象類中可以定義構造器,雖然不能初始化,可以被子類繼承 System.out.println(&34;); } public static void staticAbstractMethod() { System.out.println(&34;); }}/** * @author sir */public class AbstractClassTest extends AbstractClass{ public AbstractClassTest() { System.out.println(&34;); } @Override void print() { System.out.println(&34;); } public static void main(String[] args) { AbstractClassTest.staticAbstractMethod();//抽象類中可以定義靜態方法,可直接由類名調用 AbstractClass.staticAbstractMethod(); new AbstractClassTest().print(); }}複製代碼

輸出結果:

二. 接口

1.介紹

1.1 基本用法

接口是一種與類相似的結構,它在許多方面都與抽象類很相似,但是它的目的是指明相關或者不相關類的多個對象的共同行為。接口就是規範,定義的是一組規則,體現了現實世界中「如果你是/要...則必須能...」的思想。繼承是一個&34;的關係,而接口實現則是 &34;的關係。 語法:

修飾符 interface 接口名 { /** 常量聲明 */ /** 方法籤名 */}複製代碼

定義Java類的語法格式:先寫extends,後寫implements

class SubClass extends SuperClass implements InterfaceA{ }複製代碼

  • 接口中不能定義構造器的!意味著接口不可以實例化。
  • Java開發中,接口通過讓類去實現(implements)的方式來使用。類和接口之間的關係稱為接口繼承( interface inheritance)。因為接口繼承和類繼承本質上是相同的,所以我們將它們都簡稱為繼承。如果實現類覆蓋了接口中的所有抽象方法,則此實現類就可以實例化。如果實現類沒有覆蓋接口中所有的抽象方法,則此實現類仍為一個抽象類。
  • Java類可以實現多個接口,彌補了Java單繼承性的局限性 格式:class AA extends BB implements CC,DD,EE
  • 接口與接口之間可以繼承,而且可以多繼承

1.2接口和抽象類之間的對比

接口示例:


public class USBTest { public static void main(String[] args) { Computer computer = new Computer(); //1.創建了接口的非匿名實現類的非匿名對象 Flash flash = new Flash(); computer.transferData(flash); //2. 創建了接口的非匿名實現類的匿名對象 computer.transferData(new Printer()); //3. 創建了接口的匿名實現類的非匿名對象 USB phone = new USB(){ @Override public void start() { System.out.println(&34;); } @Override public void stop() { System.out.println(&34;); } }; computer.transferData(phone); //4. 創建了接口的匿名實現類的匿名對象 computer.transferData(new USB(){ @Override public void start() { System.out.println(&34;); } @Override public void stop() { System.out.println(&34;); } }); }}class Computer{ public void transferData(USB usb){//USB usb = new Flash(); usb.start(); System.out.println(&34;); usb.stop(); }}interface USB{ //常量:定義了長、寬、最大最小的傳輸速度等 void start(); void stop();}class Flash implements USB{ @Override public void start() { System.out.println(&34;); } @Override public void stop() { System.out.println(&34;); }}class Printer implements USB{ @Override public void start() { System.out.println(&34;); } @Override public void stop() { System.out.println(&34;); }}複製代碼



1.3JDK8接口新特性

除了定義全局常量和抽象方法之外,還可以定義靜態方法、默認方法 Java 8中,你可以為接口添加靜態方法和默認方法。從技術角度來說,這是完全合法的,只是它看起來違反了接口作為一個抽象定義的理念。

  • 靜態方法:使用 static 關鍵字修飾。可以通過接口直接調用靜態方法,並執行其方法體。 我們經常在相互一起使用的類中使用靜態方法。你可以在標準庫中找到像Collection/Collections或者Path/Paths這樣成對的接口和類。
  • 默認方法:默認方法使用 default 關鍵字修飾。可以通過實現類對象來調用。 我們在已有的接口中提供新方法的同時,還保持了與舊版本代碼的兼容性。比如:java 8 API中對Collection、List、Comparator等接口提供了豐富的默認方法。
  • 若一個接口中定義了一個默認方法,而另外一個接口中也定義了一個同名同參數的方法(不管此方法是否是默認方法),在實現類同時實現了這兩個接口時,會出現:接口衝突。 解決辦法:實現類必須覆蓋接口中同名同參數的方法,來解決衝突
  • 若一個接口中定義了一個默認方法,而父類中也定義了一個同名同參數的非抽象方法,則不會出現衝突問題。因為此時遵守:類優先原則。接口中具有相同名稱和參數的默認方法會被忽略

public interface CompareA { //靜態方法 public static void method1(){ System.out.println(&34;); } //默認方法 public default void method2(){ System.out.println(&34;); } default void method3(){ System.out.println(&34;); }}***********************************************public interface CompareB { default void method3(){ System.out.println(&34;); } }public class SuperClass { public void method3(){ System.out.println(&34;); } }**********************************************public class SubClassTest { public static void main(String[] args) { SubClass s = new SubClass(); // s.method1();// SubClass.method1(); //知識點1:接口中定義的靜態方法,只能通過接口來調用。 CompareA.method1(); //知識點2:通過實現類的對象,可以調用接口中的默認方法。 //如果實現類重寫了接口中的默認方法,調用時,仍然調用的是重寫以後的方法 s.method2(); //知識點3:如果子類(或實現類)繼承的父類和實現的接口中聲明了同名同參數的默認方法, //那么子類在沒有重寫此方法的情況下,默認調用的是父類中的同名同參數的方法。-->類優先原則 //知識點4:如果實現類實現了多個接口,而這多個接口中定義了同名同參數的默認方法, //那麼在實現類沒有重寫此方法的情況下,報錯。-->接口衝突。 //這就需要我們必須在實現類中重寫此方法 s.method3(); } }*************************************************************class SubClass extends SuperClass implements CompareA,CompareB{ public void method2(){ System.out.println(&34;); } public void method3(){ System.out.println(&34;); } //知識點5:如何在子類(或實現類)的方法中調用父類、接口中被重寫的方法 public void myMethod(){ method3();//調用自己定義的重寫的方法 super.method3();//調用的是父類中聲明的 //調用接口中的默認方法 CompareA.super.method3(); CompareB.super.method3(); }}複製代碼

輸出結果:


2. Comparable接口

2.1 用法

  1. Comparable 接口定義了 compareTo 方法,用於比較對象
  2. compareTo 方法判斷這個對象相對於給定對象 o 的順序,並且當這個對象小於、等於或大於給定對象 o 時,分別返回負整數、0或正整數。
  3. Comparable 接口是一個泛型接口。在實現該接口時,泛型類型 E 被替換成一種具體的類型。
  4. Java 類庫中的許多類實現了 Comparable 接口以定義對象的自然順序。Byte、Short、Integer、Long、Float、Double、Character、Biglnteger、BigDecimalx Calendar、String以及 Date 類 都 實 現 了 Comparable 接 口。

import java.util.Date;/** * @author mazouri * @create 2020-04-12 17:40 */public class CompareTest { public static void main(String[] args) { System.out.println((new Integer(3).compareTo(new Integer(5)))); // System.out.println((Integer.compare(3, 5)));當然可以用這個更好的方法 System.out.println(&34;.compareTo(&34;)); Date date1 = new Date(1990, 1, 1); Date date2 = new Date(1989, 6, 4); System.out.println(date1.compareTo(date2)); }}複製代碼

輸出結果:


2.2 自定義實現Comparable的類進行比較

題目: 定義一個接口用來實現兩個對象的比較。 interface CompareObject{ public int compareTo(Object o); //若返回值是 0 , 代表相等; 若為正數,代表當 前對象大;負數代表當前對象小 } 定義一個Circle類,聲明width,height屬性,提供getter和setter方法 定義一個ComparableRectangle.類,繼承Rectangle類並且實現CompareObject接口。在 ComparableCircle類中給出接口中方法compareTo的實現體,用來比較兩個長方形面積大小。 定義一個測試類ComparableRectangleTest,創建兩個ComparableRectangle對象,調用compareTo 方法比較兩個類的面積大小。

public interface CompareObject<C extends Rectangle> { /** * @return 若返回值是 0 , 代表相等; 若為正數,代表當前對象大;負數代表當前對象小 */ int compareTo(Object o);}******************************************************************public class Rectangle { private double width; private double height; public Rectangle() { } public Rectangle(double width, double height) { this.width = width; this.height = height; } public double getWidth() { return width; } public void setWidth(double width) { this.width = width; } public double getHeight() { return height; } public void setHeight(double height) { this.height = height; } public double getArea() { return height * width; }}******************************************************************public class ComparableRectangle extends Rectangle implements CompareObject { public ComparableRectangle() { } public ComparableRectangle(double width, double height) { super(width, height); } @Override public int compareTo(Object o) { if (this == o) { return 0; } if (o instanceof ComparableRectangle) { ComparableRectangle c = (ComparableRectangle) o; // return Double.compare(getArea(), c.getArea()); if (getArea() > c.getArea()) { return 1; } else if (getArea() < c.getArea()) { return -1; } else { return 0; } } else { throw new RuntimeException(&34;); } }}******************************************************************public class ComparableRectangleTest { public static void main(String[] args) { ComparableRectangle c1 = new ComparableRectangle(2.2, 3.4); ComparableRectangle c2 = new ComparableRectangle(2.3, 3.4); int compareValue = c1.compareTo(c2); if (compareValue > 0) { System.out.println(&34;); } else if (compareValue < 0) { System.out.println(&34;); } else { System.out.println(&34;); } }}複製代碼

輸出結果:


三. 內部類

1. 介紹

  • 當一個事物的內部,還有一個部分需要一個完整的結構進行描述,而這個內部的完整的結構又只為外部事物提供服務,那麼整個內部的完整結構最好使用內部類。
  • 在Java中,允許一個類的定義位於另一個類的內部,前者稱為內部類,後者稱為外部類

分類: ① 成員內部類(static成員內部類和非static成員內部類) ② 局部內部類(不談修飾符)、匿名內部類

2.局部內部類

2.1 基本用法

java局部內部類就是在方法中定義的類,它僅在該方法中有效。

class 外部類{方法(){ class 局部內部類{ } } { class 局部內部類{ } } }複製代碼

2.2 如何使用局部內部類:

  • 只能在聲明它的方法或代碼塊中使用,而且是先聲明後使用。除此之外的任何地方都不能使用該類
  • 但是它的對象可以通過外部方法的返回值返回使用,返回值類型只能是局部內部類的父類或父接口類型

2.3 局部內部類的特點

  • 內部類仍然是一個獨立的類,在編譯之後內部類會被編譯成獨立的.class文件,但是前面冠以外部類的類名和$符號,以及數字編號。
  • 只能在聲明它的方法或代碼塊中使用,而且是先聲明後使用。除此之外的任何地方都不能使用該類。
  • 局部內部類可以使用外部類的成員,包括私有的。
  • 局部內部類可以使用外部方法的局部變量,但是必須是final的。 由局部內部類和局部變量的聲明周期不同所致。 jdk 7及之前版本:要求此局部變量顯式的聲明為final的 jdk 8及之後的版本:可以省略final的聲明
  • 局部內部類和局部變量地位類似,不能使用public,protected,預設,private
  • 局部內部類不能使用static修飾,因此也不能包含靜態成員

3.匿名內部類

3.1 基本用法

匿名內部類不能定義任何靜態成員、方法和類,只能創建匿名內部類的一個實例。一個匿名內部類一定是在new的後面,用其隱含實現一個接口或實現一個類。 格式:

new 父類構造器(實參列表)實現接口(){//匿名內部類的類體部分} 複製代碼

interface A{public abstract void fun1();}public class Outer{public static void main(String[] args) {new Outer().callInner(new A(){//接口是不能new但此處比較特殊是子類對象實現接口,只不過沒有為對象取名public void fun1() {System.out.println(「implement for fun1&34;黃鸝&34;小明&34;人:吃飯&34;卡拉是條狗&34;杜鵑&34;我是一隻小小鳥"); Person.this.eat();//調用外部類的非靜態屬性 eat(); System.out.println(age); } public void display(String name){ System.out.println(name);//方法的形參 System.out.println(this.name);//內部類的屬性 System.out.println(Person.this.name);//外部類的屬性 } }} 複製代碼

輸出結果:


作者:馬走日lx
連結:https://juejin.im/post/6864894289751572493

相關焦點

  • Java學習(十一): 抽象類和接口
    ,抽象類也可以像普通類一樣,有構造方法、一般方法和屬性,更重要的是還可以有一些抽象方法,需要子類去實現,而且在抽象類中聲明構造方法後,在子類中必須明確調用。在外部抽象類上無法使用static聲明,但是內部抽象類卻可以使用static定義,使用static定義的內部抽象類就表示一個外部類。
  • Java抽象類與接口的區別
    它根本不存在方法的實現實現子類使用extends關鍵字來繼承抽象類。如果子類不是抽象類的話,它需要提供抽象類中所有聲明的方法的實現。子類使用關鍵字implements來實現接口。它需要提供接口中所有聲明的方法的實現構造器抽象類可以有構造器接口不能有構造器與正常Java類的區別除了你不能實例化抽象類之外,它和普通Java類沒有任何區別接口是完全不同的類型訪問修飾符抽象方法可以有public、protected和default這些修飾符接口方法默認修飾符是public
  • JavaSE基礎知識學習---抽象類和接口
    什麼叫抽象類在java中,因為繼承,使得類越來越具體化,類的設計使得父類越來越通用,在類的設計裡應該保證父類和子類能夠共享特徵,有時候就把父類設計的非常抽象,讓它沒有具體的實例。這樣的類就叫抽象類,例如人可以說話,但是不同的人可能說的話不一樣,所以讓說話的內容由子類自己決定。1.抽象類不可以被實例化,實例化應該是它的子類來完成.
  • EffectiveJava-3-類和接口
    或Serializable接口,如果實現,請不要在clone或readObject方法中調用可覆蓋的方法,原因同上- 對於普通的具體類,若非為了安全的進行子類化而設計,要禁止其子類化(或者完全消除這個類中可覆蓋方法的自用性,以確保安全的進行子類化)接口優於抽象類- 二者區別:1.
  • Java中抽象類和接口的介紹及二者間的區別
    接口(Interface)和抽象類(Abstract Class)是支持抽象類定義的兩種機制。一、抽象類在Java中被abstract關鍵字修飾的類稱為抽象類,被abstract關鍵字修飾的方法稱為抽象方法,抽象方法只有方法的聲明,沒有方法體。抽象類是用來捕捉子類的通用特性的 。它不能被實例化,只能被用作子類的超類。
  • 你好,我是java中的內部類
    一個類定義在一個java源文件中不香嗎?因此在使用內部類之前,了解使用內部類的理由顯得尤為重要,個人覺得學知識帶著目的來學,印象可能更深一些,畢竟有實際的例子來輔助記憶。曾經讀過一本書《Think in java》(像java一樣思考),記得裡面有一句關於內部類的話:&34;。當然這句話現在幾乎成了勸人學內部類的定理。
  • 「三分鐘了解」Java的數據類型:類、接口
    還有3種引用類型(類、接口、數組)。在Java類的體系中還包括了幾個特殊作用的類:抽象類,內部類,枚舉。成員內部類中不能定義static屬性和方法外部類先創建內部類的對象,然後通過內部類的對象來才能訪問其屬性和方法。局部內部類局部內部類也叫區域內嵌類,局部內部類與成員內部類類似,不過,是定義在一個方法中的內嵌類,只能被此方法使用。
  • 玩轉PHP中的抽象類與接口
    在面向對象開發中,特別是使用現代化框架的過程中,我們經常會和接口、抽象類打交道。特別是我們自己嘗試去封裝一些功能時,接口和抽象類往往會是我們開始的第一步,但你真的了解它們嗎?抽象類定義抽象類的特點:顧名思義,它是抽象的,當然也就是不能被實例化的。所以,抽象類一般是作為我們的基類來進行定義的。在一個類中,只要有一個方法被定義為抽象的,那麼這個類就必須加上abstract關鍵字成為抽象類。
  • 淺析java繼承與多態,抽象類與接口的區別
    類通過實現接口定義的方法而受接口的約束,所以說接口是類的需求描述和行為規範。接口和類是兩種不同的數據類型。public int add(int i, int j){return i+j;}}從上文可知 Java 中類不能實現多繼承,但是這裡類可以通過接口實現多繼承,多個接口之間用 ',' 分割,繼承的類必須實現所有繼承接口中定義的方法。
  • Java之抽象方法的使用與及接口中抽象方法的簡單介紹
    各位小夥伴們大家好,這次小編要介紹的是Java當中的接口,什麼是接口呢?接口就是多個類的公共規範,是一中引用數據類型,最重要的內容就是其中的抽象方法。如上圖所示,通過上面這個USB接口,兩臺電腦可以互相傳遞文件,只要符合USB接口的規範,很多設備都可以使用。
  • java集合類框架,你了解多少?
    這篇文章並沒有對每一個集合類進行分析,而是一個整體的框架的認識。在後期會陸續發表出來這篇文章的大體結構如下:1、對java集合框架一個整體的認識和了解2、通過繼承關係圖認識集合的整體框架3、提前給出各個集合類的使用場景等一、集合框架的認識對於集合框架的認識,為了防止時間久,而印象變得模糊,所以我自己是這樣記得,這個方法以供參考吧,假定給定一個集合類,可以把他當成一個人,首先記住從哪裡來(繼承關係),然後有什麼本事(底層的數據結構決定了特點
  • Java中內部類到底有什麼用?
    java中內部類種類較多,語法比較複雜,用法也不盡相同。概括下來,可以分類為以下五種內部類。內部類嵌套內部類局部內部類接口內部類匿名內部類本篇文章只對實際項目開發中用的較多的,普通內部類與匿名內部類做一定介紹。其他三種若有興趣請自行通過谷歌或書籍進行了解。
  • java中的匿名內部類總結
    匿名內部類也就是沒有名字的內部類正因為沒有名字,所以匿名內部類只能使用一次,它通常用來簡化代碼編寫但使用匿名內部類還有個前提條件:必須繼承一個父類或實現一個接口實例1:不使用匿名內部類來實現抽象方法abstract class Person { public abstract void eat
  • 一篇文章快速了解Java中的IO流
    例如,c:\book\Welcome.java 是文件Welcome.java 在 Windows 作業系統上的絕對文件名。Welcome.java 是一個相對文件名。windows和DOS系統默認使用「\」來表示 UNIX和URL使用「/」來表示 Java程序支持跨平臺運行,因此路徑分隔符要慎用。
  • Java內部類解析你知道多少?
    ,定義在靜態方法中的局部類只能訪問外部類的靜態變量和方法。匿名內部類不能定義任何靜態成員和靜態方法。當所在的方法的形參需要被匿名內部類使用時,必須聲明為 final。匿名內部類不能是抽象的,它必須要實現繼承的類或者實現的接口的所有抽象方法。
  • java中static, final, 內部類的具體運用
    static概念:static它是靜態修飾符,一般用來修飾類中的成員。當在定義類的時候,類中都會有相應的屬性和方法。而屬性和方法都是通過創建本類對象調用的。static特點:static是靜態修飾符,一般修飾成員。被static修飾的成員屬於類,不屬於單個這個類的某個對象。
  • Java提高篇——詳解內部類
    在使用內部類之間我們需要明白為什麼要使用內部類,內部類能夠為我們帶來什麼樣的好處。一、為什麼要使用內部類為什麼要使用內部類?在《Think in java》中有這樣一句話:使用內部類最吸引人的原因是:每個內部類都能獨立地繼承一個(接口的)實現,所以無論外圍類是否已經繼承了某個(接口的)實現,對於內部類都沒有影響。
  • 120、抽象類和接口區別
    接口和抽象類的概念不一樣。接口是對動作的抽象,抽象類是對根源的抽象。抽象類表示的是,這個對象是什麼。接口表示的是,這個對象能做什麼。比如,男人,女人,這兩個類(如果是類的話...... ),他們的抽象類是人。說明,他們都是人。
  • 144 、使用接口和抽象類的作用
    Java接口和Java抽象類代表的就是抽象類型,就是我們需要提出的抽象層的具體表現。OOP面向對象的編程,如果要提高程序的復用率,增加程序的可維護性,可擴展性,就必須是面向接口的編程,面向抽象的編程,正確地使用接口、抽象類這些有用的抽象類型作為你結構層次上的頂層。
  • Java 的各種內部類、Lambda表達式
    (而外部頂級類即類名和文件名相同的只能使用 public 和 default)。注意:內部類是一個編譯時的概念,一旦編譯成功,就會成為完全不同的兩個類。對於一個名為outer的外部類和其內部定義的名為inner的內部類。編譯完成後出現 outer.class 和outer$inner.class 兩類。