基础面试题
這里寫自定義目錄標題
文章目錄
6.什么是泛型通配符?什么是泛型的上下限?
8.什么是線程池?線程池有什么優點?
1. 程序計數器
2 Java虛擬機棧
3 本地方法棧
4 Java堆
5 方法區
1.static方法
2.static變量
3.static代碼塊
4.靜態內部類
5.靜態導包
11.什么是方法?談談你對方法的理解
1.概念
2.格式
3.注意事項
4.方法的重載:
5.方法的重寫:
6.方法的遞歸:
12.內部類有哪些種類?又有哪些使用場景?
13.談談串行、并行、并發、分布式?
答:面向對象的特征主要有以下幾個方面:
1.封裝:
封裝是把過程和數據包裹起來,外界對于數據的操作僅限于我們提供的方式。我們可以將生活中各種事物進行抽象封裝形成類,也可以通過private修飾符來封裝屬性與方法,不過需要注意的是,封裝后需要手動提供對應被封裝資源對外公共的操作方式。
2.繼承:繼承是一種聯結類的層次模型,并且允許和鼓勵類的重用,它提供了一種明確表述共性的方法。我們可以從現有的類中派生出一個新的類,這個過程稱為類繼承。新類繼承了原始類的特性,新類稱為原始類的派生類(子類),而原始類稱為新類的基類(父類)。派生類可以從它的基類那里繼承方法和實例變量,并且類可以修改或增加新的方法使之更適合特殊的需要。
3.多態性:多態性是指可以盡量屏蔽不同類的差異性,提供通用的解決方案。多態性語言具有靈活、抽象、行為共享、代碼共享的優勢,很好的解決了應用程序函數同名問題。我們所使用的有:
向上造型【將子類對象統一看作父類型,比如花木蘭替父從軍】
向下造型【將之前看作父類型的子類對象再重新恢復成子類對象,比如花木蘭打仗結束回家化妝】
4.抽象:抽象就是忽略一個主題中與當前目標無關的那些方面,以便更充分地注意與當前目標有關的方面。抽象并不打算了解全部問題,而只是選擇其中的一部分,暫時不用部分細節。抽象包括兩個方面,一是過程抽象,二是數據抽象。
抽象類:
抽象方法必須用abstract關鍵字進行修飾。如果一個類含有抽象方法,則稱這個類為抽象類,抽象類必須在類前用abstract關鍵字修飾。因為抽象類中含有無具體實現的方法,所以不能用抽象類創建對象。
抽象類可以擁有成員變量和普通的成員方法。
== 抽象類和普通類的主要有三點區別:==
1)抽象方法必須為public或者protected(因為如果為private,則不能被子類繼承,子類便無法實現該方法),缺省情況下默認為public。
2)抽象類不能用來創建對象;
3)如果一個類繼承于一個抽象類,則子類必須實現父類的抽象方法。如果子類沒有實現父類的抽象方法,則必須將子類也定義為為abstract類。
接口:
接口中的變量會被隱式地指定為public static final變量,并且只能是public static final變量,用private修飾會報編譯錯誤,而方法會被隱式地指定為public abstract方法且只能是public abstract方法,用其他關鍵字,比如private、protected、static、 final等修飾會報編譯錯誤,并且接口中所有的方法不能有具體的實現,也就是說,接口中的方法必須都是抽象方法。
抽象類和接口的區別:
語法層面上的區別
1)一個類只能繼承一個抽象類,而一個類卻可以實現多個接口
2)抽象類中的成員變量可以是各種類型的,而接口中的成員變量只能是public static final類型的
3)接口中不能含有靜態代碼塊以及靜態方法,而抽象類可以有靜態代碼塊和靜態方法
4)抽象類可以提供成員方法的實現細節,而接口中只能存在public abstract 方法
5)抽象類的抽象方法可以是public,protected,default類型,而接口的方法只能是public
設計層面上的區別
1)抽象類是對一種事物的抽象,即對類抽象,而接口是對行為的抽象。抽象類是對整個類整體進行抽象,包括屬性、行為,但是接口卻是對類局部(行為)進行抽象
所以抽象是重構的結果,接口是設計的結果。
2)設計層面不同,抽象類作為很多子類的父類,它是一種模板式設計。而接口是一種行為規范,它是一種輻射式設計。
1.棧Stack:
又稱堆棧,它是運算受限的線性表,其限制是僅允許在標的一端進行插入和刪除操作,不允許在其他任何位置進行添加、查找、刪除等操作。
我們可以簡單理解成:棧結構對元素的存取有如下要求:
先進后出(也就是說,棧中越早存進去的元素,就越在最下面)
例如:子彈壓進彈夾,先壓進去的子彈在下面,后壓進去的子彈在上面,當開槍時,先彈出上面的子彈,然后才能彈出下面的子彈。
所以,棧的入口、出口的都是棧的頂端位置。我們需要知道兩個名詞:
1)壓棧:就是存元素。即,把元素存儲到棧的頂端位置,棧中已有元素依次向棧底方向移動一個位置。
2)彈棧:就是取元素。即,把棧的頂端位置元素取出,棧中已有元素依次向棧頂方向移動一個位置。
2.隊列queue:
又稱隊,它同堆棧一樣,也是一種運算受限的線性表,其限制是僅允許在表的一端進行插入,而在表的另一端進行刪除。
我們可以簡單理解成:隊列結構對元素的存取有如下要求:
先進先出(也就是說,最先存進去的元素,是可以最先取出的)
例如:我們生活中排隊買結賬,最先到的人最先付款,最后到的人得等前面的人都付款結束后才能付款。
所以:隊列的入口、出口各占一側
3.數組Array:
是有序的元素序列,數組是在內存中開辟一段連續的空間,并在此空間存放元素。就像是一列火車,從1號車廂到最后一節車廂,每節車廂都有自己的固定編號,乘坐火車的人可以通過車廂號快速找到自己的位置。
我們可以簡單理解成:數組結構對元素的存取有如下要求:
查找元素快:通過索引,可以快速訪問指定位置的元素。
增刪元素慢:
我們指定一個索引增加元素,不能修改原數組的長度,而是需要創建一個新長度的數組,將指定新元素存儲在指定索引位置,再把原數組元素根據索引,復制到新數組對應索引的位置。
我們指定一個索引刪除元素:不能修改原數組的長度,而是需要創建一個新長度的數組,把原數組元素根據索引復制到新數組對應索引的位置,原數組中指定索引位置元素不復制到新數組中。
4.鏈表LinkedList:
是一系列節點Node(鏈表中每一個元素稱為節點)組成,節點可以在運行時動態生成。每個節點包括兩個部分:一個是存儲數據元素的數據域,另一個是存儲下一個節點地址的指針域。我們常說的鏈表結構有單向鏈表與雙向鏈表。
我們這里介紹的是單向鏈表。
我們可以簡單理解成:鏈表結構對元素的存取有如下要求:
多個節點之間,通過地址進行連接。
例如:自行車的鏈條,就是通過上一個環連接下一個環,這樣就形成一個鏈條了
查找元素慢:想查找某個元素,需要通過連接的節點,依次向后查找指定元素
增刪元素快:
增加元素:只需要修改連接下個元素的地址即可。
刪除元素:只需要修改連接下個元素的地址即可。
5.紅黑樹
二叉樹BinaryTree:每個節點不超過2的有序樹(tree)
我們可以簡單理解成生活的樹的結構,只不過每個節點上都最多只能有兩個子節點。
二叉樹是每個節點最多有兩個子樹的樹結構。頂上的叫根節點,兩邊被稱作“左子樹”和“右子樹”。
紅黑樹:紅黑樹本身就是一顆二叉查找樹,將節點插入后,該樹仍然是一顆二叉查找樹。也就意味著,樹的鍵值仍然是有序的。紅黑樹的速度特別快,趨近平衡樹,查找葉子元素最少和最多次數不多于二倍
紅黑樹的特點:
節點可以是紅色的或者黑色的
根節點是黑色的
葉子節點(特指空節點)是黑色的
每個紅色節點的子節點都是黑色的
任何一個節點到其每一個葉子節點的所有路徑上黑色節點數相同
4. 什么是向上轉型?什么是向下轉型?
在JAVA中,繼承是一個重要的特征,通過extends關鍵字,子類可以復用父類的功能,如果父類不能滿足當前子類的需求,則子類可以重寫父類中的方法來加以擴展。
那么在這個過程中就存在著多態的應用。存在著兩種轉型方式,分別是:向上轉型和向下轉型。
向上轉型:可以把不同的子類對象都當作父類來看,進而屏蔽不同子類對象之間的差異,寫出通用的代碼,做出通用的編程,統一調用標準。
比如:父類Parent,子類Child
父類的引用指向子類對象:Parent p=new Child();
說明:向上轉型時,子類對象當成父類對象,只能調用父類的功能,如果子類重寫了父類中聲明過的方法,方法體執行的就是子類重過后的功能。但是此時對象是把自己看做是父類類型的,所以其他資源使用的還是父類型的。
比如:花木蘭替父從軍,大家都把花木蘭看做她爸,但是實際從軍的是花木蘭,而且,花木蘭只能做她爸能做的事,在軍營里是不可以化妝的。
向下轉型(較少):子類的引用的指向子類對象,過程中必須要采取到強制轉型。這個是之前向上造型過的子類對象仍然想執行子類的特有功能,所以需要重新恢復成子類對象
Parent p = new Child();//向上轉型,此時,p是Parent類型
Child c = (Child)p;//此時,把Parent類型的p轉成小類型Child
其實,相當于創建了一個子類對象一樣,可以用父類的,也可以用自己的
說明:向下轉型時,是為了方便使用子類的特殊方法,也就是說當子類方法做了功能拓展,就可以直接使用子類功能。
比如:花木蘭打仗結束,就不需要再看做是她爸了,就可以”對鏡貼花黃”了
String
特點:創建之后長度內容是不可變的,每次拼接字符串,都會產生新的對象
如果是直接“ ” 或者字符串常量拼接產生的,保存在字符串常量池中
如果是直接通過new方式創建的,保存在堆中
創建方式:
String() String(String s) String(char[] c) String(byte[] b) String s = “abc”;
優缺點:
優點:String類提供了豐富的關于操作字符串的方法,比如:拼接、獲取對應下標處的字符、截取子串等等
缺點:在進行字符串拼接+=的時候,效率比較低
String轉StringBuilder:
String s = “abc”; StringBuilder sb = new StringBuilder(s);
StringBuilder
特點:StringBuilder是一個長度可變的字符串序列,在創建的時候,會有一個長度為16的默認空間
當拼接字符串的時候,實在原對象的基礎之上進行拼接,如果長度不夠就擴容
所以StringBuilder在創建之后,對應的操作一直是用一個對象
創建方式:
StringBuilder sb = new StringBuilder();//創建一個長度為16的StringBuilder對象
StringBuilder sb = new StringBuilder(“abc”);//以指定字符串內容為“abc”的方式創建一個StringBuilder對象
優缺點:
優點:在拼接的時候,不會產生新的對象,就避免了因為拼接頻繁生成對象的問題,提高了程序的效率
缺點:對于字符串的操作,不太方便,所以在使用的時候,如果拼接操作很多的話:
先將String轉為StringBuilder進行拼接,拼接完成之后再轉回String
StringBuilder轉String:
StringBuilder sb = new StringBuilder();
sb.append(“abc”);
String s = sb.toString();
6.什么是泛型通配符?什么是泛型的上下限?
當使用泛型類或者接口時,傳遞的數據中,泛型類型不確定,可以通過通配符<?>表示。但是一旦使用泛型的通配符后,只能使用Object類中的共性方法,集合中元素自身方法無法使用。
通配符基本使用
泛型的通配符:不知道使用什么類型來接收的時候,此時可以使用?,?表示未知通配符。
通配符高級使用----受限泛型
之前設置泛型的時候,實際上是可以任意設置的,只要是類就可以設置。但是在JAVA的泛型中可以指定一個泛型的上限和下限。
泛型的上限:
格式: 類型名稱 <? extends 類 > 對象名稱
意義: 只能接收該類型及其子類
泛型的下限:
格式: 類型名稱 <? super 類 > 對象名稱
意義: 只能接收該類型及其父類型
7. 線程有幾種狀態?它們是怎么切換的?
線程生命周期,主要有五種狀態:
新建狀態(New) : 當線程對象創建后就進入了新建狀態.如:Thread t = new MyThread();
就緒狀態(Runnable):當調用線程對象的start()方法,線程即為進入就緒狀態.
處于就緒(可運行)狀態的線程,只是說明線程已經做好準備,隨時等待CPU調度執行,并不是執行了t.start()此線程立即就會執行
運行狀態(Running):當CPU調度了處于就緒狀態的線程時,此線程才是真正的執行,即進入到運行狀態
就緒狀態是進入運行狀態的唯一入口,也就是線程想要進入運行狀態狀態執行,先得處于就緒狀態
阻塞狀態(Blocked):處于運狀態中的線程由于某種原因,暫時放棄對CPU的使用權,停止執行,此時進入阻塞狀態,直到其進入就緒狀態才有機會被CPU選中再次執行.
根據阻塞狀態產生的原因不同,阻塞狀態又可以細分成三種:
等待阻塞:運行狀態中的線程執行wait()方法,本線程進入到等待阻塞狀態
同步阻塞:線程在獲取synchronized同步鎖失敗(因為鎖被其他線程占用),它會進入同步阻塞狀態
其他阻塞:調用線程的sleep()或者join()或發出了I/O請求時,線程會進入到阻塞狀態.當sleep()狀態超時.join()等待線程終止或者超時或者I/O處理完畢時線程重新轉入就緒狀態
死亡狀態(Dead):線程執行完了或者因異常退出了run()方法,該線程結束生命周期
就緒 → 執行:為就緒線程分配CPU即可變為執行狀態"
執行 → 就緒:正在執行的線程由于時間片用完被剝奪CPU暫停執行,就變為就緒狀態
執行 → 阻塞:由于發生某事件,使正在執行的線程受阻,無法執行,則由執行變為阻塞
(例如線程正在訪問臨界資源,而資源正在被其他線程訪問)
反之,如果獲得了之前需要的資源,則由阻塞變為就緒狀態,等待分配CPU再次執行
8.什么是線程池?線程池有什么優點?
我們使用線程的時候就去創建一個線程,這樣實現起來非常簡便,但是就會有一個問題:
如果并發的線程數量很多,并且每個線程都是執行一個時間很短的任務就結束了,這樣頻繁創建線程就會大大降低系統的效率,因為頻繁創建線程和銷毀線程需要時間。
所以我們在在Java中可以通過線程池來避免這些問題:
線程池:其實就是一個容納多個線程的容器,其中的線程可以反復使用,省去了頻繁創建線程對象的操作,無需反復創建線程而消耗過多資源。
合理利用線程池能夠帶來三個好處
降低資源消耗。減少了創建和銷毀線程的次數,每個工作線程都可以被重復利用,可執行多個任務。
提高響應速度。當任務到達時,任務可以不需要的等到線程創建就能立即執行。
提高線程的可管理性。可以根據系統的承受能力,調整線程池中工作線線程的數目,防止因為消耗過多的內存,而把服務器累趴下(每個線程需要大約1MB內存,線程開的越多,消耗的內存也就越大,最后死機)。
9. 你對Java內存分配了解多少?簡單談談:
Java虛擬機管理的內存包括幾個運行時數據內存:方法區、虛擬機棧、本地方法棧、堆、程序計數器,其中方法區和堆是由線程共享的數據區,其他幾個是線程隔離的數據區
程序計數器是一塊較小的內存,他可以看做是當前線程所執行的行號指示器。字節碼解釋器工作的時候就是通過改變這個計數器的值來選取下一條需要執行的字節碼的指令,分支、循環、跳轉、異常處理、線程恢復等基礎功能都需要依賴這個計數器來完成。如果線程正在執行的是一個Java方法,這個計數器記錄的是正在執行的虛擬機字節碼指令的地址;如果正在執行的是Native方法,這個計數器則為空。此內存區域是唯一一個在Java虛擬機規范中沒有規定任何OutOfMemotyError情況的區域
2 Java虛擬機棧
虛擬機棧描述的是Java方法執行的內存模型:每個方法在執行的同時都會創建一個棧幀用于儲存局部變量表、操作數棧、動態鏈接、方法出口等信息。每個方法從調用直至完成的過程,就對應著一個棧幀在虛擬機棧中入棧到出棧的過程。
棧內存就是虛擬機棧,或者說是虛擬機棧中局部變量表的部分
局部變量表存放了編譯期可知的各種基本數據類型(boolean、byte、char、short、int、float、long、double)、對象引用(refrence)類型和returnAddress類型(指向了一條字節碼指令的地址)
其中64位長度的long和double類型的數據會占用兩個局部變量空間,其余的數據類型只占用1個。
Java虛擬機規范對這個區域規定了兩種異常狀況:如果線程請求的棧深度大于虛擬機所允許的深度,將拋出StackOverflowError異常。如果虛擬機擴展時無法申請到足夠的內存,就會拋出OutOfMemoryError異常
3 本地方法棧
本地方法棧和虛擬機棧發揮的作用是非常類似的,他們的區別是虛擬機棧為虛擬機執行Java方法(也就是字節碼)服務,而本地方法棧則為虛擬機使用到的Native方法服務
本地方法棧區域也會拋出StackOverflowError和OutOfMemoryErroy異常
4 Java堆
堆是Java虛擬機所管理的內存中最大的一塊。Java堆是被所有線程共享的一塊內存區域,在虛擬機啟動的時候創建,此內存區域的唯一目的是存放對象實例,幾乎所有的對象實例都在這里分配內存。所有的對象實例和數組都在堆上分配
Java堆是垃圾收集器管理的主要區域。Java堆細分為新生代和老年代
不管怎樣,劃分的目的都是為了更好的回收內存,或者更快地分配內存
Java堆可以處于物理上不連續的內存空間中,只要邏輯上是連續的即可。如果在堆中沒有完成實例分配,并且堆也無法再擴展時將會拋出OutOfMemoryError異常
5 方法區
方法區它用于儲存已被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯后的代碼等數據
除了Java堆一樣不需要連續的內存和可以選擇固定大小或者可擴展外,還可以選擇不實現垃圾收集。這個區域的內存回收目標主要是針對常量池的回收和對類型的卸載
當方法區無法滿足內存分配需求時,將拋出OutOfMemoryErroy異常
1.6 運行時常量池
它是方法區的一部分。Class文件中除了有關的版本、字段、方法、接口等描述信息外、還有一項信息是常量池,用于存放編譯期生成的各種字面量和符號引用,這部分內容將在類加載后進入方法區的運行時常量池中存放
Java語言并不要求常量一定只有編譯期才能產生,也就是可能將新的常量放入池中,這種特性被開發人員利用得比較多的便是String類的intern()方法
當常量池無法再申請到內存時會拋出OutOfMemoryError異常
static是Java中的一個關鍵字,可以用來修飾方法、變量、代碼塊、內部類,還可以使用靜態導包
1.static方法
static方法一般稱作靜態方法,由于靜態方法不依賴于任何對象就可以進行訪問,因此對于靜態方法來說,是沒有this的,因為它不依附于任何對象,既然都沒有對象,就談不上this了。并且由于這個特性,在靜態方法中不能訪問類的非靜態成員變量和非靜態成員方法,因為非靜態成員方法/變量都是必須依賴具體的對象才能夠被調用。
注意:雖然在靜態方法中不能訪問非靜態成員方法和非靜態成員變量,但是在非靜態成員方法中是可以訪問靜態成員方法/變量的。
2.static變量
static變量也稱作靜態變量,靜態變量和非靜態變量的區別是:靜態變量被所有的對象所共享,在內存中只有一個副本【存放在方法區】,它當且僅當在類初次加載時會被初始化【加final和不加final的static變量初始化的位置不一樣】。而非靜態變量是對象所擁有的,在創建對象的時候被初始化,存在多個副本,各個對象擁有的副本互不影響。
static成員變量的初始化順序按照定義的順序進行初始化。
3.static代碼塊
static關鍵字還有一個比較關鍵的作用就是用來形成靜態代碼塊以優化程序性能,因為靜態資源只會加載一次。static塊可以置于類中的任何地方,類中可以有多個static塊。在類初次被加載的時候,會按照static塊的順序來執行每個static塊,并且只會執行一次。
初始化的順序 靜態代碼塊 > 構造代碼塊 > 構造函數
為什么說static塊可以用來優化程序性能,是因為它的特性:只會在類加載的時候執行一次。
下面看個例子:
class Person{
private Date birthDate;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
isBornBoomer是用來這個人是否是1946-1964年出生的,而每次isBornBoomer被調用的時候,都會生成startDate和birthDate兩個對象,造成了空間浪費,如果改成這樣效率會更好,其實就是利用了靜態代碼塊在內存中值加載一次的機制:
class Person{
private Date birthDate;
private static Date startDate,endDate;
static{
startDate = Date.valueOf(“1946”);
endDate = Date.valueOf(“1964”);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
因此,很多時候會將一些只需要進行一次的初始化操作都放在static代碼塊中進行。
4.靜態內部類
在談論靜態內部之前,我們來談談,為何要用內部類?
定義在一個類內部的類叫內部類,包含內部類的類稱為外部類。內部類可以聲明public、protected、private等訪問限制,可以聲明為abstract的供其他內部類或外部類繼承與擴展,或者聲明為static、final的,也可以實現特定的接口。內部類有以下特點:
1.內部類一般只為其外部類使用【比如:hashmap集合中,內部類Entry<K,V>】
2.內部類提供了某種進入外部類的窗戶,內部類存在外部類的引用,所以內部類可以直接訪問外部類的屬性
3.每個內部類都能獨立地繼承一個接口,而無論外部類是否已經繼承了某個接口。因此,內部類使多重繼承的解決方案變得更加完整。
靜態內部類
定義靜態內部類:在定義內部類的時候,可以在其前面加上一個權限修飾符static。此時這個內部類就變為了靜態內部類。通常稱為嵌套類,當內部類是static時,意味著:
要創建嵌套類的對象,并不需要其外圍類的對象;
不能從嵌套類的對象中訪問非靜態的外圍類對象(不能夠從靜態內部類的對象中訪問外部類的非靜態成員);
嵌套類與普通的內部類還有一個區別:普通內部類的字段與方法,只能放在類的外部層次上,所以普通的內部類不能有static數據和static字段, 也不能包含嵌套類。但是在嵌套類里可以包含所有這些東西。也就是說,在非靜態內部類中不可以聲明靜態成員,只有將某個內部類修飾為靜態類,然后才能夠在這 個類中定義靜態的成員變量與成員方法。
另外,在創建靜態內部類時不需要將靜態內部類的實例綁定在外部類的實例上。普通非靜態內部類的 對象是依附在外部類對象之中的,要在一個外部類中定義一個靜態的內部類,不需要利用關鍵字new來創建內部類的實例。靜態類和方法只屬于類本身,并不屬于 該類的對象,更不屬于其他外部類的對象。
補充:內部類標識符
每個類會產生一個.class文件,文件名即為類名。同樣,內部類也會產生這么一個.class文件,但是它的名稱卻不是內部類的類名,而是有著嚴格的限制:外圍類的名字,加上$,再加上內部類名字。
5.靜態導包
靜態導包就是java包的靜態導入,用import static代替import靜態導入包是JDK1.5中的新特性。
一般我們導入一個類都用 import com……ClassName;
而靜態導入是這樣:import static com……ClassName.* ;
這里的多了個static,還有就是類名ClassName后面多了個.* ,意思是導入這個類里的靜態方法。
當然,也可以只導入某個靜態方法,只要把 .* 換成靜態方法名就行了。
然后在這個類中,就可以直接用方法名調用靜態方法,而不必用ClassName.方法名的方式來調用。
好處:這種方法的好處就是可以簡化一些操作,例如打印操作System.out.println(…);
就可以將其寫入一個靜態方法print(…),在使用時直接print(…)就可以了。
但是這種方法建議在有很多重復調用的時候使用,如果僅有一到兩次調用,不如直接寫來的方便
在靜態導入之前:
public class TestStatic {
public static void main(String[] args) {
System.out.println(Integer.MAX_VALUE);
System.out.println(Integer.toHexString(42));
}
}
1
2
3
4
5
6
在靜態導入之后:
import static java.lang.System.out;
import static java.lang.Integer.*;
public class TestStaticImport {
public static void main(String[] args) {
out.println(MAX_VALUE);
out.println(toHexString(42));
}
}
1
2
3
4
5
6
7
8
讓我們看一下使用靜態導入特性的代碼中將發生什么:
雖然該特性通常稱為“靜態導入”,但語法必須是import static,后面跟你想導入的static成員的完全限定名稱,或者通配符。在本例中,我們在System類的out對象上進行靜態導入。
在本例中,我們可能想使用java.lang.Integer類的幾個static成員。該靜態導入語句使用通配符來表達“我想在此類中的所有靜態成員上進行靜態導入”。
現在我們終于看到靜態導入特性的好處!我們不必在System.out.println中鍵入System。太好了!另外,我們不必在Integer.MAX_VALUE中鍵入Integer。因此,在這行代碼中,我們能夠將快捷方式用于靜態方法和一個常量。
最后,我們進行更多的快捷操作,這次針對Integer類的方法。
下面是使用靜態導入的幾條原則:
你必須說import static, 不能說static import。
提防含糊不清的命名static成員。例如,如果你對Integer類和Long類執行了靜態導入,引用MAX_VALUE將導致一個編譯器錯誤,因為Integer和Long都有一個MAX_VALUE常量,并且Java不會知道你在引用哪個MAX_VALUE。
你可以在static對象引用、常量(記住,它們是static 或final)和static方法上進行靜態導入。
11.什么是方法?談談你對方法的理解
1.概念
方法其實是具有一定功能的代碼塊,我們可以把需要多次使用的功能提取成一個方法,這樣多次使用的時候也不需要把這些重復的代碼寫多次造成代碼的冗余。
2.格式
方法定義的格式:修飾符 返回值類型 方法名(參數列表){方法體}
方法簽名:方法名(參數列表)
3.注意事項
注意:我們這里說的是返回值類型而不是返回值,如果一個方法有返回值,那么返回值類型必須設置為與返回值相同的類型,并且返回值需要使用return關鍵字來返回。
4.方法的重載:
在同一個類中出現方法名相同但參數列表不同方法的現象
注意:方法之間能否構成重載,取決于方法的參數個數與類型,與方法的參數名無關
我們可以通過方法名+參數列表的方式確定要調用的是哪個方法
方法的傳值:基本類型傳遞的是實際值,引用類型傳遞的是地址
而且方法的參數屬于形參,只是格式上需要定義,但是調用方法時起不到限制的作用
形參:定義方法的時候的參數列表
實參:使用方法的時候傳入的數據
重載的意義:
是為了方便外界對方法進行調用,什么樣的參數程序都可以找到對應的方法來執行,體現的是程序的靈活性
5.方法的重寫:
子類繼承父類以后,如果子類對父類的功能不滿意,可以重寫父類的方法
但是重寫的時候需要注意如下的規則:兩同兩小一大
一大:子類方法的修飾符范圍 >= 父類方法的修飾符范圍–指的是訪問控制符
兩同:方法名相同,參數列表相同
兩小: 子類方法的返回值類型 <= 父類方法的返回值類型【這個大小是繼承關系,不是值的大小】
子類方法拋出的異常類型 <= 父類方法拋出的異常類型【這個還沒學,不用管】
注意:如果父類方法的返回值類型是void,子類保持一致即可
注意:子類不可以重寫父類的私有方法,還是因為不可見
重寫的意義:是在不修改源碼的前提下,進行功能的修改和拓展
(OCP原則:面向修改關閉,面向拓展開放)
6.方法的遞歸:
遞歸:在方法中調用自己本身
注意遞歸次數過多時,會出現棧溢出異常
== 練習題 : 求數字階乘(遞歸解法版)==
需求:接收用戶輸入的數字,計算該數字的階乘結果
已知:負數不可以有階乘,0的階乘結果是1,
5 ! = 5 x 4 x 3 x 2 x 1
package cn.cxy.design;
//需求:求用戶輸入數字的階乘結果
//f(int n)–用來求階乘
//規律:
//f(n)= nf(n-1)
//f(5)= 54321 = 5f(4)
//f(4)= 4321 = 4f(3)
//f(3)= 321 = 3f(2)
//f(2)= 21 = 2f(1)
//f(1)= 1
//
//5!=54321=120
//4!=4321
//3!=321
//2!=2*1
//1!=1
public class TestRecursion {
public static void main(String[] args) {
int result = f(15);//調用f()用來求階乘
System.out.println(result);
}
/*遞歸的兩要素 1.總結規律 2.最簡問題/
public static int f(int n) {
if(n == 1) {//最簡問題
return 1;
}else {//其他情況 nf(n-1)
//遞歸:再方法內部自己調用自己
return nf(n-1);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
== 練習題 : 遞歸求目錄總大小==
需求:遞歸求目錄的總大小 D:\ready,步驟分析如下:
1.列出文件夾中的所有資源–listFiles()–>File[]
2.判斷,當前資源是文件還是文件夾–文件夾大小為0,文件大小需要累加
–是文件,求文件的字節量大小length(),累加就行
–是文件夾,繼續列出文件夾下的所有資源–listFiles()–>File[]
–判斷,是文件,求文件的字節量大小length(),累加就行
–判斷,是文件夾,再一次列出文件夾下的所有資源
–…重復操作
也就是說,規律就是:只要是文件夾,就需要重復步驟1 2
package cn.cxy.file;
import java.io.File;
/*本類用來遞歸求目錄總大小/
public class FileSumRecursion {
public static void main(String[] args) {
//1.指定要求哪個目錄的總大小
/*注意:此處指定的目錄必須是真實存在的
* 如果傳一個不存在的文件夾會報錯,如果是傳了一個空文件夾,大小為0/
File file = new File(“D:\ready”);
//2.調用size()求目錄大小
long total = size(file);
//3.接收結果并打印
System.out.println(“文件夾的總大小為:”+total);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
練習題 : 遞歸刪除文件夾
需求:遞歸刪除文件夾 D:\ready\a
1.列出文件夾下的所有資源listFiles()
2.判斷,當前資源是文件還是文件夾
–判斷,是文件,直接刪除delete()
–判斷,是文件夾,繼續重復操作1 2
具體思路可以分為這么幾步:
1.首先,我們需要指定一個根目錄作為要刪除的對象
2.列出文件夾下的所有資源listFiles(),并進行遍歷
3.判斷當前的資源,如果是文件,直接刪除;如果是文件夾,則執行步驟2
4.將文件夾中的內容刪除完畢后,刪除文件夾本身
package cn.tedu.file;
import java.io.File;
/*本類用于遞歸刪除目錄/
public class TestFileDeleteRecursion {
public static void main(String[] args) {
//1.指定要刪除的目錄
/**為了更好的測試,注意指定的目錄是已存在的目錄,但是,千萬不要刪盤符!!!*/
/我們也有一些沒有權限的文件夾,那個是無法訪問且不能刪除的哦/
File file = new File(“D:\ready\a”);
//2.調用刪除目錄的方法
boolean result = del(file);
//3.打印刪除的結果
System.out.println(“刪除的結果為:”+result);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
12.內部類有哪些種類?又有哪些使用場景?
定義在一個類中或者方法中的類稱為內部類。
內部類可以分為以下四類:
成員內部類【這里是非靜態的】
這是最普通的內部類,它定義在一個類的內部中,就如同一個類里的成員變量一樣。
成員內部類可以無條件的訪問外部類的成員屬性和成員方法(包括 private 和 static 類型的成員)
這是因為在成員內部類中,隱式地持有了外部類的引用。
使用場景:當類 A 需要使用類 B ,同時 B 需要訪問 A 的成員/方法時,可以將 B 作為 A 的成員內部類。同時我們可以利用 private 內部類禁止其他類訪問該內部類,從而做到將具體的實現細節完全隱藏。
靜態內部類【這里是成員內部類被靜態修飾】
這是使用 static 關鍵字修飾的內部類,靜態內部類不持有外部類的引用,可以看作是和外部類平級的類。
我們想在靜態內部類中訪問外部類的成員只能 new 一個外部類的對象,否則只能訪問外部類的靜態屬性和靜態方法。
使用場景:當類 A 需要使用類 B,而 B 不需要直接訪問外部類 A 的成員變量和方法時,可以將 B 作為 A 的靜態內部類。
局部內部類
這是在代碼塊或者方法中創建的類。
局部內部類的作用域只能在其所在的代碼塊或者方法內,在其它地方無法創建該類的對象。
我們可以把局部內部類理解為作用域很小的成員內部類。
使用場景:局部內部類只用于當前方法或者代碼塊中創建、使用,屬于一次性產品,使用場景比較少。
匿名內部類
這是一個沒有名字的內部類,通常與匿名對象一起使用,實現了創建實現類+實現方法+創建對象并調用方法的功能
概括一下匿名內部類的特點:
1.必須繼承一個父類或實現一個接口,并不需要增加額外的方法,只是對繼承方法的實現或是覆蓋。
2.只是為了獲得一個對象實例,并不需要知道其實際的類型。
3.匿名內部類的匿名指的是沒有類名,而不是沒有引用指向它。
4.匿名內部類不能有構造方法,只能有初始化代碼塊。因為編譯器會幫我們生成一個構造方法然后調用。
5.匿名內部類中使用到的參數是需要聲明為 final 的,否則編譯器會報錯。
使用場景: 當我們需要實現一個接口,但不需要持有它的引用,僅需要使用一次它的某一個資源時使用
那么為什么匿名內部類中使用參數需要聲明為final呢?
因為匿名內部類是創建一個對象并返回,這個對象的方法被調用的時機不確定,方法中有修改參數的可能,如果在匿名內部類中修改了參數,外部類中的參數是否需要同步修改呢?Java 為了避免這種問題,限制匿名內部類訪問的變量需要使用 final 修飾,這樣可以保證訪問的變量不可變。
而且,除了靜態內部類,剩下的成員內部類、局部內部類、匿名內部類 都會默認隱式地持有外部類的引用。
13.談談串行、并行、并發、分布式?
比如現在有2個任務:A任務與B任務
那我們通過圖片來演示一下串行、并行與并發,大家可以結合圖片來理解:
串行
首先,A和B兩個任務運行在單核【1個CPU】線程上
其次,A和B兩個任務只能一次執行一個,在上一個任務執行完之前不會執行下一個任務。一次調用一個。
并行
首先,A和B兩個任務在同一時刻發生在多核【多個CPU】線程上
所以通常是指兩個或兩個以上的任務在同一時刻可在不同CPU上同時執行,效率較高
但注意,這個會受限于CPU線程數,如果任務數量超過了CPU線程數,那么每個線程上的任務仍然是順序執行的。
并發
是指多個線程在宏觀時間上看似同時執行,但實際上是輪流穿插執行的效果。
并發實際上是一個CPU在若干程序間的多路復用,主要是為了提高有限物理資源的運行效率。
并發與并行串行并不矛盾,如果是單核啟用并發,那就是串行并發,如果在多核【多個線程】上啟用并發,那就是并行并發。
分布式
分布式在并行處理的基礎上,強調任務正在執行的物理設備,如處理器、內存等等硬件,在物理上是分開的。
而并行計算是指在一臺計算機上的計算,在物理上不分開。
總結
- 上一篇: win7计算机限制不能安装,win7怎么
- 下一篇: Arduino :PWM详解和电路搭建以