1. 屬性:getters 和 setters

當數十名程序員同時開發一個大型項目時,如果他們對存儲在類字段中的數據的處理方式不同,問題往往會突然出現。

也許人們沒有詳細研究類文檔,或者它沒有描述每個案例。因此,經常會出現對象的內部數據“損壞”,從而使對象無效的情況。

為了避免這些情況,習慣上在 Java 中將所有類字段設為私有。只有類的方法可以修改類的變量。其他類的任何方法都不能直接訪問變量。

如果您希望其他類能夠獲取或更改您類對像中的數據,您需要向您的類添加兩個方法——get 方法和 set 方法。例子:

代碼 筆記
class Person
{
   private String name;

   public Person(String name)
   {
      this.name = name;
   }

   public String getName()
   {
      return name;
   }

   public void setName(String name)
   {
      this.name = name;
   }
}


privatename field



通過構造函數初始化字段


getName()— 此方法返回 name 字段的值




setName()— 此方法更改 name 字段的值

沒有其他類可以直接更改名稱字段的值。如果有人需要獲取 name 字段的值,他們將不得不調用對像getName() 上的方法Person。如果某些代碼想要更改名稱字段的值,則需要調用對像setName() 上的方法Person

getName()方法也稱為“名稱字段的獲取器setName()”,該方法稱為“名稱字段的設置器”。

這是一種非常常見的方法。在 80-90% 的所有 Java 代碼中,您永遠不會在類中看到公共變量。相反,它們將被聲明private(或protected),並且每個變量都有公共的 getter 和 setter。

這種方法使代碼更長,但更可靠。

直接訪問一個類變量就像讓你的車通過雙黃線轉彎:它更容易也更快,但如果每個人都這樣做,那麼每個人的情況都會變得更糟。

假設您要創建一個描述點 ( x, y) 的類。以下是新手程序員的做法:

class Point
{
   public int x;
   public int y;
}

有經驗的 Java 程序員會這樣做:

代碼
class Point {
   private int x;
   private int y;

   public Point(int x, int y) {
      this.x = x;
      this.y = y;
   }

   public int getX() {
      return x;
   }

   public void setX(int x) {
      this.x = x;
   }

   public int getY() {
      return y;
   }

   public void setY(int y) {
      this.y = y;
   }
}

代碼更長嗎?無疑。

但是您可以為 getter 和 setter 添加參數驗證。例如,您可以確保 和x始終y大於零(或不小於零)。例子:

代碼 筆記
class Point {
   private int x;
   private int y;

   public Point(int x, int y) {
      this.x = x < 0 ? 0 : x;
      this.y = y < 0 ? 0 : y;
   }

   public int getX() {
      return x;
   }

   public void setX(int x) {
      this.x = x < 0 ?  0 : x;
   }

   public int getY() {
      return y;
   }

   public void setY(int y) {
      this.y = y < 0 ? 0 : y;
   }
}


2. 對像生命週期

您已經知道對像是使用運算符創建的new,但是如何刪除對象呢?它們不會永遠存在。內存不足。

在許多編程語言中,例如 C++,都有一個專門delete用於刪除對象的運算符。但是這在 Java 中是如何工作的呢?

在 Java 中,一切的安排都略有不同。Java 沒有刪除運算符。這是否意味著在 Java 中對像不會被刪除?不,它們當然被刪除了。否則,Java 應用程序會很快耗盡內存,而且不會有幾個月不間斷運行的程序。

在 Java 中,對象的刪除是完全自動化的。Java 機器本身處理對象的刪除。這個過程稱為垃圾收集,收集垃圾的機制稱為垃圾收集器( GC )。

那麼 Java 機器如何知道何時刪除一個對象呢?

垃圾收集器將所有對象分為“可達”和“不可達”。如果至少有一個對象的引用,則認為它是可達的。如果沒有引用某個對象的變量,則該對像被認為是不可訪問的,並被聲明為垃圾,這意味著它可以被刪除。

在 Java 中,您不能創建對現有對象的引用——您只能分配您已有的引用。如果我們刪除對一個對象的所有引用,那麼它就永遠丟失了。

循環引用

在我們遇到一個簡單的反例之前,這個邏輯聽起來很棒:假設我們有兩個相互引用的對象(存儲對彼此的引用)。沒有其他對象存儲對這些對象的引用。

這些對像不能從代碼中訪問,但它們仍然被引用。

這就是垃圾收集器將對象分為可達和不可達,而不是“已引用”和“未引用”的原因。

可達對象

首先,將 100% 存活的對象添加到可達列表中。例如,當前線程 ( Thread.current()) 或控制台 InputStream ( System.in)。

然後,可達對象列表會擴展,以包括由初始可達對象集引用的對象。然後再次擴展以包含此擴展集引用的對象,依此類推。

這意味著如果有一些對像只相互引用,但是沒有辦法從可達對像中到達它們,那麼這些對象將被認為是垃圾,將被刪除。


3.垃圾收集

內存碎片

與對象刪除相關的另一個重點是內存碎片。如果你不斷地創建和刪除對象,很快內存就會嚴重碎片化:佔用的內存區域將散佈在未佔用的內存區域中。

結果,我們很容易陷入無法創建大對象(例如,具有一百萬個元素的數組)的情況,因為沒有大塊的空閒內存。換句話說,可能有空閒內存,甚至很多,但可能沒有大的連續空閒內存塊

內存優化(碎片整理)

Java 機器以特定的方式解決了這個問題。它看起來像這樣:

內存分為兩部分。所有對象的創建(和刪除)僅佔內存的一半。當需要清理內存中的漏洞時,前半部分的所有對像都被複製到後半部分。但是它們是緊挨著複製的,所以沒有孔。

該過程大致如下所示:

第一步:創建對像後

Java 中的垃圾收集

第二步:“洞”的出現

Java 2 中的垃圾收集

第三步:消除“洞”

Java 3 中的垃圾收集

這就是您不需要刪除對象的原因。Java 機器只是將所有可到達的對象複製到一個新位置,並釋放用於存儲對象的整個內存區域。