抽象類能實例化嗎?口氣很強硬的說:「不能」!

2021-01-12 51CTO

本文轉載自微信公眾號「 見賢思編程」,作者 泰鬥賢若如。轉載本文請聯繫 見賢思編程公眾號。

前言

針對這個問題,在 19 年我在博客園專門寫過一篇博客,為什麼突然翻出來呢?

昨晚有個大二的學弟專門加我好友來問我這個問題,當時他問我的時候,我居然不知道該怎麼回答他了,我知道不能,但一時說不出原因,可見 Java 基礎確實需要補補課了。

忘了也是正常的,就怕你知道你忘了,還無動於衷,這就說不過去了。

於是乎,我進博客園把兩年前的博客給扒出來了,先自己溫習了一遍,然後給學弟講了一遍,現在我覺得我又行了(打臉)。

不翻不知道,一翻變了樣。就這問題,居然有 13000+ 的閱讀量,說明關注這問題或者被這個問題所迷惑的人還不少,於是乎,小牛 把這篇博客又搬運到公眾號上了,也許還有讀者不知道。

抽象類不能實例化

抽象類不能直接通過 new 去實例化一個對象,那它就是不能實例化,要獲取抽象類的對象,需要先用一個類繼承抽象類,然後去實例化子類。

也可以用匿名內部類,在抽象類中創建一個匿名的子類,繼承抽象類,通過特殊的語法實例化子類的對象(這個後面會詳細解釋) 。

現在重點來了,要研究這個問題,前提是你要了解抽象類,萬變不離其宗,我們從抽象類的根源談起 ,深化對抽象類的理解。

首先看這個例子:

package com.my.animal;     //動物類  public class Animal {  String name;//名字  String color;//顏色     public Animal(String name,String color){  this.name = name;  this.color = color;  }  public void run(){  System.out.println(name+"四條腿跑的很快!!!");  }  }  //狗類繼承動物類  class Dog extends Animal{  public Dog(String name,String color){  super(name,color);  }  }  //魚類繼承動物類  class Fish extends Animal{     public Fish(String name, String color) {  super(name, color);  }  }     class Test{  public static void main(String[] args) {  Dog dog = new Dog("哈巴狗","白色");  dog.run();     Fish fish = new Fish("錦鯉","紅色");  fish.run();  }  } 

運行結果:

哈巴狗四條腿跑的很快!!!

錦鯉四條腿跑的很快!!!

是不是發現問題了,魚怎麼能用腿跑呢,難道是原始魚?

哈哈,開玩笑的,這個問題如何解決?估計大家馬上想到了,在子類中重寫父類的 run 方法不就行了。

對,確實這樣就可以解決,但是大家想過沒有,我們是如何發現這個問題的?

是不是編譯運行之後才看到的,當然,也有大佬能不編譯運行就能看到,不抬槓啊。

意思是說有發現不了這個問題的風險,對別人可能無所謂,但對我們程式設計師來說,這種低級錯誤還是不犯的好,程式設計師應該有更高的追求,豈能在這被絆倒,我們要把這種風險降為零,那該如何做呢?

不急,心急吃不了熱豆腐,且看我慢慢分析:

目前存在的問題:

1.動物類的run方法描述的不正確

2.沒有強制要子類一定要重寫父類的run方法

解決方案:(抽象類的應用場景)

我們在描述一類事物的時候,發現該種事物確實存在著某種行為,但是這種行為目前是不具體的,那麼我們可以抽取這種行為的聲明,但是不去實現該種行為,這時候這種行為我們稱作為抽象的行為,我們就需要使用抽象類

先看下面的例子:

package com.my.animal;  //動物類(抽象類)  public abstract class Animal {  String name;//名字  String color;//顏色  //構造方法  public Animal(String name,String color){  this.name = name;  this.color = color;  }  //非抽象方法  public void eat(){  System.out.println(name+"吃東西!!!");  }  //抽象方法  public abstract void run();  }     class Dog extends Animal{  public Dog(String name,String color){  super(name,color);  }     @Override  public void run() {  System.out.println(name+"四條腿跑得快!!");  }  }     class Fish extends Animal{     public Fish(String name, String color) {  super(name, color);  }     @Override  public void run() {  System.out.println(name+"搖搖尾巴遊啊遊!!");  }  }     class Test{  public static void main(String[] args) {  Dog dog = new Dog("哈巴狗","白色");  dog.run();     Fish fish = new Fish("錦鯉","紅色");  fish.run();  }  } 

運行結果:

哈巴狗四條腿跑得快!!

錦鯉搖搖尾巴遊啊遊!!

這個問題解決了,那下面解決的問題就是:抽象類能實例化對象嗎?

看這個例子就知道了:

{  String name;  String color;     public Animal(String name,String color){  this.name = name;  this.color = color;  }  public abstract void run();  }     class Test{  public static void main(String[] args) {  Animal a = new Animal();  a.run();  }  } 

運行結果:

Error:(45,20) java:com.my.animal.Animal是抽象的;無法實例化

抽象類注意的細節:

1.如果一個函數沒有方法體,那麼該函數必須要使用abstract修飾,把該函數修飾成抽象的函數。

2.如果一個類出現了抽象的函數,那麼該類也必須使用abstract修飾。

3.如果一個非抽象類繼承了抽象類,那麼必須要把抽象類的所有抽象方法全部實現。

4.抽象類可以存在抽象方法,也可以存在非抽象方法,還可以不存在抽象方法,但是這樣沒任何意義,Java是不寫廢話的。

5.抽象類是不能實例化對象的

6.抽象類是存在構造函數的,其構造函數是提供給子類創建對象的時候初始化父類的屬性的。

疑問:為什麼抽象類不能實例化對象?

因為抽象類是存在抽象方法的,如果能讓抽象類創建對象的話,那麼使用抽象類的對象調用抽象方法是沒有任何意義的。

疑問排解了,故事結束了?不,學海本無底,我們來點擴展,就是開頭提到的如何用匿名內部類去實例化子類對象。

看下面的例子:

public class Java_Abstract2 {     public void a(){  System.out.println("我是抽象類中的一個非抽象方法");  }     public static Java_Abstract2 newIntences(){  return new Java_Abstract2(){     };  }  }     class Test2{  public static void main(String[] args) {  Java_Abstract2 java_abstract2 = Java_Abstract2.newIntences();  java_abstract2.a();  }  } 

運行結果:

我是抽象類中的一個非抽象方法

這個問題到這就結束了,但是學習還沒有停止,比如接口也是一種抽象類型,是抽象方法的集合,由此,我們是不是該聯想到學習接口了呢?忘了的同學該複習了哈!

【編輯推薦】

【責任編輯:

武曉燕

TEL:(010)68476606】

點讚 0

相關焦點

  • 抽象類和接口的區別?
    1.是否熟悉抽象類和接口的定義,區別?2.是否熟悉 Java 8 之後的接口變化?考察的知識點1.抽象類和接口的定義,區別2.Java 8 之後的接口變化考生應該如何回答1、考生首先應該回答抽象類和接口的定義和區別,接口和抽象類是 Java 面向對象設計的兩個基礎機制。接口是對行為的抽象,它是抽象方法的集合,利用接口可以達到 API 定義和實現分離的目的。
  • JavaSE基礎知識學習---抽象類和接口
    什麼叫抽象類在java中,因為繼承,使得類越來越具體化,類的設計使得父類越來越通用,在類的設計裡應該保證父類和子類能夠共享特徵,有時候就把父類設計的非常抽象,讓它沒有具體的實例。這樣的類就叫抽象類,例如人可以說話,但是不同的人可能說的話不一樣,所以讓說話的內容由子類自己決定。
  • C sharp編程基礎實現多態的方法之二抽象類實例解析
    一、抽象類概念:抽象類是虛擬的類,不能創建對象,用abstract修飾,在子類中用override進行重寫。實現多態的示例代碼三、抽象類實現多態的實例練習要求:使用多態求矩形的面積和周長:總結抽象類的特點1.抽象成員必須標記為abstract,並且不能有任何實現。2.抽象成員必須在抽象類中。
  • 論Java中的抽象類與接口
    ,可以通過實例化其子類,通過子類重寫方法實現等——設置抽象方法就是讓子類來實現的,否則毫無意義。——瘋狂的Java講義abstract不能用於修飾Field,不能用於修飾局部變量,即沒有抽象變量、沒有抽象Field等說法;abstract也不能用於修飾構造器,沒有抽象構造器,抽象類裡定義的構造器只能是普通構造器。
  • Java開發中抽象類和接口都有什麼區別?
    Java在Java軟體開發中抽象類和接口會有一個明顯的區別,具體會有哪些區別呢?下文就兩者的區別做了一個比較詳細的描述。抽象類抽象類:1、抽象類使用abstract修飾;2、抽象類不能實例化,即不能使用new關鍵字來實例化對象
  • 一日一技:在 Python 裡面如何實現一個抽象類
    在某個在線教育的網站上設計模式相關的課程中,某老師說 Python 不支持抽象類和接口。但實際上,Python 支持抽象類。Python 自帶的abc模塊用於實現抽象類相關的定義和操作。基於ABC類可以實現一個抽象類。通過@abstractmethod裝飾一個方法,讓它成為一個抽象方法。抽象方法在子類中必需被實現。抽象類不能被實例化,所以我們實例化一下,可以看到這裡報錯了,如下圖所示:
  • Java抽象類與接口的區別
    在討論它們之間的不同點之前,我們先看看抽象類、接口各自的特性。抽象類抽象類是用來捕捉子類的通用特性的 。它不能被實例化,只能被用作子類的超類。抽象類是被用來創建繼承層級裡子類的模板。如果一個類實現了某個接口,那麼它就繼承了這個接口的抽象方法。這就像契約模式,如果實現了這個接口,那麼就必須確保使用這些方法。接口只是一種形式,接口自身不能做任何事情。
  • Java-學習了抽象類,那它的細節也是必須要知道的,避免出錯!
    1.1.抽象類的細節問題1、一個類是抽象類,那麼這個類不能創建對象。因為如果類是抽象類,類中就有可能存在抽象方法,由於抽象方法是沒有方法體。所以抽象類中的構造函數不是給自己用的,是給子類創建對象時候使用的。3、抽象類一定是父類嗎?抽象肯定是父類,因為它必須有子類去複寫其中的抽象函數。但不一定是最頂層的父類。4、抽象類中可以沒有抽象方法嗎?
  • 如何區分Java中的抽象類(abstract class)和接口(interface)?
    1、相同點①抽象類和接口都不能實例化,但可以聲明。比如:public abstract class Student{……}∥聲明抽象類Student student;∥OKStudent student = new Student();∥錯誤②一個類繼承了某個抽象類,或實現了某個接口,其中的抽象方法全部都必須要實現,否則該類仍然需要聲明為抽象類(abstract class)。
  • Java接口interface、抽象類abstract,逐步學習怎麼封裝對象
    中常用的接口和抽象類。一、接口Java接口是一系列的方法的聲明,也是一些方法特徵的集合;100%的抽象類,即接口中的方法必須是抽象方法;接口聲明了一個類必須做什麼和不能做什麼,即定義了類的藍圖;>抽象方法只能存在於抽象類或接口中,但抽象類卻能存在非抽象方法,即接口是百分之百的抽象類。
  • 淺析java繼承與多態,抽象類與接口的區別
    如:注意看,所有子類實例都可以賦值給父類變量,但僅能調用父類定義的方法。因為 JVM 會把 s2 當作 Person 類實例看待,父類中不存在的則不能訪問,又因為 s 和 s2 實際指向的是同一對象,所以調用 getName 方法還是子類的方法。子類實例引用可以賦值給父類變量,但父類引用不能賦值給子類變量。
  • 小白,你要的Java抽象類,操碎了心!
    因為有讀者留言「鼓勵」我說,「二哥,你真的是為小白操碎了心啊!」我容易嗎?我。當我們要完成的任務是確定的,但具體的方式需要隨後開個會投票的話,Java 的抽象類就派上用場了。這句話怎麼理解呢?搬個小板凳坐好,聽我來給你講講。01、抽象類的 5 個關鍵點1)定義抽象類的時候需要用到關鍵字 abstract,放在 class 關鍵字前。
  • 80106:abstract class(抽象類)和interface(接口)有什麼區別?
    abstract class(抽象類)和interface(接口)有什麼區別?
  • 面試官:接口和抽象類有什麼區別?
    抽象類抽象類和接口類似,它也是用來定義對象的公共行為的,並且它也不能直接實例化,抽象類的實現關鍵字為 abstract class,子類用 extends 關鍵字繼承父類。抽象類中的方法控制符無限制,其中抽象方法不能使用 private 修飾,如下代碼所示:
  • 深入解析面試常問的Java 接口與抽象類問題
    在了解抽象類之前,先來了解一下抽象方法。抽象方法是一種特殊的方法:它只有聲明,而沒有具體的實現。抽象方法的聲明格式為:抽象方法必須用abstract關鍵字進行修飾。如果一個類含有抽象方法,則稱這個類為抽象類,抽象類必須在類前用abstract關鍵字修飾。因為抽象類中含有無具體實現的方法,所以不能用抽象類創建對象。
  • JAVA抽象類和接口知識點
    抽象類類是具有相同功能和屬性的對象的集合,而抽象類是對類的高度抽象,在類層次中處於上層
  • Java中的接口與抽象類:有什麼區別?
    接口是可用於實現類的藍圖。接口不包含任何具體方法(有代碼的方法)。接口的所有方法都是抽象的方法。無法實例化接口。但是,可以實例化實現接口的類。接口從來不包含實例變量,但它們可以包含公共靜態最終變量(即常量類變量)。什麼是抽象類?
  • 帶你分析Java中接口與抽象類的相同與不同
    01接口與抽象類的相同點接口和抽象類都不能被直接實例化為對象接口和抽象類都可以有抽象方法實現接口或繼承抽象類的普通類必須實現接口或抽象類中定義的抽象方法接口和抽象類都可以沒有抽象方法而抽象類沒有抽象方法,可以是一個空的沒有任何方法的抽象類,也可以是一個擁有的方法都是非抽象方法的抽象類。
  • 我如何理解Java中抽象類和接口
    然後,我們就大說一通抽象類可以有方法,接口不能有實際的方法啦;一個類只能繼承一個抽象類,卻可以繼承多個接口啦,balabala一大堆,就好像把標準答案熟練的說出來一樣。  抽象類和接口這篇文章講到了他們的區別和聯繫,它們確實有很多相似的地方,但是從本質上看,或從語言的設計角度來看,這不是它們最本質的區別。
  • 一篇文章帶你了解Java中的抽象類和接口知識
    一、抽象類1.什麼是抽象類?凡是使用abstract關鍵字修飾的類就是抽象類。2.假設在定義Animal類,定義一個shout()方法表示動物發出的叫聲,我們知道不同動物它們的發出的聲音是不一樣的,在shout()方法不能夠準確的描述動物發出的叫聲。當在定義一個類,通常會定義一些方法來描述這個類的行為特徵,有些時候這些方法實現的方式我們不能確定。