JavaRush /Java Blog /Random-TW /Java中的泛型是什麼

Java中的泛型是什麼

在 Random-TW 群組發布
你好!今天我們來談談泛型。我必須說你會學到很多新東西!不僅如此,接下來的幾堂課也將專門討論泛型。 Java 中的泛型是什麼 - 1 因此,如果您對這個主題感興趣,那麼您很幸運:今天您將了解許多有關泛型的特性。好吧,如果沒有,冷靜下來,放鬆一下!:) 這是一個非常重要的主題,你需要了解它。讓我們從一個簡單的開始:「什麼」和「為什麼」。什麼是仿製藥? 泛型是帶有參數的型別。 建立泛型時,您不僅指定其類型,還指定它應使用的資料類型。我想最明顯的例子已經浮現在你的腦海裡了——這就是ArrayList!我們通常在程式中創建它的方式如下:
import java.util.ArrayList;
import java.util.List;

public class Main {

   public static void main(String[] args) {

       List<String> myList1 = new ArrayList<>();
       myList1.add("Test String 1");
       myList1.add("Test String 2");
   }
}
正如您可能猜到的,清單的特殊性在於不可能將所有內容「塞」進去:它只適用於物件String。現在讓我們簡短回顧一下 Java 的歷史,並嘗試回答這個問題:“為什麼?” 為此,我們自己編寫 ArrayList 類別的簡化版本。我們的清單只能將資料新增至內部數組並接收此資料:
public class MyListClass {

   private Object[] data;
   private int count;

   public MyListClass() {
       this.data = new Object[10];
       this.count = 0;
   }

   public void add(Object o) {
       this.data[count] = o;
       count++;
   }

   public Object[] getData() {
       return data;
   }
}
假設我們希望列表僅儲存數字Integer。我們沒有仿製藥。Integer我們無法在 中明確指定 check 的 o 實例add()。那麼我們的整個類別將只適用於Integer,並且我們將不得不為世界上存在的所有資料類型編寫相同的類別!我們決定依靠我們的程式設計師,只需在程式碼中留下註釋,以便他們不會在其中添加任何不必要的內容:
//use it ONLY with Integer data type
public void add(Object o) {
   this.data[count] = o;
   count++;
}
一位程式設計師錯過了這個註釋,並無意中嘗試將數字與字串混合在列表中,然後計算它們的總和:
public class Main {

   public static void main(String[] args) {

       MyListClass list = new MyListClass();
       list.add(100);
       list.add(200);
       list.add("Lolkek");
       list.add("Shalala");

       Integer sum1 = (Integer) list.getData()[0] + (Integer) list.getData()[1];
       System.out.println(sum1);

       Integer sum2 = (Integer) list.getData()[2] + (Integer) list.getData()[3];
       System.out.println(sum2);
   }
}
控制台輸出: 300 執行緒「main」中的例外 java.lang.ClassCastException:java.lang.String 無法在 Main.main(Main.java:14) 轉換為 java.lang.Integer 在這種情況下最糟糕的是什麼?遠遠不是程式設計師的不專心。最糟糕的是,錯誤的程式碼最終出現在我們程式的重要位置並成功編譯。現在我們不會在編碼階段看到錯誤,而只會在測試階段看到錯誤(這是最好的情況!)。 在開發後期修復錯誤會花費更多的錢和時間。 這正是泛型的優點:泛型類別可以讓不幸的程式設計師立即偵測到錯誤。程式碼根本無法編譯!
import java.util.ArrayList;
import java.util.List;

public class Main {

   public static void main(String[] args) {

       List<Integer> myList1 = new ArrayList<>();

       myList1.add(100);
       myList1.add(100);
       myList1.add("Lolkek");//error!
       myList1.add("Shalala");//error!
   }
}
程式設計師會立即「醒悟」並立即糾正自己。順便說一下,我們不必創建自己的類別List來看到這種錯誤。<Integer>只需從常規 ArrayList 中 刪除類型括號 ( ) 即可!
import java.util.ArrayList;
import java.util.List;

public class Main {

   public static void main(String[] args) {

      List list = new ArrayList();

      list.add(100);
      list.add(200);
      list.add("Lolkek");
      list.add("Shalala");

       System.out.println((Integer) list.get(0) + (Integer) list.get(1));
       System.out.println((Integer) list.get(2) + (Integer) list.get(3));
   }
}
控制台輸出: 300 Exception in thread "main" java.lang.ClassCastException: java.lang.String無法在Main.main(Main.java:16)轉換為java.lang.Integer 也就是說,即使使用「本機器”工具Java,你可能會犯這個錯誤並創建一個不安全的集合。但是,如果我們將此程式碼貼到 IDEa 中,我們會看到一條警告:「Unchecked call to add(E) as a member of raw type of java.util.List」它告訴我們,在向a 中添加元素時可能會出現問題。沒有泛型的集合不是這樣的。但是「原始類型」這個詞是什麼意思呢?直譯是相當準確的-「原始類型」或「髒類型」。 Raw type是一個泛型類,其類型已從中刪除。 換句話說,List myList1這是Raw type。相反的raw type是使用類型規範正確建立的generic type泛型類別(也稱為類別)。parameterized type例如,List<String> myList1。您可能有一個問題:為什麼允許使用它raw types?原因很簡單。Java 的創建者留下了對該語言的支持raw types,以免造成相容性問題。當 Java 5.0 發佈時(泛型在這個版本中首次出現),很多程式碼已經使用raw types. 因此,這種可能性在今天仍然存在。我們在講座中已經不只一次提到Joshua Bloch的經典著作《Effective Java》。raw types作為該語言的創造者之一,他並沒有忽視書中使用and的話題generic typesJava 中的泛型是什麼 - 2本書第 23 章有一個非常雄辯的標題:「不要在新程式碼中使用原始類型。」 這是你需要記住的事情。使用泛型類別時,切勿將它們轉換generic typeraw type.

類型化方法

Java 允許您鍵入單獨的方法,建立所謂的泛型方法。為什麼這樣的方法方便呢?首先,因為它們允許您使用不同類型的參數。如果相同的邏輯可以安全地應用於不同的類型,那麼泛型方法是一個很好的解決方案。讓我們來看一個例子。假設我們有某種列表myList1。我們想要從中刪除所有值,並用新值填滿所有可用空間。這就是我們的帶有泛型方法的類別的樣子:
public class TestClass {

   public static <T> void fill(List<T> list, T val) {
       for (int i = 0; i < list.size(); i++)
           list.set(i, val);
   }

   public static void main(String[] args) {

       List<String> strings = new ArrayList<>();
       strings.add("Старая строка 1");
       strings.add("Старая строка 2");
       strings.add("Старая строка 3");

       fill(strings, "Новая строка");

       System.out.println(strings);

       List<Integer> numbers = new ArrayList<>();
       numbers.add(1);
       numbers.add(2);
       numbers.add(3);

       fill(numbers, 888);
       System.out.println(numbers);
   }
}
注意語法,它看起來有點不尋常:
public static <T> void fill(List<T> list, T val)
傳回型別前面有<T>,表示泛型方法。在本例中,此方法採用2 個參數作為輸入:一個物件列表T 和另一個單獨的物件T。透過使用<T>,實現了此方法的類型化:我們無法在其中傳遞字串列表和數字。字串和字串的列表,數字和數字的列表,我們的物件Cat和另一個物件的列表Cat- 這是唯一的方法。該方法main()清楚地表明該方法fill()可以輕鬆處理不同類型的資料。首先,它接受一個字串列表和一個字串作為輸入,然後是一個數字列表和一個數字。 控制台輸出: [Newline, Newline, Newline] [888, 888, 888] 想像一下,如果fill()我們需要 30 個不同類別的方法邏輯,並且我們沒有通用方法。我們將被迫為不同的資料類型編寫相同的方法 30 次!但由於通用方法,我們可以重複使用我們的程式碼!:)

類型化類

您不僅可以使用 Java 中提供的通用類,還可以建立自己的類別!這是一個簡單的例子:
public class Box<T> {

   private T t;

   public void set(T t) {
       this.t = t;
   }

   public T get() {
       return t;
   }

   public static void main(String[] args) {

       Box<String> stringBox = new Box<>();

       stringBox.set("Старая строка");
       System.out.println(stringBox.get());
       stringBox.set("Новая строка");

       System.out.println(stringBox.get());

       stringBox.set(12345);//ошибка компиляции!
   }
}
我們的類別Box<T>(“盒子”)已鍵入。在建立過程中為其指定了資料類型 () 後<T>,我們將無法再將其他類型的物件放入其中。這可以在範例中看到。創建時,我們指定我們的物件將使用字串:
Box<String> stringBox = new Box<>();
當我們在最後一行程式碼中嘗試將數字 12345 放入框中時,我們收到編譯錯誤!就像這樣,我們創建了自己的泛型類別!:) 今天的講座到此結束。但我們並沒有告別仿製藥!在接下來的講座中,我們將討論更高級的功能,所以不要說再見!) 祝你學習順利!:)
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION