?這篇文章我們主要學(xué)習(xí)的是兩個知識點,可以來解決文章標(biāo)題所提出來的三個問題。
?
目錄
1.抽象類
1.1 抽象類概念
1.2 抽象類語法
1.3 抽象類特性
1.4 抽象類的作用
2.內(nèi)部類
2.1 內(nèi)部類的分類
2.2 實例內(nèi)部類
2.3 靜態(tài)內(nèi)部類
2.4 匿名內(nèi)部類
2.5 局部內(nèi)部類
1.抽象類
在多態(tài)的學(xué)習(xí)中,我們曾寫過這樣的一段代碼:
class Shape {
//屬性....
public void draw() {
System.out.println("畫圖形!");
}
}
class Rect extends Shape {
@Override
public void draw() {
System.out.println("?");
}
}
class Cycle extends Shape {
@Override
public void draw() {
System.out.println("●");
}
}
class Triangle extends Shape {
@Override
public void draw() {
System.out.println("▲");
}
}
但是,我們會發(fā)現(xiàn),在父類Shape中的draw()方法似乎不曾被使用過,我們可不可以不寫draw()的實現(xiàn)部分呢?答案是可以的,抽象類將回來幫我們解決這個問題。
1.1 抽象類概念
在面向?qū)ο蟮母拍钪?,所有的對象都是通過類來描繪的,但是反過來,并不是所有的類都是用來描繪對象的,如果 一個類中沒有包含足夠的信息來描繪一個具體的對象,這樣的類就是抽象類。 比如:
說明:
- 矩形、三角形、圓形都是圖形,因此和Shape類的特性應(yīng)該是繼承關(guān)系。
- 雖然圖形圖Shape中也存在draw的方法,但由于Shape類并不是具體的圖形,因此其內(nèi)部的draw方法實際是沒有辦法實現(xiàn)的。
- 由于Shape類沒有辦法描述一個具體的圖形,導(dǎo)致其draw0方法無法具體實現(xiàn),因此可以將Shape類設(shè)計為“抽象類"。
在打印圖形例子中, 我們發(fā)現(xiàn), 父類 Shape 中的 draw 方法好像并沒有什么實際工作, 主要的繪制圖形都是由 Shape 的各種子類的 draw 方法來完成的. 像這種沒有實際工作的方法, 我們可以把它設(shè)計成一個抽象方法(abstract method), 包含抽象方法的類我們稱為抽象類(abstract class)。
1.2 抽象類語法
在Java中,一個類如果被 abstract 修飾稱為抽象類,抽象類中被 abstract 修飾的方法稱為抽象方法,抽象方法不用給出具體的實現(xiàn)體。
對于上面的shape類,我們可以做出如下修改:
abstract class Shape {
//屬性....
public abstract void draw();
}
這樣,shape就是一個抽象類。
// 抽象類:被abstract修飾的類
abstract class Shape {
// 抽象方法:被abstract修飾的方法,沒有方法體
abstract public void draw();
abstract void calcArea();
// 抽象類也是類,也可以增加普通方法和屬性
public double getArea() {
return area;
}
protected double area; // 面積
}
?注意:抽象類也是類,內(nèi)部可以包含普通方法和屬性,甚至構(gòu)造方法
1.3 抽象類特性
1. 抽象類不能直接實例化對象
2. 抽象方法不能是 private 的
3. 抽象方法不能被final和static修飾,因為抽象方法要被子類重寫
4. 抽象類必須被繼承,并且繼承后子類要重寫父類中的抽象方法,否則子類也是抽象類,必須要使用 abstract 修飾
5. 抽象類中不一定包含抽象方法,但是有抽象方法的類一定是抽象類
6. 抽象類中可以有構(gòu)造方法,供子類創(chuàng)建對象時,初始化父類的成員變量
1.4 抽象類的作用
抽象類本身不能被實例化, 要想使用, 只能創(chuàng)建該抽象類的子類,然后讓子類重寫抽象類中的抽象方法。
我們可能會想, 普通的類也可以被繼承呀, 普通的方法也可以被重寫呀, 為啥非得用抽象類和抽象方法呢?
確實如此. 但是使用抽象類相當(dāng)于多了一重編譯器的校驗。
使用抽象類的場景就如上面的代碼, 實際工作不應(yīng)該由父類完成, 而應(yīng)由子類完成.。那么此時如果不小心誤用成父類 了, 使用普通類編譯器是不會報錯的.。但是父類是抽象類就會在實例化的時候提示錯誤, 讓我們盡早發(fā)現(xiàn)問題。
很多語法存在的意義都是為了 "預(yù)防出錯", 例如我們曾經(jīng)用過的 final 也是類似. 創(chuàng)建的變量用戶不去修改, 不 就相當(dāng)于常量嘛? 但是加上 final 能夠在不小心誤修改的時候, 讓編譯器及時提醒我們。充分利用編譯器的校驗, 在實際開發(fā)中是非常有意義的。
2.內(nèi)部類
當(dāng)一個事物的內(nèi)部,還有一個部分需要一個完整的結(jié)構(gòu)進行描述,而這個內(nèi)部的完整的結(jié)構(gòu)又只為外部事物提供服 務(wù),那么這個內(nèi)部的完整結(jié)構(gòu)最好使用內(nèi)部類。在 Java 中,可以將一個類定義在另一個類或者一個方法的內(nèi)部, 前者稱為內(nèi)部類,后者稱為外部類。內(nèi)部類也是封裝的一種體現(xiàn)。
【注意事項】
1. 定義在class 類名{}花括號外部的,即使是在一個文件里,都不能稱為內(nèi)部類
?2. 內(nèi)部類和外部類共用同一個java源文件,但是經(jīng)過編譯之后,內(nèi)部類會形成單獨的字節(jié)碼文件
2.1 內(nèi)部類的分類
先來看下,內(nèi)部類都可以在一個類的哪些位置進行定義
class OutClass {
// 成員位置定義:未被static修飾 --->實例內(nèi)部類
public class InnerClass1 {
}
// 成員位置定義:被static修飾 ---> 靜態(tài)內(nèi)部類
static class InnerClass2 {
}
public void method() {
// 方法中也可以定義內(nèi)部類 ---> 局部內(nèi)部類:幾乎不用
class InnerClass5 {
}
}
}
?根據(jù)內(nèi)部類定義的位置不同,一般可以分為以下幾種形式:
- 成員內(nèi)部類(普通內(nèi)部類:未被static修飾的成員內(nèi)部類 和 靜態(tài)內(nèi)部類:被static修飾的成員內(nèi)部類)
- 局部內(nèi)部類(不談修飾符)、匿名內(nèi)部類
注意:內(nèi)部類其實日常開發(fā)中使用并不是非常多,大家在看一些庫中的代碼時候可能會遇到的比較多,日常開始中使用最多的是匿名內(nèi)部類。
2.2 實例內(nèi)部類
即未被static修飾的成員內(nèi)部類。
實例內(nèi)部類成員變量的定義:
在實例內(nèi)部類中,不能定義static修飾的成員變量,除非加final修飾:
創(chuàng)建實例內(nèi)部類對象時,先將外部類對象先創(chuàng)建出來,然后再創(chuàng)建實例內(nèi)部類對象:
在實例內(nèi)部類中可以直接訪問外部類中:任意訪問限定符修飾的成員
如果外部類和實例內(nèi)部類中具有相同名稱成員時,優(yōu)先訪問的是內(nèi)部類自己的
如果要訪問外部類同名成員時候,必須:外部類名稱.this.同名成員名字
class OuterClass {
public int data1 = 1;
public static int data2 = 2;
private int data3 = 3;
class InnerClass {
public int data1 = 111;
private int data4 = 4;
public static final int data5 = 5; //data5為常量
protected int data6 = 6;
public void test() {
System.out.println("InnerClass::test()");
System.out.println(data1);//優(yōu)先訪問的是內(nèi)部類自己的data1
System.out.println(OuterClass.this.data1); //訪問外部類的data1
System.out.println(data2);
System.out.println(data3);
System.out.println(data4);
System.out.println(data5);
System.out.println(data6);
}
}
public void test() {
System.out.println("OuterClass::test()");
System.out.println(data1); //訪問外部類成員變量
System.out.println(data2);
System.out.println(data3);
//外部類方法訪問內(nèi)部類需要先創(chuàng)建內(nèi)部類對象來訪問
InnerClass innerClass = new InnerClass();
System.out.println(innerClass.data1);
System.out.println(innerClass.data4);
System.out.println(innerClass.data6);
}
}
public class Test3 {
public static void main(String[] args) {
OuterClass outerClass = new OuterClass();
OuterClass.InnerClass innerClass = outerClass.new InnerClass();
innerClass.test();
outerClass.test();
}
}
輸出結(jié)果:
?【注意事項】
1. 外部類中的任何成員都可以在實例內(nèi)部類方法中直接訪問。
2. 實例內(nèi)部類所處的位置與外部類成員位置相同,因此也受public、private等訪問限定符的? ? ? ? 約束。
3. 在實例內(nèi)部類方法中訪問同名的成員時,優(yōu)先訪問自己的,如果要訪問外部類同名的成? ? ? ? ? 員,必須:外部類名稱.this.同名成員 來訪問。
4. 實例內(nèi)部類對象必須在先有外部類對象前提下才能創(chuàng)建。
5. 實例內(nèi)部類的非靜態(tài)方法中包含了一個指向外部類對象的引用。
6. 外部類中,不能直接訪問實例內(nèi)部類中的成員,如果要訪問必須先要創(chuàng)建內(nèi)部類的對象。
2.3 靜態(tài)內(nèi)部類
被static修飾的內(nèi)部成員類稱為靜態(tài)內(nèi)部類。
創(chuàng)建靜態(tài)內(nèi)部類對象不需要先創(chuàng)建外部類對象:
靜態(tài)內(nèi)部類不能直接訪問外部類非靜態(tài)成員變量:
class OuterClass {
public int data1 = 1;
public static int data2 = 2;
private int data3 = 3;
public static class InnerClass {
public int data4 = 4;
public static int data5 = 5;
private int data6 = 6;
void test() {
System.out.println("InnerClass::test()");
OuterClass outerClass = new OuterClass();
//System.out.println(data1); //編譯報錯
System.out.println(outerClass.data1);
System.out.println(data2);
//System.out.println(data3); //編譯報錯
System.out.println(outerClass.data3);
System.out.println(data5);
System.out.println(data6);
}
}
}
【注意事項】
1. 在靜態(tài)內(nèi)部類中只能訪問外部類中的靜態(tài)成員
2. 創(chuàng)建靜態(tài)內(nèi)部類對象時,不需要先創(chuàng)建外部類對象
2.4 匿名內(nèi)部類
學(xué)過接口的大家都知道,接口是不能實例化出對象的:
?但是我們可以通過接口創(chuàng)建出匿名內(nèi)部類對象:
?輸出結(jié)果:
2.5 局部內(nèi)部類
定義在外部類的方法體或者{}中,該種內(nèi)部類只能在其定義的位置使用,一般使用的非常少,此處簡單了解下語法格式。
public class Test3 {
public static void func() {
class AA {
public int a = 1;
}
AA aa = new AA();
System.out.println(aa.a);
}
public static void main(String[] args) {
func();
}
}
?
【注意事項】
1. 局部內(nèi)部類只能在所定義的方法體內(nèi)部使用
2. 不能被public、static等修飾符修飾
3. 編譯器也有自己獨立的字節(jié)碼文件,命名格式:外部類名字$數(shù)字內(nèi)部類名字.class
4. 幾乎不會使用文章來源:http://www.zghlxwxcb.cn/news/detail-632438.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-632438.html
到了這里,關(guān)于【JavaSE】什么是抽象類?什么是內(nèi)部類?以及它們的作用是什么?的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!