抽象類能實(shí)例化嗎?口氣很強(qiáng)硬的說:“不能”!
本文轉(zhuǎn)載自微信公眾號「 見賢思編程」,作者 泰斗賢若如。轉(zhuǎn)載本文請聯(lián)系 見賢思編程公眾號。
前言
針對這個問題,在 19 年我在博客園專門寫過一篇博客,為什么突然翻出來呢?
昨晚有個大二的學(xué)弟專門加我好友來問我這個問題,當(dāng)時他問我的時候,我居然不知道該怎么回答他了,我知道不能,但一時說不出原因,可見 Java 基礎(chǔ)確實(shí)需要補(bǔ)補(bǔ)課了。
忘了也是正常的,就怕你知道你忘了,還無動于衷,這就說不過去了。
于是乎,我進(jìn)博客園把兩年前的博客給扒出來了,先自己溫習(xí)了一遍,然后給學(xué)弟講了一遍,現(xiàn)在我覺得我又行了(打臉)。
不翻不知道,一翻變了樣。就這問題,居然有 13000+ 的閱讀量,說明關(guān)注這問題或者被這個問題所迷惑的人還不少,于是乎,小牛 把這篇博客又搬運(yùn)到公眾號上了,也許還有讀者不知道。
抽象類不能實(shí)例化
抽象類不能直接通過 new 去實(shí)例化一個對象,那它就是不能實(shí)例化,要獲取抽象類的對象,需要先用一個類繼承抽象類,然后去實(shí)例化子類。
也可以用匿名內(nèi)部類,在抽象類中創(chuàng)建一個匿名的子類,繼承抽象類,通過特殊的語法實(shí)例化子類的對象(這個后面會詳細(xì)解釋) 。
現(xiàn)在重點(diǎn)來了,要研究這個問題,前提是你要了解抽象類,萬變不離其宗,我們從抽象類的根源談起 ,深化對抽象類的理解。
首先看這個例子:
- 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();
- }
- }
運(yùn)行結(jié)果:
哈巴狗四條腿跑的很快!!!
錦鯉四條腿跑的很快!!!
是不是發(fā)現(xiàn)問題了,魚怎么能用腿跑呢,難道是原始魚?
哈哈,開玩笑的,這個問題如何解決?估計(jì)大家馬上想到了,在子類中重寫父類的 run 方法不就行了。
對,確實(shí)這樣就可以解決,但是大家想過沒有,我們是如何發(fā)現(xiàn)這個問題的?
是不是編譯運(yùn)行之后才看到的,當(dāng)然,也有大佬能不編譯運(yùn)行就能看到,不抬杠啊。
意思是說有發(fā)現(xiàn)不了這個問題的風(fēng)險(xiǎn),對別人可能無所謂,但對我們程序員來說,這種低級錯誤還是不犯的好,程序員應(yīng)該有更高的追求,豈能在這被絆倒,我們要把這種風(fēng)險(xiǎn)降為零,那該如何做呢?
不急,心急吃不了熱豆腐,且看我慢慢分析:
目前存在的問題:
1.動物類的run方法描述的不正確
2.沒有強(qiáng)制要子類一定要重寫父類的run方法
解決方案:(抽象類的應(yīng)用場景)
我們在描述一類事物的時候,發(fā)現(xiàn)該種事物確實(shí)存在著某種行為,但是這種行為目前是不具體的,那么我們可以抽取這種行為的聲明,但是不去實(shí)現(xiàn)該種行為,這時候這種行為我們稱作為抽象的行為,我們就需要使用抽象類
先看下面的例子:
- package com.my.animal;
- //動物類(抽象類)
- public abstract class Animal {
- String name;//名字
- String color;//顏色
- //構(gòu)造方法
- 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();
- }
- }
運(yùn)行結(jié)果:
哈巴狗四條腿跑得快!!
錦鯉搖搖尾巴游啊游!!
這個問題解決了,那下面解決的問題就是:抽象類能實(shí)例化對象嗎?
看這個例子就知道了:
- {
- 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();
- }
- }
運(yùn)行結(jié)果:
Error:(45,20) java:com.my.animal.Animal是抽象的;無法實(shí)例化
抽象類注意的細(xì)節(jié):
1.如果一個函數(shù)沒有方法體,那么該函數(shù)必須要使用abstract修飾,把該函數(shù)修飾成抽象的函數(shù)。
2.如果一個類出現(xiàn)了抽象的函數(shù),那么該類也必須使用abstract修飾。
3.如果一個非抽象類繼承了抽象類,那么必須要把抽象類的所有抽象方法全部實(shí)現(xiàn)。
4.抽象類可以存在抽象方法,也可以存在非抽象方法,還可以不存在抽象方法,但是這樣沒任何意義,Java是不寫廢話的。
5.抽象類是不能實(shí)例化對象的
6.抽象類是存在構(gòu)造函數(shù)的,其構(gòu)造函數(shù)是提供給子類創(chuàng)建對象的時候初始化父類的屬性的。
疑問:為什么抽象類不能實(shí)例化對象?
因?yàn)槌橄箢愂谴嬖诔橄蠓椒ǖ?,如果能讓抽象類?chuàng)建對象的話,那么使用抽象類的對象調(diào)用抽象方法是沒有任何意義的。
疑問排解了,故事結(jié)束了?不,學(xué)海本無底,我們來點(diǎn)擴(kuò)展,就是開頭提到的如何用匿名內(nèi)部類去實(shí)例化子類對象。
看下面的例子:
- 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();
- }
- }
運(yùn)行結(jié)果:
我是抽象類中的一個非抽象方法
這個問題到這就結(jié)束了,但是學(xué)習(xí)還沒有停止,比如接口也是一種抽象類型,是抽象方法的集合,由此,我們是不是該聯(lián)想到學(xué)習(xí)接口了呢?忘了的同學(xué)該復(fù)習(xí)了哈!