1. 程式人生 > >Java基礎筆記2——方法和麵向物件

Java基礎筆記2——方法和麵向物件

Java基礎筆記2
六、方法
將要重複使用的邏輯或者是程式碼提取到一個新的結構——方法。
修飾符 返回值型別 方法名(引數列表){
方法體;
return 返回值;
}
無返回值的方法用void定義,void方法也可以寫return語句,但只能寫為return;用於規避掉一些非法資料。
方法的定義過程需要明確返回值型別,明確引數。
明確引數型別——根據方法的執行結果的型別來確定。
定義方法的時候在()內定義的引數稱為形式引數,簡稱形參。呼叫方法的時候傳入的資料稱之為實參。
方法簽名:方法名+引數列表,例method(int a)
同一個類中不能存在方法簽名相同的方法。
方法的傳參
形參:定義方法的時候()定義的變數
實參:呼叫方法的時候傳入的資料
對於基本型別而言,傳參傳遞的是實際值,所以在另一個方法中改變這個引數的值不會影響原來方法的資料。
對於引用型別而言,傳參傳遞的是地址。如果地址不發生改變,則影響原來方法中的物件;如果地址放生改變,則不影響原來的物件。
可變引數
本質上是一個數組,可以傳入任意個數的引數。
public static int sum(int … ns){ //…代表0或多個引數
int sum=0;
for(int n:ns){ //遍歷引數,求和
sum+=n;
}
可變引數可以直接傳入一個數組。
int[] num={1,2,3,4,5,6,7,8};
sum(num); //呼叫sum方法
注意:在一個方法裡只可以有一個可變引數,只能用一次,且必須在引數列表最後一個位置出現。
public static int sum(int n3,int … ns){
int sum=0;
for(int n:ns){
sum+=n;
}
return sum*n3;
方法過載
在同一個類中,定義多個方法名一致而引數列表不同(引數個數或者對應位置上的引數型別不一樣)的方法。
方法有歧義的不能構成過載。如add(int i,int j)和add(int a,int b),只是形參變數名不一樣而已,實際方法簽名一致。
所謂引數列表不同實際上是看每一位上的引數型別是否不同或者引數個數是否不同。和修飾符、返回值型別、異常沒有關係。
引數型別不一樣,排序不一樣,可以構成方法過載,如下①②兩種方法。
①add(int i,double j)
②add(double j,int i)
根據實參型別確認呼叫的方法,就近原則——優先呼叫引數型別最符合的方法。
方法的遞迴
定義:在方法中呼叫自己本身。
應用:利用遞迴可以輕鬆求斐波那契數列: 一個數總是前兩個數之和
0,1,1,2,3,5,8,13…… f(n)=f(n-1)+f(n-2);
方法在棧記憶體中執行,遞迴在使用的時候不能遞迴層數太深,不然遞迴過程容易導致棧溢位錯誤StackOverflowError。
從空間上考慮,遞迴比迴圈更耗費記憶體;從時間考慮,遞迴比迴圈要花費更多的時間。
遞迴的效率要低於迴圈。遞迴應用於某些方面易於理解。
迴圈——正推理,遞迴——反推理。
方法的修飾:
用static修飾的方法是共享的,可以直接呼叫方法。無static修飾的方法需要new一個類物件,通過引用物件的方式呼叫方法。
許可權修飾符
本類中 子類中 同包類中 其他類中
public 可以 可以 可以 可以
protected 可以 可以 可以 不可以
預設 可以 同包子類可以 可以 不可以
private 可以 不可以 不可以 不可以
關於protected方法和屬性
如果用protected來修飾變數與方法: 若子類a,b與父類f在同一個包,則b可以訪問a的變數與方法,a也可以訪問b的變數和方法。如果有一個子類c在另一個包,也c無法訪問與父類在同一個包的子類a,b的變數與方法,但是與父類在一個包的子類a,b可以訪問c的變數,但不能訪問方法。
七、面向物件
面向物件特徵:多型、繼承、封裝
面向物件本身是相對於面向過程而言的。
面向物件是基於面向過程。
面向過程和麵向物件是思維方式。
在java裡,萬物皆物件!
比較分析:
①面向過程:注重每一個步驟,瞭解操作過程
②面向物件:注重這個物件,不瞭解操作過程,但獲取物件就擁有物件的一切功能。
面向過程的結構化程式設計
案例:列印員工資訊 ,修改員工資訊後再列印
特點:執行過程是什麼樣的,程式碼就寫成什麼樣,程式碼編寫更偏向於計算機底層的執行思維
面向過程的結構化程式的弊端:
1.缺乏對資料的封裝
2.資料和方法的分離
面向物件程式設計
更接近於人的思維方式。
將資料和方法封裝為一個整體,java中將其稱為類。
什麼是類:類是一類事物的模板。
類的定義:成員變數(屬性) 方法(行為)
一個java檔案只能有一個公共類,可以有多個普通類。
成員變數:
如果一個變數宣告在類的裡邊,方法的外邊,那麼這個變數就叫做成員變數。
成員變數會被程式預設初始化。
預設初始值取決於資料型別:
①int、byte、short預設值0
②long型別預設值0L
③float型別預設值0.0f
④double型別預設值0.0
⑤char型別預設值’\u0000’(表示空字元)
⑥boolean型別預設值是false
⑦引用型別,如陣列、String類預設值全是null
成員變數和區域性變數的區別:
1.定義位置:成員變數定義在類內,區域性變數定義在方法內。
2.作用範圍:成員變數作用域整個類內,區域性變數作用於方法內。
3.儲存位置:成員變數儲存在堆記憶體,區域性變數存在棧記憶體
4.成員變數會自動賦予一個預設值,區域性變數不會,需賦初始值才能使用。
5.生命週期:成員變數在物件被建立的時候出現,在物件被銷燬時才釋放;區域性變數在程式碼執行完之後被釋放。
物件:是經由模板創建出來的具體存在的例項。
類和物件的關係:類是物件的概括,物件是類的具體展現。
呼叫物件中的內容,通過引用來呼叫。
Java將所佔用的記憶體劃分為5塊:棧記憶體、堆記憶體、方法區、本地方法棧、暫存器(PC計數器)。其中靜態常量池在方法區裡。
物件被建立後不會自動銷燬,遵循垃圾回收機制。
構造方法
構造方法名必須和類名一致。
class Student{
public Student() {} //此處如果不寫,編譯時會預設新增
}
(1)當在程式中使用new運算子生成物件時,系統就會自動呼叫類的構造方法。
(2)如果程式沒有明確的定義構造方法,系統會自動為該類新增預設的無參構造方法。
注意:如果使用者定義了(含參)構造器,無引數構造器就不會被自動提供,如果要使用無引數構造器,需要自己定義。
(3)構造方法也能過載。一個類可以有多個構造方法,如下例:
class Student{
String name;
int age;
char gender;

public Student() {}
public Student(String name) {}
public Student(char gender) {}
public Student(String name,char gender) {}
public Student(String name,int age,char gender) {}

}
注意:構造方法沒有返回值型別。

類名命名習慣首字母大寫;方法名習慣首字母小寫,遵循駝峰命名法。
類名可以用public/private/abstract這三個許可權修飾,也可以不寫。
用static修飾的方法只能呼叫static修飾的屬性。
構造程式碼塊:
放在類裡面,構造方法前。
在建立物件的時候,先於構造方法執行一次。

區域性程式碼塊:
定義在主方法內。
限制區域性變數的作用範圍,縮短區域性變數的生命週期,提高棧記憶體利用率。

this關鍵字的使用方法:
①this代替當前在活動的這個物件
②this代替一個物件,用於呼叫屬性
③this語句,可以呼叫本類中其他的對應形式的構造方法。
④this語句只能放在方法裡的第一行

繼承
對一部分的類進行分析,將這些類中共有的屬性和方法提取到了一個新的類中,然後利用關鍵字extends讓原來的類和新的類產生了關係,這種關係稱為繼承。
子類/派生類 extends(繼承) 父類/基類/超類
子類可以用父類一部分屬性和方法。
在java中,支援單繼承——一個子類只能繼承一個父類,但是一個父類可以有多個子類。支援多層繼承——子類有一個父類,但是這個子類可以作為別的子類的父類(爸爸繼承爺爺,爸爸可以被兒子繼承,但是兒子不能直接繼承爺爺)。
c語言支援多繼承——一個子類可以有多個父類,一個父類可以有多個子類。
單繼承和多繼承的優劣性比較:
1.多繼承程式碼複用性更高,優於單繼承
2.單繼承具有明確性,而多繼承呼叫時容易產生歧義。
注意:子類可以繼承父類所有屬性和方法,前提是這些屬性和方法對子類全部可見。例如用private修飾的父類屬性,子類無法直接繼承。

如果一個類用protected修飾其成員變數或者函式,那麼這個類的子類可以擁有訪問這個成員變數或者函式的權利,而其他類仍然像private的限制一樣無法訪問這個類的protected成員。

封裝
體現形式:內部類、方法、屬性的私有法——將屬性用private修飾,然後提供對外的
get和set方法來獲取或者設定屬性,在方法中對屬性進行限制是資料更加的符合場景要求。
意義:提高複用性,保證資料的合法性
優勢:1.提供程式碼的複用性。2.保證資料的合法性。

方法的過載
方法返回值型別為物件

super關鍵字
表示父類物件的引用。
通過super可以在子類中呼叫父類的方法和屬性。
如果在子類的建構函式中沒有手動建立一個父類物件,那麼在編譯的時候會預設新增引用父類的無參構造super()。
super語句呼叫父類中對應形式的構造方法。
注意:
(1)如果父類是含參構造,那麼super(引數) 括號裡也要有對應父類的引數。
(2) super語句必須寫在子類構造方法的第一行。
(3) super語句和this語句不能同時出現。
子類除了能自動繼承父類的屬性和方法外,還可以定義自己的屬性和方法。
protected修飾的屬性和方法可以在本類中、子類中、同包類中使用。
在子類中使用和子類物件使用不是一回事。
普通類裡面的方法,要在main方法裡通過物件呼叫才能輸出類方法裡的輸出語句。
方法的重寫:
在父子類中存在方法簽名一致的非靜態方法,稱之為方法的重寫/覆蓋。
方法在重寫的過程中需要遵守的5個原則——兩等兩小一大:
1.方法簽名相同
2.子類重寫方法的許可權修飾符範圍要大於等於父類
3.如果父類方法的返回值型別是引用型別,那麼子類重寫的方法的返回值型別和父類方法返回值型別一致或者是父類方法返回值型別的子類。
4.子類丟擲的異常型別不能比父類的更寬泛,異常型別個數不能比父類方法的更多。
5.如果父類方法的返回值型別是基本型別/void,子類在重寫方法是要求返回值型別一致。
@Override //用於註解當前方法是一個重寫的方法。
總結:過載和重寫的異同點
無論是方法的過載還是方法的重寫,都是行為的多型。
過載:在同一個類中,存在方法名一致而引數列表不同的方法。方法的過載只和方法簽名有關,和修飾符、返回值型別以及異常沒有關係。本身是一種編譯時多型。
重寫:在父子類中,存在方法簽名一致的非靜態方法。在構成重寫的時候,要求子類重寫的方法的許可權修飾符的範圍要大於等於父類對應方法的許可權修飾符的範圍。如果方法的返回值型別是基本型別或者是void,那麼子類在重寫的時候要保持一致。如果方法的返回值型別是引用型別,那麼子類在重寫方法的時候返回值或者和父類對應方法的返回值型別一致,或者重寫的方法的返回值型別是父類對應方法的返回值型別的子類。如果父類方法丟擲了編譯時異常,那麼子類在重寫的時候丟擲的編譯時異常不能超過父類異常的範圍。重寫本身是一種執行時多型。
多型:
編譯時多型:方法的過載
執行時多型:(基於繼承)
①向上造型:用父類聲明瞭一個物件,用子類建立了這個物件。
Person p=new Doctor();
利用向上造型,呼叫的是重寫後的方法。
在使用向上造型的時候,只會檢查宣告類和實現類直接是否有繼承關係,而並不會檢查具體哪一個是實現類。只有在執行時才會看是哪一個具體的子類,然後根據子類來開闢空間進行儲存。
利用向上造型來宣告的這個物件,意味著在編譯期間不確定是哪個子類。
②方法的重寫
執行時才知道呼叫的是哪個方法。
所以為了防止調用出錯,所以此時不允許呼叫子類中單獨定義的方法。
注意:在java中,基本型別之間是沒有繼承關係的。基本型別之間之所以能夠相互轉化,是因為基本型別所佔的空間的大小不一致而且都是表示的數字。
Static——靜態
修飾變數、方法、程式碼塊以及內部類。
static修飾的變數為靜態變數/類變數。
private static修飾的只有內部類,外部類不能用static修飾。
靜態變數隨著類的載入而載入到方法區,並賦初始值。靜態變數先於物件出來,故靜態變數不依賴於物件,可以通過類名.呼叫屬性。例:Person.gender=”男”;
每一個物件存的是這個靜態變數的地址,所以靜態變數是被共享的。

java檔案---->編譯---->class檔案---->ClassLoader(類載入器)---->(進入方法區)---->核心類庫—>主方法main(String[])---->靜態常量池
1.靜態變數可以在方法中定義嗎?——不可以——方法在呼叫的時候執行,到棧記憶體中執行。而靜態變數是在類載入時初始化,存在方法區。
2.靜態變數能否定義到建構函式中?——不可以——靜態變數在類載入的時候初始化,建構函式在建立物件的時候執行,在棧記憶體中執行。
為什麼靜態成員、靜態方法中不能用this和super關鍵字?
因為this代表的是呼叫這個函式的物件的引用,而靜態方法是屬於類的,不屬於物件,靜態方法成功載入後,物件還不一定存在 2. 在問題之前先講super的用法:1.super的用法跟this類似,this代表對本類物件的引用,指向本類已經建立的物件;而super代表對父類物件的引用,指向父類物件;2.靜態優先於物件存在;3.由上面的1.和2.知:因為靜態優先於物件存在,所以方法被靜態修飾之後方法先存在,而方法裡面要用到super指向的父類物件,但是所需的父類引用物件晚於該方法出現,也就是super所指向的物件沒有,當然就會出錯。綜上,靜態方法中不可以出現super關鍵字。 3. 首先你要明白物件和類的區別。 this和super是屬於物件範疇的東西,而靜態方法是屬於類範疇的東西所有的成員方法,都有一個預設的的引數this(即使是無參的方法),只要是成員方法,編譯器就會給你加上this這個引數如:
Class A中 void method1(){} 實際上是這樣的--------> void method1(A this)
void method2(int x){} 實際上是這樣的--------> void method2(A this, int x)
而靜態方法與物件無關,根本不能把物件的引用傳到方法中,所以不能用this 4. 在一個類中定義一個方法為static,則為靜態方法,那就是說,無需本類的物件即可呼叫此方法,呼叫一個靜態方法就是“類名.方法名”
堆記憶體只用來儲存物件,不能用來執行程式碼。
Person p=new Person(); //儲存在堆記憶體中,地址引用是在棧記憶體中
static Person p=new Person(); //儲存在堆記憶體中,地址引用是在方法區中
靜態方法
在類載入的時候載入到方法區中,在方法區中不執行只是儲存,在方法被呼叫的時候到棧記憶體中執行。靜態方法比物件要先出來,所以可以通過類名來呼叫靜態方法。
例Arrays.toString()
在靜態方法中可以定義靜態變數嗎?——不可以——靜態方法只有在被呼叫的時候才會執行,只有執行的時候才會將方法中的變數進行初始化,方法在棧記憶體中執行,所以方法中的變數也是儲存在棧記憶體中。靜態變數在類載入的時候初始化,靜態變數儲存在方法區中 。
在靜態方法中可以直接呼叫本類中的非靜態方法嗎?——不可以——非靜態方法在本類中是通過this,而this代表當前物件的引用。靜態方法是在物件之前出現的,也就意味著靜態方法執行的時候是沒有物件的。
靜態方法可以過載嗎?——可以——方法的過載只跟方法簽名有關,跟修飾符沒有關係。
靜態方法可以重寫嗎?——不可以——方法重寫是指方法簽名一致的非靜態方法。
父子類中是否可以出現方法簽名一致的靜態方法——可以——但是這種形式不是重寫,稱為靜態方法的隱藏hide。父子類存在方法簽名一致,要麼都是靜態,要麼都是非靜態。
靜態方法看的是宣告類,非靜態方法看的是實現類。
靜態方法可以被繼承嗎?——可以

靜態程式碼塊
寫在類裡面,方法前,用{}括起來,前面加static修飾。
靜態程式碼塊只在類載入的時候執行一次。在棧記憶體中執行。無論建立多少個物件,靜態程式碼塊都只執行一次。
靜態程式碼塊在呼叫方法前執行。
執行順序:載入父類---->載入子類---->建立父類物件---->建立子類物件
靜態程式碼塊—>建立類內物件—>程式碼塊—>構造方法(若建立的物件用static修飾時排序往前一位)

Windows—>Show View—>Tasks—>可以快速查詢備註TODO的程式碼
final
修飾資料、方法及類。
final修飾的資料稱為常量,定義好後值不可變。如果是基本型別的常量,實際值不可變;如果是引用型的常量,表示地址不可變,而其中的元素或者屬性可以改變。
final定義常量,在物件建立完成之前給值。
Static final 修飾成員變數成為常量,命名規範:所有字母都大寫,如果由多個單片語成,單詞之間用_隔開。
final修飾的變數必須初始化。初始化根據變數型別而不同:
1、static變數。只能在定義,或者靜態塊中初始化。
2、普通例項變數。可以在定義,非靜態塊,建構函式中初始化。
3、區域性變數。只能在定義時初始化。
class A{
final int i;
{
i=4;
}
public A(){
}
}
如果是靜態常量,需要在類載入完成之前給值。
class A{
static final int i;
static{
i=4;
}
public A(){
}
}
final修飾的方法可以被過載,可以被繼承,但不能重寫/隱藏。
final修飾類:最終類,不能被繼承。最終類沒有子類。

Final類
當關鍵字fina用來修飾類時,其含義是該類不能在派生子類。換句話說,任何其他類都不能繼承用final修飾的類,即使該類的訪問限制為public型別,也不能被繼承;否則,將編譯報錯。
那麼什麼時候應該使用final修飾類呢?只有當需要確保類中的所有方法都不被重寫時才應該建立最終(final)類,final關鍵字將為這些方法提供安全,沒有任何人能夠重寫final類中方法,因為不能繼承。
Final方法
當用final關鍵字修飾方法後,該方法在子類中將無法重寫,只能繼承。
要恰當使用final的方法,只有在子類覆蓋某個方法會帶來問題時,再將此方法設為final的方法,一般情況下可以不必使用
abstract
一個類中的所有子類都重寫了父類的某個方法,可以把父類的這個方法宣告為一個抽象方法。而抽象方法所在的類必須是抽象類。
抽象類不能用java語言例項化(建立物件)。
抽象方法一定不能用final、static、private修飾。
抽象類的許可權是預設的
java底層是c語言架構的。
抽象類中不一定有抽象方法。
抽象類中可以定義抽象方法,也可以定義實體方法,可以定義屬性。
意義:利用抽象類來分門別類(明確類:知道抽象類是animal,希望實現的是cat的方法。 )
抽象類必須有子類,子類方法重寫所有抽象父類的方法,除非子類也是抽象類。
抽象方法與抽象(實體)方法可以過載。
抽象方法不能用static/final修飾。——static修飾的方法可以直接呼叫,而抽象方法不能;static修飾的方法不能被重寫。
抽象方法不能用private修飾,因為private修飾的方法只能在本類中使用,對子類不可見。
如果抽象方法用的是預設許可權,那麼對子類有什麼要求?——要求父子類必須是同包package。
抽象類中的構造方法能否私有化?——可以——但只能在類內使用。
抽象類能否用final修飾?——不可以——因為final修飾的類不能被繼承。
介面
用interface定義介面,類用implements關鍵字實現介面。
接口裡可以定義屬性,系統預設用public static final修飾(可以不寫),值不可變。
接口裡都是抽象方法,預設用public abstract修飾,可以不寫。
介面不能有構造方法,介面不是類。
可以用介面宣告,實現類建立。
Animal a=new Pig(); //Animal是介面 ,Pig是實現類。
在Java中,支援單繼承,多實現。——一個類只能繼承一個類,可以實現多個介面。此時形成網狀結構。在網狀結構中購買香菸判斷兩個點之間是否有繼承關係是一件相對複雜的事情。
為了提高編譯效率,在編譯期間,放棄對介面的檢查。故任意一個介面強轉任何一個物件時編譯不報錯,到執行時才會真正檢查是否能夠強轉。
類實現介面後,必須實現介面所有方法;類中的方法都是public修飾。
多實現問題點:如果一個類實現了多個介面,並且這多個介面中存在了方法簽名一致的方法就可能會導致方法的重寫產生歧義。
class Pig implements Animal,Pet{} //介面名用逗號“,”隔開。
介面之間可以繼承,是多繼承。介面之間的繼承用extends關鍵字。
抽象類和介面的對比

一 介面和抽象類的相似性
1 介面和抽象類都不能被例項化,它們都位於繼承樹的頂端,用於被其他類實現和繼承。
2 介面和抽象類都可以包含抽象方法,實現介面或繼承抽象類的普通子類都必須實現這些抽象方法。
二 介面和抽象類的區別
1 接口裡只能包含抽象方法,靜態方法和預設方法,不能為普通方法提供方法實現,抽象類則完全可以包含普通方法。
2 接口裡只能定義靜態常量,不能定義普通成員變數,抽象類裡則既可以定義普通成員變數,也可以定義靜態常量。
3 介面不能包含構造器,抽象類可以包含構造器,抽象類裡的構造器並不是用於建立物件,而是讓其子類呼叫這些構造器來完成屬於抽象類的初始化操作。
4 接口裡不能包含初始化塊,但抽象類裡完全可以包含初始化塊。
5 一個類最多隻能有一個直接父類,包括抽象類,但一個類可以直接實現多個介面,通過實現多個介面可以彌補Java單繼承不足。
內部類
放在類裡面的類,也叫巢狀類。
內部類使用有很多限制。
方法內部類:定義在方法裡的類,也叫區域性內部類。
只能在定義它的方法中使用。
內部類不能定義靜態變數和靜態方法。可以定義靜態常量static final int i=1;
方法內部類可以使用外部類的一切屬性和方法。
方法內部類不能使用當前方法中的區域性變數,只能使用區域性常量final int i=1。
存在意義:提高程式碼複用性。(在一個方法裡可以重複利用。)
內部類可以繼承類也可以實現介面。
方法內部類只能用abstract或final修飾。
如果內部類和外部類存在方法簽名一致的方法,外部類.this.方法名來呼叫外部類中對應的方法。
Outer.this.method();
成員內部類:
定義在類裡面。
系統生成的檔案預設名字:外部類 . c l a s s O u t e r 6 內部類.class 例:Outer6 Inner7.class
成員內部類可以有屬性、方法 。
成員內部類不允許呼叫靜態屬性和靜態方法。
成員內部類可以使用外部類的一切屬性和方法,可以繼承類也可以實現介面。
可以修飾類的修飾符:public、abstract、final預設。
可以修飾方法:static、final、abstract、strictfp、sysnchronized、native
可以修飾屬性的修飾符:許可權修飾符、static、final、volatile
在類外建立內部類物件需要使用外部類物件來建立。兩種例項化方法如下:
① Outer o=new Outer();
Outer.Inner o1=o.new Inner();
② Outer.Inner o1=new Outer().new Inner();
靜態內部類:
靜態內部類可以定義靜態屬性和靜態方法。
靜態內部類只能使用外部類的靜態屬性和靜態方法。

匿名內部類
只要一個類可以被繼承,那麼就可以存在匿名內部類。
程式設計中用的最多。
本質上是繼承了對應的類或實現了對應的介面。
最終類不存在匿名內部類。
匿名內部類定義在方法中,那麼使用規則和方法內部類一致。
匿名內部類只能使用外部用final修飾的變數(即常量)。

內部介面:類中定義的介面
類中定義的介面及介面中的定義的類和介面都是靜態的。
總結:在java中,類中可以定義類,類中定義介面,介面中定義類,介面中定義介面。