方法、類和物件
方法、類和物件
- 方法:類似於其它語言的函式。
- 類:類是一個模板,它描述一類物件的行為和狀態。
- 物件:物件是類的一個例項,有狀態和行為。
方法
方法的基礎用法
方法宣告格式:
[修飾符1 修飾符2 …] 返回值型別 方法名(形式引數列表){
Java語句;… … …
}
方法的呼叫:
物件名.方法名(實參列表)
方法的命名:
- 方法的名字的第一個單詞應以小寫字母作為開頭,後面的單詞則用大寫字母開頭寫,不使用連線符。
- 下劃線可能出現在 JUnit 測試方法名稱中用以分隔名稱的邏輯元件。
方法的過載
方法的過載是指一個類中可以定義多個方法名相同,但引數不同的方法。 呼叫時,會根據不同的引數自動匹配對應的方法。 構成方法過載的條件:
- 形參型別、形參個數、形參順序不同
- 只有返回值不同不構成方法的過載
- 只有形參的名稱不同,不構成方法的過載
引數傳值機制
Java方法中所有引數都是“值傳遞”,也就是“傳遞的是值的副本”。 也就是說,我們得到的是“原引數的影印件,而不是原件”。因此,影印件改變不會影響原件。
- 基本資料型別引數的傳值:傳遞的是值的副本。 副本改變不會影響原件。
- 引用型別引數的傳值:引用型別指的是“物件的地址”。因此,副本和原引數都指向了同一個“地址”,改變“副本指向地址物件的值,也意味著原引數指向物件的值也發生了改變”。
類
類的定義方法
// 每一個原始檔必須有且只有一個public class,並且類名和檔名保持一致! public class Car { } class Tyre { // 一個Java檔案可以同時定義多個class } class Engine { } class Seat { }
一個類可以包含以下型別變數:
- 區域性變數:在方法、構造方法或者語句塊中定義的變數被稱為區域性變數。變數宣告和初始化都是在方法中,方法結束後,變數就會自動銷燬。
- 成員變數:(屬性,field)成員變數是定義在類中,方法體之外的變數。這種變數在建立物件的時候例項化。成員變數可以被類中方法、構造方法和特定類的語句塊訪問。
- 類變數:類變數也宣告在類中,方法體之外,但必須宣告為 static 型別。
一個類可以擁有多個方法。
構造方法
構造器也叫構造方法(constructor),用於物件的初始化。
- 構造器是一個建立物件時被自動呼叫的特殊方法,目的是物件的初始化。
- 構造器的名稱應與類的名稱一致。Java通過new關鍵字來呼叫構造器,從而返回該類的例項,是一種特殊的方法。
- 每個類都有構造方法。如果沒有顯式地為類定義構造方法,Java 編譯器將會為該類提供一個預設構造方法。
- 構造器雖然有返回值,但是不能定義返回值型別(返回值的型別肯定是本類),不能在構造器裡使用return返回某個值。
- 構造方法也可以像普通類一樣過載。
public class Puppy{
public Puppy(){
}
public Puppy(String name){
// 這個構造器僅有一個引數:name
}
}
static關鍵字
在類中,用static宣告的成員變數為靜態成員變數,也稱為類變數。 類變數的生命週期和類相同,在整個應用程式執行期間都有效。它有如下特點:
- 為該類的公用變數,屬於類,被該類的所有例項共享,在類被載入時被顯式初始化。
- 對於該類的所有物件來說,static成員變數只有一份,被該類的所有物件共享。
- 一般用“類名.類屬性/方法”來呼叫。(也可以通過物件引用或類名(不需要例項化)訪問靜態成員。)
- 在static方法中不可直接訪問非static的成員。
- static修飾的成員變數和方法,從屬於類。普通變數和方法從屬於物件的。
物件
建立物件
物件是根據類建立的。在Java中,使用關鍵字 new 來建立一個新的物件。建立物件需要以下三步:
- 宣告:宣告一個物件,包括物件名稱和物件型別。
- 例項化:使用關鍵字 new 來建立一個物件。
- 初始化:使用 new 建立物件時,會呼叫構造方法初始化物件。
示例:
public class Puppy{
public Puppy(String name){
//這個構造器僅有一個引數:name
System.out.println("小狗的名字是 : " + name );
}
public static void main(String[] args){
// 下面的語句將建立一個Puppy物件
Puppy myPuppy = new Puppy( "tommy" );
}
}//小狗的名字是 : tommy
訪問例項變數和方法
//例項化物件
Object referenceVariable = new Constructor();
//訪問類中的變數
referenceVariable.variableName;
//訪問類中的方法
referenceVariable.methodName();
this關鍵字
this的本質就是建立好的物件的地址, 由於在構造方法呼叫前,物件已經建立。因此,在構造方法中也可以使用this代表“當前物件”。
this最常的用法:
- 在程式中產生二義性之處,應使用this來指明當前物件。普通方法中,this總是指向呼叫該方法的物件。構造方法中,this總是指向正要初始化的物件。
- 使用this關鍵字呼叫過載的構造方法,避免相同的初始化程式碼。但只能在構造方法中用,並且必須位於構造方法的第一句。
- this不能用於static方法中。
原始檔宣告規則
- 一個原始檔中只能有一個 public 類
- 一個原始檔可以有多個非 public 類
- 原始檔的名稱應該和 public 類的類名保持一致。例如:原始檔中 public 類的類名是 Employee,那麼原始檔應該命名為Employee.java。
- 如果一個類定義在某個包中,那麼 package 語句應該在原始檔的首行。
- 如果原始檔包含 import 語句,那麼應該放在 package 語句和類定義之間。如果沒有 package 語句,那麼 import 語句應該在原始檔中最前面。
- import 語句和 package 語句對原始檔中定義的所有類都有效。在同一原始檔中,不能給不同的類不同的包宣告。
面向物件的記憶體分析
Java虛擬機器的記憶體可以分為三個區域:
- 棧stack
- 棧描述的是方法執行的記憶體模型。每個方法被呼叫都會建立一個棧幀(儲存區域性變數、運算元、方法出口等)。
- JVM為每個執行緒建立一個棧,用於存放該執行緒執行方法的資訊(實際引數、區域性變數等)。
- 棧屬於執行緒私有,不能實現執行緒間的共享。
- 棧的儲存特性是“先進後出,後進先出”。
- 棧是由系統自動分配,速度快,棧是一個連續的記憶體空間。
- 堆heap
- 堆用於儲存建立好的物件和陣列(陣列也是物件)。
- JVM只有一個堆,被所有執行緒共享。
- 堆是一個不連續的記憶體空間,分配靈活,速度慢。
- 方法區method area(又叫靜態區)
- JVM只有一個方法區,被所有執行緒共享。
- 方法區實際也是堆,只是用於儲存類、常量相關的資訊。
- 用來存放程式中永遠是不變或唯一的內容。(類資訊、靜態變數、字串常量等)
內部類
一般情況,我們把類定義成獨立的單元。有些情況下,我們把一個類放在另一個類的內部定義,稱為內部類(innerclasses)。
內部類可以使用public、default、protected 、private以及static修飾。而外部頂級類(我們以前接觸的類)只能使用public和default修飾。
內部類只是一個編譯時概念,一旦我們編譯成功,就會成為完全不同的兩個類。對於一個名為Outer的外部類和其內部定義的名為Inner的內部類。編譯完成後會出現Outer.class和Outer$Inner.class兩個類的位元組碼檔案。所以內部類是相對獨立的一種存在,其成員變數/方法名可以和外部類的相同。
內部類的分類
-
成員內部類
-
非靜態內部類
可以使用private、default、protected、public任意進行修飾。 類檔案:外部類$內部類.class
-
非靜態內部類必須寄存在一個外部類物件裡。因此,如果有一個非靜態內部類物件那麼一定存在對應的外部類物件。非靜態內部類物件單獨屬於外部類的某個物件。
-
非靜態內部類可以直接訪問外部類的成員,但是外部類不能直接訪問非靜態內部類成員。
-
非靜態內部類不能有靜態方法、靜態屬性和靜態初始化塊。
-
外部類的靜態方法、靜態程式碼塊不能訪問非靜態內部類,包括不能使用非靜態內部類定義變數、建立例項。
-
成員變數訪問要點:
- 內部類裡方法的區域性變數:變數名。
- 內部類屬性:this.變數名。
- 外部類屬性:外部類名.this.變數名。
-
內部類的訪問:
-
外部類中定義內部類:
new Inner()
-
外部類以外的地方使用非靜態內部類:
Outer.Inner varname = new Outer().new Inner()
-
-
-
靜態內部類
- 當一個靜態內部類物件存在,並不一定存在對應的外部物件。 因此,靜態內部類的例項方法不能直接訪問外部類的例項方法。
- 靜態內部類看做外部類的一個靜態成員。 因此,外部類的方法中可以通過:“靜態內部類.名字”的方式訪問靜態內部類的靜態成員,通過 new 靜態內部類()訪問靜態內部類的例項。
-
-
匿名內部類:
-
適合那種只需要使用一次的類。比如:鍵盤監聽操作等等。
-
匿名內部類沒有訪問修飾符。
-
匿名內部類沒有構造方法。因為它連名字都沒有那又何來構造方法呢。
new 父類構造器(實參類表) \實現介面 () { //匿名內部類類體! }
-
匿名內部類的使用
this.addWindowListener(new WindowAdapter(){ @Override public void windowClosing(WindowEvent e) { System.exit(0); } } ); this.addKeyListener(new KeyAdapter(){ @Override public void keyPressed(KeyEvent e) { myTank.keyPressed(e); } @Override public void keyReleased(KeyEvent e) { myTank.keyReleased(e); } } );
-
-
區域性內部類
-
作用域只限於本方法
-
對於比較複雜的情況,需要建立一個非公用的類輔助,此即為區域性內部類
-
示例
public class Test2 { public void show() { //作用域僅限於該方法 class Inner { public void fun() { System.out.println("helloworld"); } } new Inner().fun(); } public static void main(String[] args) { new Test2().show(); } }
-
Lambda表示式
Lambda表示式相當於對匿名內部類又一次簡化,但僅適用於只有一個待實現方法的情況。
示例:
new Thread(()->{//只有run()方法待實現,故可以使用
for(int i=0;i<20;i++){
System.out.println("helloworld");
}
}).start();