วิธีการใส่รายการ <MyType>


88

ฉันจะทำให้สิ่งนี้ทำงานได้อย่างไร? ฉันสามารถตรวจสอบว่าแต่ไม่ถ้า(obj instanceof List<?>) (obj instanceof List<MyType>)มีวิธีนี้ไหม?



คำตอบ:


49

เป็นไปไม่ได้เนื่องจากการลบข้อมูลประเภทข้อมูลในเวลาคอมไพล์ของข้อมูลทั่วไป วิธีเดียวที่เป็นไปได้ในการทำเช่นนี้คือการเขียนกระดาษห่อหุ้มบางชนิดที่เก็บรายการประเภทนี้ไว้:

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

ขอบคุณฉันคิดว่าฉันจะส่งประเภททั่วไปไปยังฟังก์ชันที่ฉันเรียกเพื่อตรวจสอบและตรวจสอบทั้งสองรายการ
Rocky Pulley

คุณช่วยอธิบายโดยละเอียดได้ไหม
Thirumal

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

7
... และสำหรับรายการที่ว่างเปล่า? สะท้อน?
Gewure

ใช่ นี่เป็นตัวเลือกเดียวสำหรับรายการว่าง stackoverflow.com/questions/1942644/…
Sathish

12
คำตอบนี้ไม่ปลอดภัยเพราะแม้ว่าองค์ประกอบ 0 จะเป็น MyType แต่องค์ประกอบอื่น ๆ ก็อาจเป็นประเภทอื่นได้ ตัวอย่างเช่นรายการอาจถูกประกาศเป็น ArrayList <Object> จากนั้นจึงมีการเพิ่ม MyType จากนั้นจึงมีการเพิ่ม String
Adam Gawne-Cain

@ AdamGawne-Cain มันไม่ปลอดภัย แต่โชคร้ายเป็นทางออกเดียวสำหรับคนที่ไม่รู้มากเกี่ยวกับรายการ ตัวอย่างเช่น - ฉันมีตัวแปรโลคัลvalueที่ส่งคืนObjectและฉันต้องตรวจสอบ - หากเป็นรายการหากเป็นเช่นนั้นให้ตรวจสอบว่าอินสแตนซ์ประเภทรายการของอินเทอร์เฟซของฉันหรือไม่ ไม่มีกระดาษห่อหุ้มหรือประเภทพาราเมตริกที่มีประโยชน์ที่นี่
SocketByte

อยู่ที่ไหนmyListประกาศ?
IgorGanapolsky

9

คุณอาจต้องใช้การสะท้อนเพื่อรับประเภทของสิ่งเหล่านี้เพื่อตรวจสอบ หากต้องการรับประเภทของรายการ: รับ ประเภททั่วไปของ java.util.List


2
เท่าที่ฉันรู้มันใช้ได้เฉพาะกับฟิลด์ แต่ +1 สำหรับการกล่าวถึง
Tim Pote

6

สามารถใช้หากคุณต้องการตรวจสอบว่าobjectเป็นอินสแตนซ์List<T>ซึ่งไม่ว่างเปล่า:

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


1

หากคุณกำลังตรวจสอบว่าการอ้างอิงของค่า List หรือ Map ของ Object เป็นอินสแตนซ์ของ Collection หรือไม่เพียงแค่สร้างอินสแตนซ์ของ List ที่ต้องการและรับคลาส ...

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และsetOfStrings?
DanielM

@DanielM เพิ่งอัปเดตตัวอย่าง ต้องใช้การอ้างอิงเหล่านั้น! ขอบคุณ!
Marcello de Sales

1

หากสิ่งนี้ไม่สามารถพันด้วย generics ได้ (คำตอบของ @ Martijn) จะเป็นการดีกว่าที่จะส่งผ่านโดยไม่ต้องแคสต์เพื่อหลีกเลี่ยงการทำซ้ำรายการซ้ำซ้อน (การตรวจสอบประเภทขององค์ประกอบแรกจะไม่รับประกันว่าไม่มีอะไรเลย) เราสามารถโยนแต่ละองค์ประกอบในส่วนของรหัสที่เราทำรายการซ้ำ

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

คุณสามารถใช้โรงงานปลอมเพื่อรวมหลายวิธีแทนที่จะใช้ 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

ข้อกังวลหลักที่นี่คือคอลเล็กชันไม่คงประเภทไว้ในคำจำกัดความ ประเภทมีเฉพาะในรันไทม์เท่านั้น ฉันมาพร้อมกับฟังก์ชันเพื่อทดสอบคอลเล็กชันที่ซับซ้อน (มีข้อ จำกัด อย่างหนึ่ง)

ตรวจสอบว่าวัตถุนั้นเป็นตัวอย่างของคอลเลกชันทั่วไปหรือไม่ เพื่อเป็นตัวแทนของคอลเลกชัน

  • ไม่มีชั้นเรียนเสมอไป false
  • ชั้นเดียวไม่ใช่การรวบรวมและส่งกลับผลinstanceofการประเมิน
  • ในการแสดงListหรือSetประเภทของรายการจะตามมาเช่น{List, Integer}สำหรับList<Integer>
  • ในการแทนMapค่าประเภทคีย์และค่าจะตามมาเช่น {Map, String, Integer} สำหรับMap<String, Integer>

สามารถสร้างกรณีการใช้งานที่ซับซ้อนขึ้นได้โดยใช้กฎเดียวกัน ตัวอย่างเช่นเพื่อเป็นตัวแทนList<Map<String, GenericRecord>>สามารถเรียกได้ว่าเป็น

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

โปรดทราบว่าการใช้งานนี้ไม่รองรับประเภทที่ซ้อนกันในแผนที่ ดังนั้นประเภทของคีย์และค่าควรเป็นคลาสไม่ใช่คอลเล็กชัน แต่ไม่ควรยากที่จะเพิ่ม

    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;
    }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.