ฉันมีคลาสเทมเพลตดังนี้:
class MyClass<T>
{
T field;
public void myMethod()
{
field = new T(); // gives compiler error
}
}
ฉันจะสร้างอินสแตนซ์ใหม่ของ T ในชั้นเรียนได้อย่างไร
ฉันมีคลาสเทมเพลตดังนี้:
class MyClass<T>
{
T field;
public void myMethod()
{
field = new T(); // gives compiler error
}
}
ฉันจะสร้างอินสแตนซ์ใหม่ของ T ในชั้นเรียนได้อย่างไร
คำตอบ:
หลังจากการลบประเภทสิ่งที่รู้T
ก็คือมันเป็นคลาสย่อยของObject
. T
คุณต้องระบุโรงงานบางส่วนในการสร้างอินสแตนซ์
แนวทางหนึ่งสามารถใช้Supplier<T>
:
class MyClass<T> {
private final Supplier<? extends T> ctor;
private T field;
MyClass(Supplier<? extends T> ctor) {
this.ctor = Objects.requireNonNull(ctor);
}
public void myMethod() {
field = ctor.get();
}
}
การใช้งานอาจมีลักษณะดังนี้:
MyClass<StringBuilder> it = new MyClass<>(StringBuilder::new);
หรือคุณสามารถระบุClass<T>
วัตถุจากนั้นใช้การสะท้อนกลับ
class MyClass<T> {
private final Constructor<? extends T> ctor;
private T field;
MyClass(Class<? extends T> impl) throws NoSuchMethodException {
this.ctor = impl.getConstructor();
}
public void myMethod() throws Exception {
field = ctor.newInstance();
}
}
java.util.function.Supplier
อีกวิธีหนึ่งที่ไม่สะท้อนแสงคือการใช้รูปแบบ Builder / Abstract Factory แบบผสม
ใน Java ที่มีประสิทธิภาพ Joshua Bloch จะอธิบายรายละเอียดเกี่ยวกับรูปแบบ Builder และสนับสนุนอินเทอร์เฟซ Builder ทั่วไป:
public interface Builder<T> {
public T build();
}
ผู้สร้างคอนกรีตสามารถใช้อินเทอร์เฟซนี้ได้และชั้นเรียนภายนอกสามารถใช้ตัวสร้างคอนกรีตเพื่อกำหนดค่าตัวสร้างได้ตามต้องการ ตัวสร้างสามารถส่งผ่านไปยัง MyClass เป็นไฟล์Builder<T>
.
เมื่อใช้รูปแบบนี้คุณจะได้รับอินสแตนซ์ใหม่T
แม้ว่าจะT
มีพารามิเตอร์ตัวสร้างหรือต้องการการกำหนดค่าเพิ่มเติมก็ตาม แน่นอนว่าคุณจะต้องมีวิธีส่ง Builder ไปยัง MyClass หากคุณไม่สามารถส่งผ่านอะไรเข้าไปใน MyClass ได้แสดงว่า Builder และ Abstract Factory จะหมดลง
สิ่งนี้อาจมีน้ำหนักมากกว่าที่คุณกำลังมองหา แต่ก็ใช้ได้ผลเช่นกัน โปรดทราบว่าหากคุณใช้แนวทางนี้จะเป็นการดีกว่าที่จะฉีดโรงงานลงใน MyClass เมื่อถูกสร้างขึ้นแทนที่จะส่งผ่านเข้าไปในวิธีการของคุณทุกครั้งที่มีการเรียกใช้
interface MyFactory<T>
{
T newObject();
}
class MyClass<T>
{
T field;
public void myMethod(MyFactory<T> factory)
{
field = factory.newObject()
}
}
หากคุณยินดีที่จะคลาสย่อยคุณสามารถหลีกเลี่ยงการลบได้เช่นกันโปรดดู http://www.artima.com/weblogs/viewpost.jsp?thread=208860
ทางเลือกหนึ่งคือการใช้ Object
{field = (T) new Object();}
ในตอนแรกจะเป็นประเภท Object แต่จากนั้นจะโยนลงไปที่พิมพ์ T นี่เป็นสิ่งที่น่าเกลียดเพราะการลดการแคสต์ให้เหลือศูนย์คือเป้าหมายที่ควรจะเป็นสำหรับการเริ่มต้นอ็อบเจ็กต์ แต่ฉันคิดว่ามันจะได้ผล
คลาส classOfT
try {
t = classOfT.newInstance();//new T(); NOTE: type parameter T cannot be instantiated directly
} catch (Exception e) {
e.printStackTrace();
}
Supplier
อยู่ใน? `MyClass (Class <? expands T> im)` ต้องประกาศว่าจะคอมไพล์ NoSuchMethodException คำตอบของคุณไม่เหมาะสำหรับผู้เริ่มต้น Java