ไม่ได้รวบรวมข้อเสนอแนะใด ๆ ที่ชื่นชม
...
List<Object> list = getList();
return (List<Customer>) list;
คอมไพเลอร์กล่าวว่า: ไม่สามารถส่งList<Object>
ไปยังList<Customer>
ไม่ได้รวบรวมข้อเสนอแนะใด ๆ ที่ชื่นชม
...
List<Object> list = getList();
return (List<Customer>) list;
คอมไพเลอร์กล่าวว่า: ไม่สามารถส่งList<Object>
ไปยังList<Customer>
คำตอบ:
คุณสามารถโยนวัตถุใด ๆ ให้เป็นประเภทใดก็ได้โดยการอัพลงวัตถุก่อน ในกรณีของคุณ:
(List<Customer>)(Object)list;
คุณต้องแน่ใจว่าในรันไทม์รายการไม่มีอะไรเลยนอกจากอ็อบเจ็กต์ของลูกค้า
นักวิจารณ์กล่าวว่าการคัดเลือกนักแสดงดังกล่าวบ่งบอกถึงสิ่งที่ผิดปกติกับรหัสของคุณ คุณควรจะสามารถปรับแต่งการประกาศประเภทของคุณเพื่อหลีกเลี่ยงได้ แต่ Java Generics ซับซ้อนเกินไปและไม่สมบูรณ์แบบ บางครั้งคุณอาจไม่รู้ว่ามีวิธีแก้ปัญหาที่น่าพอใจสำหรับคอมไพเลอร์หรือไม่แม้ว่าคุณจะรู้จักประเภทรันไทม์เป็นอย่างดีและคุณรู้ว่าสิ่งที่คุณพยายามทำนั้นปลอดภัย ในกรณีนี้ให้ทำการหล่อแบบหยาบตามต้องการเพื่อให้คุณออกจากงานกลับบ้านได้
@SuppressWarnings("unchecked")
นี้ยังมีความต้องการ โปรดทราบว่าคุณยังสามารถที่จะ upCast แทนที่จะเป็น(List)
(Object)
นั่นเป็นเพราะแม้ว่าลูกค้าจะเป็นวัตถุ แต่รายชื่อลูกค้าไม่ใช่รายการวัตถุ หากเป็นเช่นนั้นคุณสามารถใส่วัตถุใดก็ได้ในรายชื่อลูกค้า
.Cast<T>()
และอีกวิธีหนึ่งเรียกว่า.OfType<T>()
. ก่อนหน้านี้ทำการแคสต์ในแต่ละองค์ประกอบ (โยนข้อยกเว้นที่ต้องการ) ในขณะที่องค์ประกอบหลังจะกรององค์ประกอบที่ไม่สามารถแคสต์ได้ (ดังนั้นคุณจะเลือกอย่างใดอย่างหนึ่งขึ้นอยู่กับสถานการณ์การใช้งานของคุณ)
instanceof
ลูกค้า
คำตอบที่ดีที่สุดอาจแตกต่างกันไปทั้งนี้ขึ้นอยู่กับรหัสอื่นของคุณ ลอง:
List<? extends Object> list = getList();
return (List<Customer>) list;
หรือ
List list = getList();
return (List<Customer>) list;
แต่โปรดทราบว่าไม่แนะนำให้ทำการร่ายแบบไม่เลือก
ด้วย Java 8 Streams :
บางครั้งการหล่อด้วยกำลังเดรัจฉานก็ใช้ได้:
List<MyClass> mythings = (List<MyClass>) (Object) objects
แต่นี่เป็นวิธีแก้ปัญหาที่หลากหลายกว่า:
List<Object> objects = Arrays.asList("String1", "String2");
List<String> strings = objects.stream()
.map(element->(String) element)
.collect(Collectors.toList());
มีประโยชน์มากมาย แต่อย่างหนึ่งก็คือคุณสามารถแคสต์รายการของคุณให้หรูหรายิ่งขึ้นหากคุณไม่แน่ใจว่ามีอะไรบ้าง:
objects.stream()
.filter(element->element instanceof String)
.map(element->(String)element)
.collect(Collectors.toList());
FluentIterable
ใช้ได้ผลกับฉัน
คุณสามารถใช้การร่ายสองครั้ง
return (List<Customer>) (List) getList();
โปรดทราบว่าฉันไม่ใช่โปรแกรมเมอร์ java แต่ใน. NET และ C # คุณลักษณะนี้เรียกว่าความแตกต่างหรือความแปรปรวนร่วม ฉันยังไม่ได้เจาะลึกสิ่งเหล่านั้นเนื่องจากเป็นสิ่งใหม่ใน. NET 4.0 ซึ่งฉันไม่ได้ใช้เนื่องจากเป็นเพียงเบต้าดังนั้นฉันไม่รู้ว่าคำศัพท์ใดในสองคำที่อธิบายปัญหาของคุณ แต่ให้ฉันอธิบาย ปัญหาทางเทคนิคเกี่ยวกับเรื่องนี้
สมมติว่าคุณได้รับอนุญาตให้แคสต์ หมายเหตุผมพูดทิ้งเนื่องจากว่าเป็นสิ่งที่คุณกล่าวว่า แต่มีสองการดำเนินงานที่อาจจะเป็นไปได้หล่อและการแปลง
การแปลงจะหมายความว่าคุณได้รับวัตถุรายการใหม่ แต่คุณพูดว่าการแคสต์ซึ่งหมายความว่าคุณต้องการให้วัตถุหนึ่งเป็นประเภทอื่นชั่วคราว
นี่คือปัญหาที่เกิดขึ้น
จะเกิดอะไรขึ้นถ้าสิ่งต่อไปนี้ได้รับอนุญาต (โปรดทราบว่าฉันคิดว่าก่อนที่จะแคสต์รายการวัตถุมีเฉพาะวัตถุของลูกค้าเท่านั้นมิฉะนั้นการแคสต์จะไม่ทำงานแม้ใน java เวอร์ชันสมมุตินี้):
List<Object> list = getList();
List<Customer> customers = (List<Customer>)list;
list.Insert(0, new someOtherObjectNotACustomer());
Customer c = customers[0];
ในกรณีนี้สิ่งนี้จะพยายามปฏิบัติต่อวัตถุที่ไม่ใช่ลูกค้าในฐานะลูกค้าและคุณจะได้รับข้อผิดพลาดรันไทม์ ณ จุดหนึ่งไม่ว่าจะเป็นแบบฟอร์มภายในรายการหรือจากการมอบหมาย
อย่างไรก็ตาม Generics ควรให้ประเภทข้อมูลที่ปลอดภัยแก่คุณเช่นคอลเล็กชันและเนื่องจากพวกเขาชอบที่จะใช้คำว่า 'รับประกัน' ไปรอบ ๆ จึงไม่อนุญาตให้ใช้การแสดงประเภทนี้ที่มีปัญหาที่ตามมา
ใน. NET 4.0 (ฉันรู้ว่าคำถามของคุณเกี่ยวกับ java) สิ่งนี้จะได้รับอนุญาตในบางกรณีที่เฉพาะเจาะจงซึ่งคอมไพเลอร์สามารถรับประกันได้ว่าการดำเนินการที่คุณทำนั้นปลอดภัย แต่โดยทั่วไปแล้วการส่งประเภทนี้จะไม่ ได้รับอนุญาต เช่นเดียวกันกับ java แม้ว่าฉันจะไม่แน่ใจเกี่ยวกับแผนการใด ๆ ที่จะแนะนำการใช้ร่วมและความแตกต่างกับภาษา java
หวังว่าจะมีคนที่มีความรู้ java ดีกว่าฉันสามารถบอกรายละเอียดเกี่ยวกับ java ในอนาคตหรือการนำไปใช้งานได้
คุณควรทำซ้ำในรายการและโยน Objects ทั้งหมดทีละรายการ
List<Customer> cusList = new ArrayList<Customer>();
for(Object o: list){
cusList.add((Customer)o);
}
return cusList;
list.stream().forEach(x->cusList.add((Customer)x))
return cuslist;
คุณไม่สามารถเพราะList<Object>
และList<Customer>
ไม่ได้อยู่ในโครงสร้างมรดกเดียวกัน
คุณสามารถเพิ่มตัวสร้างใหม่ในList<Customer>
ชั้นเรียนของคุณโดยใช้เวลา a List<Object>
แล้ววนซ้ำผ่านรายการที่แคสต์แต่ละรายการObject
ไปยัง a Customer
และเพิ่มลงในคอลเล็กชันของคุณ โปรดทราบว่าข้อยกเว้นในการแคสต์ที่ไม่ถูกต้องอาจเกิดขึ้นได้หากผู้โทรList<Object>
มีสิ่งที่ไม่ใช่ไฟล์Customer
.
จุดสำคัญของรายการทั่วไปคือการ จำกัด รายการบางประเภท คุณกำลังพยายามเอารายชื่อที่สามารถมีอะไรก็ได้ (คำสั่งซื้อสินค้า ฯลฯ ) และบีบให้เป็นรายการที่สามารถรับลูกค้าได้เท่านั้น
คุณสามารถสร้างรายการใหม่และเพิ่มองค์ประกอบเข้าไปได้:
ตัวอย่างเช่น:
List<A> a = getListOfA();
List<Object> newList = new ArrayList<>();
newList.addAll(a);
ทางออกที่ดีที่สุดของคุณคือการสร้างใหม่List<Customer>
ทำซ้ำList<Object>
เพิ่มแต่ละรายการในรายการใหม่แล้วส่งคืน
ตามที่คนอื่น ๆ ชี้ให้เห็นคุณไม่สามารถโยนพวกเขาได้อย่างปลอดภัยเนื่องจากList<Object>
ไม่ใช่ไฟล์List<Customer>
. สิ่งที่คุณทำได้คือกำหนดมุมมองในรายการที่ทำการตรวจสอบชนิดในสถานที่ การใช้Google Collectionsที่จะเป็น:
return Lists.transform(list, new Function<Object, Customer>() {
public Customer apply(Object from) {
if (from instanceof Customer) {
return (Customer)from;
}
return null; // or throw an exception, or do something else that makes sense.
}
});
คล้ายกับ Bozho ด้านบน คุณสามารถแก้ปัญหาบางอย่างได้ที่นี่ (แม้ว่าฉันจะไม่ชอบก็ตาม) ด้วยวิธีนี้:
public <T> List<T> convert(List list, T t){
return list;
}
ใช่. มันจะส่งรายการของคุณเป็นประเภททั่วไปที่คุณต้องการ
ในกรณีที่ระบุข้างต้นคุณสามารถทำโค้ดได้ดังนี้:
List<Object> list = getList();
return convert(list, new Customer());
ขึ้นอยู่กับสิ่งที่คุณต้องการทำกับรายการคุณอาจไม่จำเป็นต้องแคสต์ไปยังไฟล์List<Customer>
. หากคุณต้องการเพิ่มCustomer
วัตถุในรายการคุณสามารถประกาศได้ดังนี้:
...
List<Object> list = getList();
return (List<? super Customer>) list;
นี่เป็นสิ่งที่ถูกกฎหมาย (ไม่ใช่แค่ถูกกฎหมาย แต่ถูกต้อง - รายการเป็น "supertype บางอย่างให้กับลูกค้า") และหากคุณกำลังจะส่งต่อไปยังวิธีการที่จะเป็นเพียงการเพิ่มออบเจ็กต์ลงในรายการดังกล่าวข้างต้น ขอบเขตทั่วไปเพียงพอสำหรับสิ่งนี้
ในทางกลับกันหากคุณต้องการดึงวัตถุจากรายการและพิมพ์ให้พวกเขาพิมพ์เป็นลูกค้าอย่างรุนแรงคุณก็โชคไม่ดีและถูกต้อง เนื่องจากรายการนี้List<Object>
ไม่มีการรับประกันว่าเนื้อหาจะเป็นของลูกค้าดังนั้นคุณจะต้องจัดเตรียมการคัดเลือกนักแสดงของคุณเองในการดึงข้อมูล (หรืออย่างแน่นอนให้แน่ใจว่ารายการจะมีCustomers
และใช้ double-cast จากคำตอบอื่น ๆ เท่านั้น แต่โปรดทราบว่าคุณกำลังหลีกเลี่ยงความปลอดภัยในการคอมไพล์ไทม์ที่คุณได้รับจากยาสามัญในนี้ กรณี).
การพูดอย่างกว้าง ๆ ควรพิจารณาขอบเขตทั่วไปที่กว้างที่สุดเท่าที่จะเป็นไปได้ซึ่งเป็นที่ยอมรับได้เมื่อเขียนวิธีการเป็นสองเท่าดังนั้นหากจะใช้เป็นวิธีการของห้องสมุด หากคุณกำลังจะอ่านจากรายการเท่านั้นให้ใช้List<? extends T>
แทนList<T>
เช่นซึ่งจะช่วยให้ผู้โทรของคุณมีขอบเขตมากขึ้นในข้อโต้แย้งที่พวกเขาสามารถส่งผ่านได้และหมายความว่าพวกเขามีโอกาสน้อยที่จะประสบปัญหาที่หลีกเลี่ยงได้คล้ายกับที่คุณ ' กำลังมีที่นี่