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
สรุปการแปลง
| ทิศทาง | วิธีที่แนะนำ | ความปลอดภัย |
|---|---|---|
| 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 เอง