Bagaimana saya bisa membuat hal semacam ini bekerja? Saya dapat memeriksa apakah (obj instanceof List<?>)tetapi tidak jika (obj instanceof List<MyType>). Adakah cara untuk melakukannya?
Itu tidak mungkin karena penghapusan tipe data pada waktu kompilasi obat generik. Satu-satunya cara yang mungkin untuk melakukan ini adalah dengan menulis semacam pembungkus yang menampung jenis yang dipegang daftar:
Jawaban ini tidak aman, karena meskipun 0 elemen adalah MyType, elemen lainnya bisa jadi tipe lain. Misalnya, mungkin daftar dideklarasikan sebagai ArrayList <Object>, lalu MyType ditambahkan, lalu String ditambahkan.
Adam Gawne-Cain
@ AdamGawne-Cain Ini tidak aman, tapi sayangnya satu-satunya solusi bagi orang yang TIDAK tahu banyak tentang daftar. Misalnya - Saya memiliki variabel lokal valueyang kembali Object, dan saya perlu memeriksa - jika itu adalah daftar, jika ada, periksa apakah contoh jenis daftar antarmuka saya. Tidak ada jenis pembungkus atau parameter yang berguna di sini.
SocketByte
Di mana myList dideklarasikan?
IgorGanapolsky
9
Anda mungkin perlu menggunakan refleksi untuk mendapatkan jenisnya untuk diperiksa. Untuk mendapatkan tipe List:
Dapatkan tipe generik java.util.List
Sejauh yang saya tahu, itu hanya berfungsi untuk bidang, tetapi +1 untuk menyebutkannya.
Tim Pote
6
Ini bisa digunakan jika Anda ingin memeriksanya object itu instance List<T>, yang tidak kosong:
if(object instanceof List){
if(((List)object).size()>0 && (((List)object).get(0) instanceof MyObject)){
// The object is of List<MyObject> and is not empty. Do something with it.
}
}
Jika Anda memverifikasi apakah referensi dari nilai Daftar atau Peta Objek adalah turunan dari Koleksi, cukup buat contoh Daftar yang diperlukan dan dapatkan kelasnya ...
Set<Object> setOfIntegers = new HashSet(Arrays.asList(2, 4, 5));
assetThat(setOfIntegers).instanceOf(new ArrayList<Integer>().getClass());
Set<Object> setOfStrings = new HashSet(Arrays.asList("my", "name", "is"));
assetThat(setOfStrings).instanceOf(new ArrayList<String>().getClass());
@DanielM baru saja memperbarui sampel. Itu pasti menggunakan referensi itu! Terima kasih!
Marcello de Sales
1
Jika ini tidak dapat digabungkan dengan generik (jawaban @ Martijn), lebih baik meneruskannya tanpa casting untuk menghindari iterasi daftar yang berlebihan (memeriksa jenis elemen pertama tidak menjamin apa pun). Kita dapat mentransmisikan setiap elemen dalam potongan kode tempat kita mengulang daftar.
Object attVal = jsonMap.get("attName");
List<Object> ls = new ArrayList<>();
if (attVal instanceof List) {
ls.addAll((List) attVal);
} else {
ls.add(attVal);
}
// far, far away ;)for (Object item : ls) {
if (item instanceof String) {
System.out.println(item);
} else {
thrownew RuntimeException("Wrong class ("+item .getClass()+") of "+item );
}
}
Perhatian utama di sini adalah bahwa koleksi tidak menyimpan tipe dalam definisi. Jenis ini hanya tersedia saat runtime. Saya datang dengan fungsi untuk menguji koleksi yang kompleks (meskipun ada satu kendala).
Periksa apakah objek tersebut merupakan turunan dari koleksi generik. Untuk mewakili sebuah koleksi,
Tidak ada kelas, selalu false
Satu kelas, itu bukan koleksi dan mengembalikan hasil instanceof evaluasi
Untuk mewakili a Listatau Set, jenis daftar datang berikutnya, misalnya {List, Integer} untukList<Integer>
Untuk merepresentasikan a Map, kunci dan tipe nilai datang berikutnya misalnya {Map, String, Integer} forMap<String, Integer>
Kasus penggunaan yang lebih kompleks dapat dibuat menggunakan aturan yang sama. Misalnya untuk merepresentasikan List<Map<String, GenericRecord>>dapat disebut sebagai
Perhatikan bahwa implementasi ini tidak mendukung tipe bertingkat di Peta. Oleh karena itu, jenis kunci dan nilai harus berupa kelas dan bukan koleksi. Tetapi seharusnya tidak sulit untuk menambahkannya.
publicstaticbooleanisInstanceOfGenericCollection(Object object, Class<?>... classes){
if (classes.length == 0) returnfalse;
if (classes.length == 1) return classes[0].isInstance(object);
if (classes[0].equals(List.class))
return object instanceof List && ((List<?>) object).stream().allMatch(item -> isInstanceOfGenericCollection(item, Arrays.copyOfRange(classes, 1, classes.length)));
if (classes[0].equals(Set.class))
return object instanceof Set && ((Set<?>) object).stream().allMatch(item -> isInstanceOfGenericCollection(item, Arrays.copyOfRange(classes, 1, classes.length)));
if (classes[0].equals(Map.class))
return object instanceof Map &&
((Map<?, ?>) object).keySet().stream().allMatch(classes[classes.length - 2]::isInstance) &&
((Map<?, ?>) object).values().stream().allMatch(classes[classes.length - 1]::isInstance);
returnfalse;
}
Jawaban:
Itu tidak mungkin karena penghapusan tipe data pada waktu kompilasi obat generik. Satu-satunya cara yang mungkin untuk melakukan ini adalah dengan menulis semacam pembungkus yang menampung jenis yang dipegang daftar:
public class GenericList <T> extends ArrayList<T> { private Class<T> genericType; public GenericList(Class<T> c) { this.genericType = c; } public Class<T> getGenericType() { return genericType; } }
sumber
if(!myList.isEmpty() && myList.get(0) instanceof MyType){ // MyType object }
sumber
value
yang kembaliObject
, dan saya perlu memeriksa - jika itu adalah daftar, jika ada, periksa apakah contoh jenis daftar antarmuka saya. Tidak ada jenis pembungkus atau parameter yang berguna di sini.Anda mungkin perlu menggunakan refleksi untuk mendapatkan jenisnya untuk diperiksa. Untuk mendapatkan tipe List: Dapatkan tipe generik java.util.List
sumber
Ini bisa digunakan jika Anda ingin memeriksanya
object
itu instanceList<T>
, yang tidak kosong:if(object instanceof List){ if(((List)object).size()>0 && (((List)object).get(0) instanceof MyObject)){ // The object is of List<MyObject> and is not empty. Do something with it. } }
sumber
if (list instanceof List && ((List) list).stream() .noneMatch((o -> !(o instanceof MyType)))) {}
sumber
Jika Anda memverifikasi apakah referensi dari nilai Daftar atau Peta Objek adalah turunan dari Koleksi, cukup buat contoh Daftar yang diperlukan dan dapatkan kelasnya ...
Set<Object> setOfIntegers = new HashSet(Arrays.asList(2, 4, 5)); assetThat(setOfIntegers).instanceOf(new ArrayList<Integer>().getClass()); Set<Object> setOfStrings = new HashSet(Arrays.asList("my", "name", "is")); assetThat(setOfStrings).instanceOf(new ArrayList<String>().getClass());
sumber
setOfIntegers
dansetOfStrings
?Jika ini tidak dapat digabungkan dengan generik (jawaban @ Martijn), lebih baik meneruskannya tanpa casting untuk menghindari iterasi daftar yang berlebihan (memeriksa jenis elemen pertama tidak menjamin apa pun). Kita dapat mentransmisikan setiap elemen dalam potongan kode tempat kita mengulang daftar.
Object attVal = jsonMap.get("attName"); List<Object> ls = new ArrayList<>(); if (attVal instanceof List) { ls.addAll((List) attVal); } else { ls.add(attVal); } // far, far away ;) for (Object item : ls) { if (item instanceof String) { System.out.println(item); } else { throw new RuntimeException("Wrong class ("+item .getClass()+") of "+item ); } }
sumber
Anda dapat menggunakan pabrik palsu untuk memasukkan banyak metode daripada menggunakan contoh:
public class Message1 implements YourInterface { List<YourObject1> list; Message1(List<YourObject1> l) { list = l; } } public class Message2 implements YourInterface { List<YourObject2> list; Message2(List<YourObject2> l) { list = l; } } public class FactoryMessage { public static List<YourInterface> getMessage(List<YourObject1> list) { return (List<YourInterface>) new Message1(list); } public static List<YourInterface> getMessage(List<YourObject2> list) { return (List<YourInterface>) new Message2(list); } }
sumber
Perhatian utama di sini adalah bahwa koleksi tidak menyimpan tipe dalam definisi. Jenis ini hanya tersedia saat runtime. Saya datang dengan fungsi untuk menguji koleksi yang kompleks (meskipun ada satu kendala).
Periksa apakah objek tersebut merupakan turunan dari koleksi generik. Untuk mewakili sebuah koleksi,
false
instanceof
evaluasiList
atauSet
, jenis daftar datang berikutnya, misalnya {List, Integer} untukList<Integer>
Map
, kunci dan tipe nilai datang berikutnya misalnya {Map, String, Integer} forMap<String, Integer>
Kasus penggunaan yang lebih kompleks dapat dibuat menggunakan aturan yang sama. Misalnya untuk merepresentasikan
List<Map<String, GenericRecord>>
dapat disebut sebagaiMap<String, Integer> map = new HashMap<>(); map.put("S1", 1); map.put("S2", 2); List<Map<String, Integer> obj = new ArrayList<>(); obj.add(map); isInstanceOfGenericCollection(obj, List.class, List.class, Map.class, String.class, GenericRecord.class);
Perhatikan bahwa implementasi ini tidak mendukung tipe bertingkat di Peta. Oleh karena itu, jenis kunci dan nilai harus berupa kelas dan bukan koleksi. Tetapi seharusnya tidak sulit untuk menambahkannya.
public static boolean isInstanceOfGenericCollection(Object object, Class<?>... classes) { if (classes.length == 0) return false; if (classes.length == 1) return classes[0].isInstance(object); if (classes[0].equals(List.class)) return object instanceof List && ((List<?>) object).stream().allMatch(item -> isInstanceOfGenericCollection(item, Arrays.copyOfRange(classes, 1, classes.length))); if (classes[0].equals(Set.class)) return object instanceof Set && ((Set<?>) object).stream().allMatch(item -> isInstanceOfGenericCollection(item, Arrays.copyOfRange(classes, 1, classes.length))); if (classes[0].equals(Map.class)) return object instanceof Map && ((Map<?, ?>) object).keySet().stream().allMatch(classes[classes.length - 2]::isInstance) && ((Map<?, ?>) object).values().stream().allMatch(classes[classes.length - 1]::isInstance); return false; }
sumber