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?
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?
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;
}
}
if(!myList.isEmpty() && myList.get(0) instanceof MyType){
// MyType object
}
value
yang 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.
Anda mungkin perlu menggunakan refleksi untuk mendapatkan jenisnya untuk diperiksa. Untuk mendapatkan tipe List: Dapatkan tipe generik java.util.List
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.
}
}
if (list instanceof List && ((List) list).stream()
.noneMatch((o -> !(o instanceof MyType)))) {}
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());
setOfIntegers
dan setOfStrings
?
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 );
}
}
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);
}
}
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
atau Set
, 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 sebagai
Map<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;
}