làm thế nào để instanceof List <MyType>?


87

Làm thế nào tôi có thể làm cho loại thứ này hoạt động? Tôi có thể kiểm tra nếu (obj instanceof List<?>)nhưng không nếu (obj instanceof List<MyType>). Có cách nào có thể làm được điều này không?



Câu trả lời:


49

Điều đó là không thể vì loại dữ liệu bị xóa tại thời điểm biên dịch của generic. Cách duy nhất có thể để làm điều này là viết một số loại trình bao bọc chứa loại nào mà danh sách nắm giữ:

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;
     }
}

Cảm ơn, tôi nghĩ tôi sẽ chỉ chuyển loại chung vào hàm tôi đang gọi để kiểm tra và kiểm tra cả hai mục.
Rocky Pulley

Bạn có thể xây dựng với ví dụ
Thirumal

31
if(!myList.isEmpty() && myList.get(0) instanceof MyType){
    // MyType object
}

6
... và cho một danh sách trống? Suy ngẫm?
Gewure

Đúng vậy. Đó là tùy chọn duy nhất có sẵn cho danh sách trống. stackoverflow.com/questions/1942644/…
Sathish

11
Câu trả lời này không an toàn, bởi vì ngay cả khi phần tử 0 là MyType, các phần tử khác có thể là các loại khác. Ví dụ: có thể danh sách được khai báo là ArrayList <Đối tượng>, sau đó MyType được thêm vào, và sau đó một Chuỗi được thêm vào.
Adam Gawne-Cain

@ AdamGawne-Cain Nó không an toàn, nhưng rất tiếc là giải pháp duy nhất cho những người KHÔNG biết nhiều về danh sách. Ví dụ - tôi có một biến cục bộ valuetrả về Objectvà tôi cần kiểm tra - nếu đó là một danh sách, nếu có, hãy kiểm tra xem loại danh sách có thể hiện trong giao diện của tôi hay không. Không có trình bao bọc hoặc kiểu tham số nào hữu ích ở đây.
SocketByte

Ở đâu myList tuyên bố?
IgorGanapolsky


6

Điều này có thể được sử dụng nếu bạn muốn kiểm tra bản sao objectcủa List<T>, bản nào không trống:

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.
    }
}

2
    if (list instanceof List && ((List) list).stream()
                                             .noneMatch((o -> !(o instanceof MyType)))) {}

1

Nếu bạn đang xác minh xem tham chiếu của một Danh sách hoặc giá trị Ánh xạ của Đối tượng có phải là một thể hiện của Tập hợp hay không, chỉ cần tạo một thể hiện của Danh sách bắt buộc và lấy lớp của nó ...

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());

Điểm của bạn là gì setOfIntegerssetOfStrings?
DanielM

@DanielM vừa cập nhật mẫu. Nó phải được sử dụng những tài liệu tham khảo! Cảm ơn!
Marcello de Sales

1

Nếu điều này không thể được bao bọc bằng generic (câu trả lời của @ Martijn) thì tốt hơn nên chuyển nó mà không truyền để tránh lặp lại danh sách thừa (kiểm tra kiểu của phần tử đầu tiên không đảm bảo gì). Chúng ta có thể ép kiểu từng phần tử trong đoạn mã mà chúng ta lặp lại danh sách.

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 );
    }
}

0

Bạn có thể sử dụng một nhà máy giả để bao gồm nhiều phương pháp thay vì sử dụng instanceof:

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);
    }
}

0

Mối quan tâm chính ở đây là các bộ sưu tập không giữ kiểu trong định nghĩa. Các loại chỉ có sẵn trong thời gian chạy. Tôi đã nghĩ ra một hàm để kiểm tra các bộ sưu tập phức tạp (mặc dù nó có một hạn chế).

Kiểm tra xem đối tượng có phải là một thể hiện của một tập hợp chung hay không. Để thể hiện một bộ sưu tập,

  • Không có lớp học, luôn luôn false
  • Một lớp, nó không phải là một tập hợp và trả về kết quả instanceofđánh giá
  • Để biểu diễn một Listhoặc Set, loại danh sách sẽ xuất hiện tiếp theo, ví dụ: {Danh sách, Số nguyên} choList<Integer>
  • Để biểu diễn a Map, các kiểu khóa và giá trị xuất hiện tiếp theo, ví dụ: {Bản đồ, Chuỗi, Số nguyên} choMap<String, Integer>

Các trường hợp sử dụng phức tạp hơn có thể được tạo bằng cách sử dụng các quy tắc tương tự. Ví dụ để đại diện List<Map<String, GenericRecord>>, nó có thể được gọi là

    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);

Lưu ý rằng triển khai này không hỗ trợ các kiểu lồng nhau trong Bản đồ. Do đó, loại khóa và giá trị phải là một lớp chứ không phải một tập hợp. Nhưng không khó để thêm nó.

    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;
    }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.