1. 程式人生 > >對於Java類的思路總結1

對於Java類的思路總結1

Java是面向物件的程式設計語言。類用於描述客觀客觀世界某一類物件的共同特徵,而物件則是具體存在。可以把類當作一種自定義型別,可以使用類來定義變數,這種變數統稱為引用變數(引用變數儲存的是堆記憶體中的一塊地址,相當於C語言中的指標),也就是說,所有類都是引用型別。
1定義一個普通類(不包括內部類)通常要用到以下幾種修飾符
public,final,abstract或者完全省略修飾符。
Java通常有四個級別訪問控制級別。
在這裡插入圖片描述
普通類不能用private修飾,因為private訪問控制權限在同一個類中,普通類就算能用private修飾也沒有意義。(編譯時也會報錯)
(1)一個原始檔只能有一個public類


針對一個Java原始檔(也稱為”編譯單元“)只會接受一個public類,否者會報錯)
(2)在Java檔案中也可以沒有public類,它並不是必須的
(3)public類的名字要與檔名相同
只是為了方便JVM(虛擬機器)在相應的路徑找到所對應的位元組碼檔案。
2定義一個類通常有以下幾種成員

        (1)成員變數
	(2)方法
	(3)構造器
	(4)初始化塊
	(5)內部類

先說說成員變數
(1)成員變數
成員變數修飾符:public,protected,private(訪問控制權限看上表)
static,final
static–>類成員變數(屬於該類本身),否者為例項變數
final(final類的時候詳細講)
注意:
靜態成員不能訪問非靜態成員


原理:程式最終在記憶體中執行,變數只有在記憶體中佔有一席之地才能被訪問。類的靜態成員(變數和方法)屬於類本身,在類載入中就會為靜態成員分配記憶體,可以通過類名直接訪問,此時不會為非靜態成員分配內。
類的非靜態成員屬於類的物件,所以只有在類的物件產生時才會分配記憶體,然後通過物件去訪問,建立物件時,並不會為靜態成員分配記憶體
在一個類的靜態成員中訪問其非靜態成員之所以會出錯是因為在類的非靜態成員不存在時類的靜態成員就已經存在了,訪問一個記憶體中不存在的東西當然會出錯
而類又在什麼時候載入呢?
由引導類載入器負責載入的核心類比如String類在JVM啟動時(main方法開始執行前)就會被載入,其他類在使用前(new它物件或呼叫其靜態方法訪問靜態域等等前)會被載入,要注意的是子類被載入前它的所有父類要根據父到子的順序被逐一載入
(2)方法

修飾符:public,protected,private(訪問控制權限看上表)
static,final,abstract(比成員變數多的一個修飾符)
static–>類方法(屬於類本身)
final(final類的時候詳細講)
abstract–>(抽象類的時候詳細講)
返回值
允許返回Java語言允許的任何資料型別,包括引用型別和基本型別
(3)構造器
構造器是一個類建立一個物件的根本途徑,如果沒有構造器,這個類通常無法建立例項,所以當沒有為一個類提供構造器時,系統會預設為這個類建立一個無參,無具體實現的構造器。一旦程式為一個類提供了構造器,系統將不再為該類提供構造器。
構造器是一個特殊的方法
修飾符 public,protected,private或者省略
構造器名 必須與類名相同
形參列表 與普通方法完全相同
注意定義構造器不需要指定返回值,連void也不能寫,但構造器其實是有返回值的,當用new呼叫構造器時,返回了類的一個例項,因此構造器返回值型別總是當前類,無需定義返回值型別,但必須之一,不要再構造器中顯式的用return來返回當前類的物件,應為構造器的返回值都是隱式的
(4)初始化塊
沒有名字,也就沒有標識,無法通過類或物件來呼叫初始化塊,初始化塊只在建立Java物件時隱式執行,而且在執行構造器前執行。一個類裡可以有多個初始化塊(相同型別的初始化塊定義多個並沒有意義,因為只有建立物件時隱式呼叫初始化塊,且他們都是全部執行,完全可以把它們合併到一個初始化塊中),相同型別(static和普通型別)的初始化塊之間有順序:先定義先執行。初始化塊內程式碼可以使用任何可執行的語句,包括定義區域性變數,迴圈控制語句等等

public class InstanceInitTest
{
   // 先執行初始化塊將a例項變數賦值為6
   {
      a = 6;
   }
   //再執行將a例項變數賦值為9
   int a = 9;
   public static void main(String[] args)
   {
      //下面程式碼將輸出9      System.out.println(new InstanceInitTest().a);
   }
}

注意:當Java建立一個物件時,系統先為該物件的所有例項變數分配記憶體(前提是該類已經被載入過了)(建立物件時是不會為為類變數分配記憶體的),接著程式開始對這些例項變數進行初始化,其初始化順序是:先執行初始化塊或宣告例項變數時指定的初始值(這兩個地方指定初始值的執行順序與他們在原始碼中的排列順序相同),再執行構造器裡指定的初始值。
初始化塊與構造器的區別於聯絡
從某種程度講,初始化塊是構造器的補充,初始化塊總是在構造器執行之前執行,系統同樣可以用初始化塊來進行物件的初始化操作。
與構造器不同的是,初始化塊是一段固定執行的初始化塊程式碼,它不能接受任何引數。因此初始化塊對同一個類的所有物件所進行的處理化處理完全相同。基於這個原因,不難發現初始化塊的基本用法,如果有一段初始化處理程式碼對所有物件完全相同,且無需接收任何引數,就可以把這段程式碼提取到初始化塊中。通過把多個構造器中相同程式碼提取到初始化塊中定義,能更好的提高初始化程式碼的複用率,提高整個應用的可維護性。
實際上初始化塊是一個”假象“,使用javac命令編譯Java類後,該類中的初始化塊會消失----初始化塊程式碼會被“還原”到每個構造器中,且位於所有程式碼的前面。
與構造器類似,建立一個Java物件時,不僅會執行該類的普通初始化塊和構造器,而且系統會一直上溯到java.lang.Object類的初始化塊和構造器(繼承,Object類是所有類的父類),先執行Object類的初始化塊,開始執行Object類的構造器依次向下執行其父類的初始化塊,開始執行其父類的構造器…最後才執行該類的初始化塊和構造器,返回該類物件。
靜態初始化塊
static修飾,也被稱為類初始化塊,對整個類進行初始化處理。屬於類成員,同樣需要遵循靜態成員不能訪問非靜態成員的規則。
系統在類初始化階段執行靜態初始化塊,而不是在建立物件時才執行,因此靜態初始化塊總是比普通初始化塊先執行。
與普通初始化塊類似,系統在類初始化階段執行靜態初始化塊,不僅會執行本類的靜態初始化塊,而且還會一直上溯到java.lang.Object類的靜態初始化塊(如果它包含靜態初始化塊),先執行Object類的靜態初始化塊,然後執行其父類的靜態初始化塊…最後才執行該類的靜態初始化塊,經過這個過程,才完成了該類的初始化過程,才可以在系統中使用這個類,包括訪問該類的類方法,類變數或者用這個類來建立例項。
java系統載入並初始化某個類時,總是保證該類的所有父類(直接的和間接的)全部載入並初始化。
當JVM第一次主動使用某個類時,系統會在類準備階段為該類的所有靜態成員變數分配記憶體,在初始化階段則負責初始化這些靜態成員變數,初始化這些靜態成員變數就是執行類的類初始化塊或者宣告該類成員變數時指定的初始值,他們的執行順序與原始碼中的排列順序相同。
3物件的產生和使用
當一個物件被建立成功了,這個物件將被儲存在堆記憶體中,java不允許直接訪問堆記憶體中的物件,只能通過該物件的引用操作該物件。
如果堆記憶體裡的物件沒有任何變數指向該物件,那麼程式將無法再訪問該物件,這個物件也就變成了垃圾,Java的垃圾回收機制將該物件,釋放該物件所佔的記憶體區。
物件的this引用
構造器中引用該構造器正在初始化的物件
在方法中引用呼叫該方法的物件

this指標最大的作用就是讓類中一個方法,訪問該類裡另一個方法或者例項變數
this可以代表任何物件,當this出現在某個方法體中時,它代表的物件是不確定的,但它代表的型別是確定的:它所代表的只能是當前類的例項:只有當呼叫這個方法時,它所代表的物件才能被確定下來:誰在呼叫這個方法,this就代表誰。
java允許物件的一個成員直接呼叫另一個成員,可以省略this字首。
省略this只是一種假象,雖然程式設計師省略了this,但實際上它還是存在的。
對於static修飾的方法而言,則可以直接實用類來呼叫該方法,如果在static修飾的方法中使用this關鍵字,則這個關鍵字就無法指定合適的物件。所以,static修飾的方法中不能使用this引用,所以靜態成員不能直接訪問非靜態成員。如果確實需要在靜態方法中訪問另一個普通方法,則只能重新建一個物件。
注意:如果方法裡有區域性變數和成員變數同名,但程式又需要在該方法中訪問這個被覆蓋的成員變數(根據被覆蓋改的是類變數還是例項變數),這必須使用this. 或者 類名.
如果構造器裡有區域性變數和成員變數同名,但程式又需要在該構造器中訪問這個被覆蓋的成員變數,這必須使用this.(這裡不包含被覆蓋的是類變數的情況,構造器是與物件相關的)
當this作為引用使用時,程式可以像訪問普通引用變數一樣來訪問這個this引用,甚至可以把this當作普通變數當作普通方法的返回值。

public class ReturnThis
{
   public int age;
   public ReturnThis grow()
   {
      age++;
      // return this返回呼叫該方法的物件
         return this;
   }
   public static void main(String[] args)
   {
      ReturnThis rt = new ReturnThis();
      // 可以連續呼叫一個方法
      rt.grow()
         .grow()
         .grow();
      System.out.println("rt的age成員變數值是:" + rt.age);
   }
}

如果在某個方法中用this作為返回值,這可以連續呼叫同一個方法,但可能造成實際意義的模糊。