Bagaimana saya bisa mencapai ini?
public class GenericClass<T>
{
public Type getMyType()
{
//How do I return the type of T?
}
}
Semua yang saya coba sejauh ini selalu mengembalikan tipe Object
daripada tipe spesifik yang digunakan.
java
generics
reflection
Glenn
sumber
sumber
Jawaban:
Seperti yang disebutkan orang lain, itu hanya mungkin melalui refleksi dalam keadaan tertentu.
Jika Anda benar-benar membutuhkan jenisnya, ini adalah pola penyelesaian (jenis-aman) yang biasa:
sumber
Foo foo1 = GetDao<Foo>(Foo.class).get(Foo.class, 1)
public static <T> GenericClass<T> of(Class<T> type) {...}
dan kemudian menyebutnya seperti:GenericClass<String> var = GenericClass.of(String.class)
. Agak lebih bagus.Saya telah melihat sesuatu seperti ini
dalam Contoh hibernate GenericDataAccessObjects
sumber
class A implements Comparable<String>
, parameter tipe sebenarnyaString
, tetapi TIDAK BISA mengatakan bahwa dalamSet<String> a = new TreeSet<String>()
, parameter tipe aktual adalahString
. Bahkan, informasi parameter tipe "dihapus" setelah kompilasi, seperti yang dijelaskan dalam jawaban lain.java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType
jawaban ini.Class-Mate
dari orang-orang Jackson. Saya menulis sebuah intisari di sini gist.github.com/yunspace/930d4d40a787a1f6a7d1(Class<T>) ((ParameterizedType)getClass().getSuperclass().getGenericSuperclass()).getActualTypeArguments()
untuk mendapatkan argumen tipe yang sebenarnya.Generik tidak diverifikasi pada saat run-time. Ini berarti informasi tersebut tidak ada pada saat dijalankan.
Menambahkan obat generik ke Java sambil mempertahankan kompatibilitas ke belakang adalah tur-de-force (Anda dapat melihat makalah mani tentang hal itu: Membuat masa depan aman untuk masa lalu: menambahkan kedermawanan ke bahasa pemrograman Java ).
Ada literatur yang kaya tentang masalah ini, dan beberapa orang tidak puas dengan keadaan saat ini, beberapa mengatakan bahwa sebenarnya itu adalah daya tarik dan tidak ada kebutuhan nyata untuk itu. Anda dapat membaca kedua tautan, saya menemukan mereka cukup menarik.
sumber
Gunakan Jambu Biji.
Beberapa waktu yang lalu, saya memposting beberapa contoh lengkap termasuk kelas abstrak dan subclass di sini .
Catatan: ini mengharuskan Anda instantiate subclass dari
GenericClass
sehingga dapat mengikat jenis parameter dengan benar. Kalau tidak, itu hanya akan mengembalikan tipeT
.sumber
java.lang.IllegalArgumentException: class com.google.common.reflect.TypeToken isn't parameterized
. Jadi saya mengubah jalurnew TypeToken(getClass()) { }
menjadinew TypeToken<T>(getClass()) { }
. Sekarang, kode berjalan dengan baik, tetapi Type masih 'T'. Lihat ini: gist.github.com/m-manu/9cda9d8f9d53bead2035default Type getParameterType() { final TypeToken<T> typeToken = new TypeToken<T>(getClass()) {}; final Type type = typeToken.getType(); return type; }
GenericClass
, Anda harus membuat kelas ituabstract
sehingga penggunaan yang salah tidak dapat dikompilasi.Tentu kamu bisa.
Java tidak menggunakan informasi pada saat dijalankan, untuk alasan kompatibilitas ke belakang. Tetapi informasi tersebut sebenarnya hadir sebagai metadata dan dapat diakses melalui refleksi (tetapi masih tidak digunakan untuk pengecekan tipe).
Dari API resmi:
http://download.oracle.com/javase/6/docs/api/java/lang/reflect/ParameterizedType.html#getActualTypeArguments%28%29
Namun , untuk skenario Anda, saya tidak akan menggunakan refleksi. Saya pribadi lebih cenderung menggunakannya untuk kode kerangka kerja. Dalam kasus Anda, saya hanya akan menambahkan jenis sebagai param konstruktor.
sumber
Java generics sebagian besar waktu kompilasi, ini berarti bahwa informasi jenis hilang saat runtime.
akan dikompilasi menjadi sesuatu seperti
Untuk mendapatkan informasi jenis saat runtime Anda harus menambahkannya sebagai argumen dari ctor.
Contoh:
sumber
private final Class<T> type;
Type t = //String[]
sumber
Saya menggunakan pendekatan follow:
sumber
Saya rasa Anda tidak bisa, Java menggunakan tipe erasure saat kompilasi sehingga kode Anda kompatibel dengan aplikasi dan pustaka yang dibuat pra-generik.
Dari Oracle Docs:
http://docs.oracle.com/javase/tutorial/java/generics/erasure.html
sumber
Teknik yang dijelaskan dalam artikel ini oleh Ian Robertson bekerja untuk saya.
Singkatnya, contoh cepat dan kotor:
sumber
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
Saya pikir ada solusi elegan lain.
Apa yang ingin Anda lakukan adalah (dengan aman) "meneruskan" tipe parameter tipe generik dari kelas concerete ke superclass.
Jika Anda membiarkan diri Anda memikirkan tipe kelas sebagai "metadata" di kelas, itu menyarankan metode Java untuk menyandikan metadata di saat runtime: annotations.
Pertama-tama tentukan anotasi khusus di sepanjang baris ini:
Anda kemudian harus menambahkan anotasi ke subkelas Anda.
Kemudian Anda bisa menggunakan kode ini untuk mendapatkan tipe kelas di kelas dasar Anda:
Beberapa batasan dari pendekatan ini adalah:
PassedGenericType
) di DUA tempat daripada yang non-KERING.sumber
Ini solusi saya:
sumber
Inilah solusi yang berfungsi !!!
CATATAN: Dapat digunakan hanya sebagai superclass
1. Harus diperluas dengan kelas yang diketik (
Child extends Generic<Integer>
)ATAU
2. Harus dibuat sebagai implementasi anonim (
new Generic<Integer>() {};
)sumber
Kamu tidak bisa Jika Anda menambahkan variabel anggota tipe T ke kelas (Anda bahkan tidak harus menginisialisasi), Anda bisa menggunakannya untuk memulihkan jenis.
sumber
Inilah satu cara, yang harus saya gunakan sekali atau dua kali:
Bersama
sumber
Salah satu solusi sederhana untuk taksi ini adalah seperti di bawah ini
sumber
Untuk menyelesaikan beberapa jawaban di sini, saya harus mendapatkan ParametrizedType dari MyGenericClass, tidak peduli seberapa tinggi hierarki, dengan bantuan rekursi:
sumber
Ini trik saya:
sumber
T
merupakan variabel tipe. Dalam kasus yangT
merupakan variabel tipe, varargs menciptakan array penghapusanT
. Lihat misalnya http://ideone.com/DIPNwd .Hanya dalam kasus Anda menggunakan menyimpan variabel menggunakan tipe generik Anda dapat dengan mudah menyelesaikan masalah ini menambahkan metode getClassType sebagai berikut:
Saya menggunakan objek kelas yang disediakan nanti untuk memeriksa apakah itu adalah turunan dari kelas yang diberikan, sebagai berikut:
sumber
value
itunull
? Kedua, bagaimana jikavalue
subkelasT
?Constant<Number> c = new Constant<Number>(new Integer(0)); Class<Number> n = c.getClassType();
kembaliInteger.class
ketika seharusnya kembaliNumber.class
. Akan lebih benar untuk kembaliClass<? extends T>
.Integer.class
adalahClass<? extends Number>
tetapi tidak aClass<Number>
.Ini solusinya
Tidak peduli berapa banyak level hierarki kelas Anda, solusi ini tetap berfungsi, misalnya:
Dalam hal ini, getMyType () = java.lang.String
sumber
Exception in thread "main" java.lang.NullPointerException at Main$ClassA.findTypeArguments(Main.java:54) at Main$ClassA.findTypeArguments(Main.java:54) at Main$ClassA.findTypeArguments(Main.java:54) at Main$ClassA.<init>(Main.java:43) at Main.main(Main.java:61)
sumber
Ini solusinya. Contoh harus menjelaskannya. Satu-satunya persyaratan adalah bahwa subkelas harus menetapkan tipe generik, bukan objek.
sumber
Saya melakukan hal yang sama dengan @ Mario di atas tetapi di Kotlin bisa dilakukan dengan cara ini:
sumber
Mungkin bermanfaat bagi seseorang. Anda dapat Menggunakan java.lang.ref.WeakReference; cara ini:
sumber
WeakReference
? Harap berikan penjelasan dengan jawaban Anda, bukan hanya beberapa kode.SomeClass<MyClass>
Anda dapat instantiateSomeClass
dan memanggilgetType
instance itu dan memiliki runtime menjadiMyClass
.WeakReference
? Apa yang Anda katakan tidak berbeda dari sebagian besar jawaban lainnya.AtomicReference
,List
,Set
).Saya menemukan ini sebagai solusi yang mudah dimengerti dan mudah dijelaskan
sumber
(T...t)
. (Itulah sebabnya kode ini tidak berfungsi.)