Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Java

วิธีแปลง ArrayList<String> เป็น ArrayList<Object> และกลับกันใน Java

Generics ใน Java เป็น Invariant -> ArrayList<String> ไม่ใช่ Subtype ของ ArrayList<Object> ต้องใช้ Wildcard ? หรือ Copy

1. ArrayList<String> -> ArrayList<Object> (Safe: Widening)

String เป็น Subtype ของ Object -> Copy ผ่าน Constructor

ArrayList<String> stringList = new ArrayList<>();
stringList.add("Apple");
stringList.add("Banana");

// วิธีที่ 1: Constructor Copy (แนะนำ - Type Safe)
ArrayList<Object> objectList = new ArrayList<>(stringList);

// วิธีที่ 2: Wildcard Cast (Unsafe - Raw Type Warning)
ArrayList<Object> objectList2 = (ArrayList<Object>)(ArrayList<?>) stringList; // Unchecked Warning
// ทำได้เพราะ String[] -> Object[] Covariant แต่ Generic Invariant

2. ArrayList<Object> -> ArrayList<String> (Unsafe: Narrowing)

ต้อง Ensure ว่า Element ทุกตัวเป็น String จริง

ArrayList<Object> objectList = new ArrayList<>();
objectList.add("Apple");
objectList.add("Banana");
// objectList.add(123); // ถ้ามี Non-String -> Runtime Error ตอน Cast

// วิธีที่ 1: Stream Filter + Collect (Safe, Modern)
ArrayList<String> stringList = objectList.stream()
    .filter(String.class::isInstance)
    .map(String.class::cast)
    .collect(Collectors.toCollection(ArrayList::new));

// วิธีที่ 2: Constructor + Unchecked Cast (Risky)
@SuppressWarnings("unchecked")
ArrayList<String> stringList2 = (ArrayList<String>)(ArrayList<?>) objectList; // ClassCastException ถ้ามี Non-String

3. ใช้ Wildcard เพื่อ Flexibility (Best Practice)

แทนที่จะ Convert ให้ใช้ List<? extends String> หรือ List<? super String>

// Producer (Read Only) - ใช้ extends
public void printList(List<? extends String> list) {
    for (String s : list) System.out.println(s);
}

// Consumer (Write Only) - ใช้ super
public void addStrings(List<? super String> list) {
    list.add("New String"); // OK
    // String s = list.get(0); // Error: ได้แค่ Object
}

// ใช้ได้กับทั้ง ArrayList และ ArrayList
printList(stringList);     // OK
printList(objectList);     // OK (Object extends String? No! แต่ ? extends String รับ String ได้)
addStrings(stringList);    // OK
addStrings(objectList);    // OK (Object super String)

สรุปการแปลง

ทิศทาง วิธีที่แนะนำ ความปลอดภัย
String -> Object new ArrayList<>(stringList) ✅ Safe (Copy)
Object -> String Stream Filter/Map + Collect ✅ Safe (Runtime Check)
All (Flexible API) Wildcard ? extends/super ✅ Best Practice

Key Points

  • Generics Invariant: List<String> ≠ List<Object>
  • Arrays Covariant: String[] → Object[] (แต่ Runtime Check)
  • Wildcard (?) ใช้สำหรับ API Flexibility แทนการ Convert
  • SuppressWarnings("unchecked") ใช้ได้แต่ต้องรับผิดชอบ Type Safety เอง