JavaRush /Java Blog /Random-TW /喝咖啡休息#165。Java 中的套件。適合初學者的線程安全方法

喝咖啡休息#165。Java 中的套件。適合初學者的線程安全方法

在 Random-TW 群組發布

Java套件

來源: Usemynotes 這篇文章將幫助您更好地理解 Java 中的套件、它們的用途以及如何實現它們。 喝咖啡休息#165。 Java 中的套件。 適合初學者的線程安全方法 - 1

Java中什麼是包

Java 中的套件是將一組類別、介面和子套件組合在一起的一種方式。套件用於建立相關類別、介面、枚舉等群組。 子包是另​​一個包內的包。預設不會匯入它們,但如果需要,您可以手動匯入它們。訪問規範不提供給子包的各個成員;它們被視為單獨的包。

Java 中的一些類型的套件:

  • java.lang - 預設與 Java 捆綁在一起。
  • java.io - 包含與輸入/輸出相關的類別、方法和其他元素。

為什麼需要包包?

  • 以避免名稱衝突。
  • 提供受控存取。
  • 實現資料封裝。

如何在Java中創建包?

讓我們建立一個名為Computer的套件。通常,包名稱以小寫字母書寫。這樣做只是為了避免與類別名稱發生名稱衝突。我們還將創建一個名為Pluggable 的接口,該接口位於電腦包中。
package computer;

interface Pluggable {
   public void pluggedIn();
   public void pluggedOut();
}
現在我們將建立一個名為PenDrive的類別來實作上述介面。
package computer;

public class PenDrive implements Pluggable {

   int storage = 64;

   public void pluggedIn () {
     System.out.println("Pen Drive is connected");
   }

   public void pluggedOut () {
     System.out.println("Pen Drive is removed");
   }

   public int storage() {
     return storage;
   }

   public static void main(String args[]) {
     PenDrive p = new PenDrive ();
     p.pluggedIn();
     System.out.println("Pen Drive Storage: " + p.storage());
     p.pluggedOut();
   }
}

如何在Java中建立包層次結構?

在形成層次結構時,Java 中的套件以相反的順序命名。這使得它們與目錄或資料夾非常相似。就像在個人電腦上一樣,一個資料夾可以包含一個或多個子資料夾,這也適用於 Java 中的套件。讓我們來看一個名為Asia.India.Kolkata的套件。這些都是現有的文件夾,但如果考慮地理位置,很明顯加爾各答位於印度,而印度位於亞洲。層次結構的主要目的是讓類別更容易找到。

Java 中的套件類型

內建包

內建包是由大量內建類別組成的包,這些內建類別是 Java API 的一部分。這些套餐包括:
  • java.util - 此套件包含有限數量的實用程式類,用於實現鍊錶、集合等資料結構。它還支援日期和時間操作等等。
  • java.net - 它包含用於網路操作的類別。

使用者定義的套件

使用者定義的包稱為用戶包。使用者可以手動建立一個包,並在其中包含任意數量的類別。

如何從一個包存取另一個包?

您可以透過三種簡單的方式從另一個包存取一個包:
  • 在導入語句中使用星號
在 Java 中,星號 ( * ) 字元用於表示「所有事物」。使用它,我們可以導入包的子包內的所有內容。 範例: 考慮一個名為tools的套件。如果我們想要導入這個套件中的所有內容,那麼我們需要使用 import 語句,例如:
import tools.*;
  • 使用 import package.ClassName;
在套件中提及類別名稱是僅將所需的類別匯入程式中的有效方法,從而避免匯入不必要的類別。 例: 考慮一個名為books的套件。如果我們只想從中匯入特定的類別或介面(我們將查看Pages類別),那麼我們可以使用以下方法匯入:
import book.Pages;
  • 使用您的全名
有一種方法可以透過使用 Java 套件或其類別的完全限定名稱來直接使用它們。這樣就不用導入包了,可以直接在程式中使用。 例子:
java.awt.List aSimpleList = new java.awt.List();

Java 中的預設批次大小

預設情況下,Java 導入java.lang套件。它有許多簡單 Java 程式中常用的類,例如StringInteger等。最重要的類別之一是Object類,它也可以在java.lang套件中找到。此套件的大小取決於其元件:8 個介面、37 個類別、3 個枚舉、27 個異常、23 個錯誤類型和 5 個註解類型。

適合初學者的線程安全 Java 方法

來源:Medium 透過本文,您可以了解 Java 中線程安全方法的工作原理。 喝咖啡休息#165。 Java 中的套件。 適合初學者的線程安全方法 - 2我發現許多初級/中級 Java 開發人員誤解了執行緒安全方法在實際專案中應如何運作。而且由於我們通常工作在多執行緒環境中,因此它們的正確使用非常重要。線程安全方法是可以從多個線程同時呼叫而不影響彼此的資料狀態的方法。對這個概念理解不足會導致難以發現和修復的錯誤。為了避免這類錯誤,讓我們來看一些例子。

範例#1:

public static int countLetters(String input) {
    int counter = 0;

    for (Character c : input.toCharArray()) {
        if (Character.isAlphabetic(c)) {
            counter++;
        }
    }

    return counter;
}
  • countLetters方法是靜態的,它傳回一個int值並接受一個字串參數作為輸入。
  • 此方法內部創建了一個原始變數計數器,然後循環遍歷輸入字串的字符,並在每次遇到字母字符時遞增變數計數器。
這個方法線程安全嗎?許多開發人員說不,因為在這種情況下我們有一個非線程安全的增量操作。讓我們弄清楚一下。在Java記憶體模型中,我們有堆疊和堆疊。每個執行緒都有自己的堆疊,並且所有執行緒共享同一個堆。在這方面,堆疊資料始終是執行緒安全的,但堆資料則不是。堆疊儲存基元和物件參考。堆包含物件本身。這意味著在這個程式碼範例中,每個執行緒將自己的變數counter儲存在堆疊上,並且不會對其他執行緒的資料產生任何影響,因此該方法是執行緒安全的請注意,輸入String值也是一個對象,但String和基元包裝器(IntegerLongDoubleBoolean等)是線程安全的,因為它們是不可變的。

範例#2:

public static int countLetters2(String input) {
    List<Character> listCounter = new ArrayList<>();

    for (Character c : input.toCharArray()) {
        if (Character.isAlphabetic(c)) {
            listCounter.add(c);
        }
    }

    return listCounter.size();
}
此程式碼使用與第一個範例相同的邏輯,但使用List物件而不是原始int變數。從前面的內容我們知道,Java中的物件是儲存在堆疊中的,而List就是一個物件。我們也知道堆疊儲存對堆上物件的參考。在範例 #2 中,每個執行緒建立一個新的ArrayList物件:並且listCounter變數在堆上儲存對其物件的引用,因此其他執行緒無法變更該物件。
List<Character> listCounter = new ArrayList<>();
這意味著該方法是線程安全的。

範例#3:

public class CounterUtil { // singleton

    List<Character> listCounter = new ArrayList<>();

    public int countLetters3(String input) {
        for (Character c : input.toCharArray()) {
            if (Character.isAlphabetic(c)) {
                listCounter.add(c);
            }
        }

        return listCounter.size();
    }
}
在這個範例中,我們有一個單例(這很重要)類別CounterUtil和一個全域變數listCounter。此變數與單例實例同時建立。當多個執行緒呼叫countChars3方法時,它們都使用同一個全域變數listCounter,該變數在堆上儲存對相同物件的引用,並且那裡的執行緒會相互影響。因此我們可以得出結論,該方法不是線程安全的。即使我們將List<Character> listCounter更改為原始變數int counter,它也不是線程安全的,因為所有線程都將使用相同的原始變數。

最後一個例子:

public static int countLetters4(List<Character> inputList) {
    List<Character> listCounter = new ArrayList<>();

    for (Character c : inputList) {
        if (Character.isAlphabetic(c)) {
            listCounter.add(c);
        }
    }

    return listCounter.size();
}
countLetters4 方法接受字元列表而不是字串參數。這裡我們不能保證這個方法是線程安全的。為什麼?因為我們無法確定開發者將如何使用這個方法。如果外部的另一個執行緒與我們的counterLetters4方法同時更改inputList中的數據,則可能會影響最終結果。

結論

我們只看了四個範例,它們並沒有涵蓋 Java 專案中線程安全的所有方面,但它們是一個很好的起點。下次當您在程式碼中看到某個方法時,請問問自己:“這個方法線程安全嗎?” 很快你就會清楚明白答案。
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION