Saya sudah mendapat kelas template sebagai berikut:
class MyClass<T>
{
T field;
public void myMethod()
{
field = new T(); // gives compiler error
}
}
Bagaimana cara membuat instance baru T di kelas saya?
Saya sudah mendapat kelas template sebagai berikut:
class MyClass<T>
{
T field;
public void myMethod()
{
field = new T(); // gives compiler error
}
}
Bagaimana cara membuat instance baru T di kelas saya?
Jawaban:
Setelah penghapusan jenis, semua yang diketahui tentang T
itu adalah beberapa subkelas Object
. Anda perlu menentukan beberapa pabrik untuk membuat instance T
.
Satu pendekatan bisa menggunakan 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();
}
}
Penggunaannya mungkin terlihat seperti ini:
MyClass<StringBuilder> it = new MyClass<>(StringBuilder::new);
Alternatifnya, Anda dapat memberikan Class<T>
objek, lalu menggunakan refleksi.
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
Pendekatan non-reflektif lainnya adalah dengan menggunakan pola Builder / Pabrik Abstrak hybrid.
Di Java Efektif, Joshua Bloch membahas pola Builder secara detail, dan menganjurkan antarmuka Builder umum:
public interface Builder<T> {
public T build();
}
Pembuat beton dapat mengimplementasikan antarmuka ini, dan kelas luar dapat menggunakan pembuat beton untuk mengonfigurasi Builder sesuai kebutuhan. Pembangun dapat diteruskan ke MyClass sebagai Builder<T>
.
Dengan menggunakan pola ini, Anda bisa mendapatkan instance baru T
, meskipun T
memiliki parameter konstruktor atau memerlukan konfigurasi tambahan. Tentu saja, Anda memerlukan beberapa cara untuk meneruskan Builder ke MyClass. Jika Anda tidak dapat mengirimkan apa pun ke MyClass, maka Builder dan Pabrik Abstrak keluar.
Ini mungkin lebih berat daripada yang Anda cari, tetapi juga akan berhasil. Perhatikan bahwa jika Anda menggunakan pendekatan ini, akan lebih masuk akal untuk memasukkan pabrik ke dalam MyClass saat dibuat daripada meneruskannya ke metode Anda setiap kali dipanggil.
interface MyFactory<T>
{
T newObject();
}
class MyClass<T>
{
T field;
public void myMethod(MyFactory<T> factory)
{
field = factory.newObject()
}
}
Jika Anda ingin membuat subkelas, Anda juga dapat menghindari penghapusan, lihat http://www.artima.com/weblogs/viewpost.jsp?thread=208860
Salah satu opsinya adalah menggunakan Object
{field = (T) new Object();}
field awalnya akan menjadi tipe Object, tapi kemudian akan diturunkan menjadi tipe T. Ini adalah salah satu yang jelek karena mengurangi casting ke nol adalah tujuan yang seharusnya untuk inisialisasi objek. Tapi saya pikir ini akan berhasil.
Kelas classOfT
try {
t = classOfT.newInstance();//new T(); NOTE: type parameter T cannot be instantiated directly
} catch (Exception e) {
e.printStackTrace();
}
Supplier
lokasinya? `MyClass (Class <? Extends T> impl)` harus mendeklarasikan `throws NoSuchMethodException` untuk dikompilasi. Jawaban Anda sayangnya tidak ramah untuk pemula Java.