Tôi có một lớp mẫu như sau:
class MyClass<T>
{
T field;
public void myMethod()
{
field = new T(); // gives compiler error
}
}
Làm cách nào để tạo một phiên bản mới của T trong lớp của tôi?
Tôi có một lớp mẫu như sau:
class MyClass<T>
{
T field;
public void myMethod()
{
field = new T(); // gives compiler error
}
}
Làm cách nào để tạo một phiên bản mới của T trong lớp của tôi?
Câu trả lời:
Sau khi xóa kiểu, tất cả những gì được biết T
là nó là một số lớp con của Object
. Bạn cần chỉ định một số nhà máy để tạo các phiên bản củaT
.
Một cách tiếp cận có thể sử dụng 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();
}
}
Cách sử dụng có thể trông như thế này:
MyClass<StringBuilder> it = new MyClass<>(StringBuilder::new);
Ngoài ra, bạn có thể cung cấp một Class<T>
đối tượng, sau đó sử dụng phản xạ.
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
Một cách tiếp cận không phản chiếu khác là sử dụng mẫu Builder / Abstract Factory kết hợp.
Trong Java hiệu quả, Joshua Bloch xem xét chi tiết mẫu Builder và ủng hộ giao diện Builder chung:
public interface Builder<T> {
public T build();
}
Người xây dựng bê tông có thể triển khai giao diện này và các lớp bên ngoài có thể sử dụng trình xây dựng bê tông để định cấu hình Trình xây dựng theo yêu cầu. Trình tạo có thể được chuyển tới MyClass dưới dạng Builder<T>
.
Sử dụng mẫu này, bạn có thể nhận các phiên bản mới T
, ngay cả khi T
có tham số hàm tạo hoặc yêu cầu cấu hình bổ sung. Tất nhiên, bạn sẽ cần một số cách để chuyển Builder vào MyClass. Nếu bạn không thể chuyển bất cứ thứ gì vào MyClass, thì Builder và Abstract Factory sẽ không hoạt động.
Điều này có thể nặng hơn những gì bạn đang tìm kiếm, nhưng nó cũng sẽ hoạt động. Lưu ý rằng nếu bạn thực hiện phương pháp này, sẽ có ý nghĩa hơn khi đưa nhà máy vào MyClass khi nó được xây dựng thay vì chuyển nó vào phương thức của bạn mỗi khi nó được gọi.
interface MyFactory<T>
{
T newObject();
}
class MyClass<T>
{
T field;
public void myMethod(MyFactory<T> factory)
{
field = factory.newObject()
}
}
Nếu bạn sẵn sàng phân lớp, bạn cũng có thể tránh bị xóa, hãy xem http://www.artima.com/weblogs/viewpost.jsp?thread=208860
Class classOfT
try {
t = classOfT.newInstance();//new T(); NOTE: type parameter T cannot be instantiated directly
} catch (Exception e) {
e.printStackTrace();
}
Supplier
nằm trong? `MyClass (Class <? Expand T> impl)` phải khai báo `ném NoSuchMethodException` để được biên dịch. Câu trả lời của bạn rất tiếc là không thân thiện với người mới bắt đầu Java.