ArrayList's มีวิธี () ประเมินวัตถุอย่างไร


303

ArrayListบอกว่าผมสร้างวัตถุหนึ่งและเพิ่มเข้าไปในของฉัน ถ้าฉันสร้างวัตถุอื่นที่มีอินพุตคอนสตรัคเตอร์เดียวกันcontains()วิธีจะประเมินทั้งสองวัตถุให้เหมือนกันหรือไม่ สมมติว่าคอนสตรัคเตอร์ไม่ได้ทำอะไรตลก ๆ กับอินพุตและตัวแปรที่เก็บไว้ในวัตถุทั้งสองเหมือนกัน

ArrayList<Thing> basket = new ArrayList<Thing>();  
Thing thing = new Thing(100);  
basket.add(thing);  
Thing another = new Thing(100);  
basket.contains(another); // true or false?

class Thing {  
    public int value;  

    public Thing (int x) {
        value = x;
    }

    equals (Thing x) {
        if (x.value == value) return true;
        return false;
    }
}

นี่เป็นวิธีที่classควรนำมาใช้เพื่อให้ได้contains()ผลตอบแทนtrueหรือไม่?

คำตอบ:


339

ArrayList implementsรายการอินเตอร์เฟส

ถ้าคุณมองไปที่Javadoc สำหรับListที่containsวิธีการที่คุณจะเห็นว่าจะใช้equals()วิธีการในการประเมินว่าวัตถุทั้งสองเหมือนกัน


61
ในกรณีที่คุณวางแผนที่จะแทนที่เท่ากับ () ให้แน่ใจว่าคุณแทนที่ hashcode () วิธีการเช่นกัน หากคุณเคยทำสิ่งต่าง ๆ อาจไม่ทำงานอย่างที่คาดไว้ในขณะที่ใช้งานคอลเล็กชัน
Mohd Farid

34
นี่คือคำตอบที่ถูกต้อง แต่ทราบว่าคุณจะต้องเปลี่ยนวิธีการของคุณเท่ากับยอมรับมากกว่าObject Thingหากคุณไม่ทำเช่นนี้จะไม่ใช้วิธีการเท่ากับของคุณ :)
mdierker

1
เพิ่งค้นพบด้วยตนเองว่าคราสมี "สร้าง hashCode () และเท่ากับ" ภายใต้เมนูแหล่งที่มา
Volodymyr Krupach

นี่จะตอบคำถามในชื่อ แต่ไม่ใช่คำถามในคำอธิบายนั่นคือ "ถ้าฉันสร้างวัตถุอื่นที่มีอินพุตคอนสตรัคเตอร์เดียวกันแน่นอนเมธอด contain () จะประเมินทั้งสองวัตถุให้เหมือนกันหรือไม่"
robguinness

3
Collectionsทำสิ่งต่าง ๆ ด้วยวิธีที่เหมาะสมที่สุดซึ่งหมายถึงการcontains()ตรวจสอบhashCodes ของวัตถุทั้งสองก่อนจากนั้นจึงเรียกequals()เท่านั้น หากhashCodes แตกต่างกัน (ซึ่งมักเป็นกรณีสำหรับสองอินสแตนซ์ที่ต่างกันThing) equals()จะไม่เรียกใช้เมธอด ตามกฎง่ายๆเมื่อคุณแทนที่equals()คุณไม่ควรลืมแทนที่hashCode()ด้วย
Sevastyan Savanyuk

52

ฉันคิดว่าการใช้งานที่เหมาะสมควรเป็น

public class Thing
{
    public int value;  

    public Thing (int x)
    {
        this.value = x;
    }

    @Override
    public boolean equals(Object object)
    {
        boolean sameSame = false;

        if (object != null && object instanceof Thing)
        {
            sameSame = this.value == ((Thing) object).value;
        }

        return sameSame;
    }
}

1
ifคำสั่งไม่จำเป็น instanceofก็เพียงพอแล้ว
พอล

@ พอลเป็นส่วนใดของข้อความที่คุณพูดถึง?
ChristopheCVB

4
object != nullสภาพไม่จำเป็นเพราะobject instanceof Thingการตรวจสอบสำหรับวัตถุที่เป็นโมฆะไม่มากเกินไป
Alexander Farber

15

ArrayList ใช้วิธีการเท่ากับที่ใช้ในชั้นเรียน (กรณีของคุณสิ่งที่ชั้น) เพื่อทำการเปรียบเทียบเท่ากับ


12

โดยทั่วไปคุณควรแทนที่hashCode()ในแต่ละครั้งที่คุณแทนที่equals()แม้ว่าเพียงเพื่อเพิ่มประสิทธิภาพ HashCode()ตัดสินใจที่ 'ถัง' วัตถุของคุณได้รับการเรียงลำดับเป็นเมื่อทำการเปรียบเทียบใด ๆ ดังนั้นวัตถุสองซึ่งประเมินเป็นจริงควรจะกลับเหมือนกันequal() hashCode value()ฉันไม่สามารถจำพฤติกรรมเริ่มต้นของhashCode()(ถ้ามันคืน 0 แล้วรหัสของคุณควรทำงาน แต่ช้า แต่ถ้ามันกลับที่อยู่แล้วรหัสของคุณจะล้มเหลว) ฉันจะจำพวงของครั้งเมื่อรหัสของฉันล้มเหลวเนื่องจากฉันลืมที่จะแทนที่hashCode()แม้ว่า :)


7

มันใช้วิธีการเท่ากับบนวัตถุ ดังนั้นหากสิ่งที่แทนที่เท่ากับและใช้ตัวแปรที่เก็บไว้ในวัตถุสำหรับการเปรียบเทียบมันจะไม่กลับจริงในcontains()วิธีการ


6
class Thing {  
    public int value;  

    public Thing (int x) {
        value = x;
    }

    equals (Thing x) {
        if (x.value == value) return true;
        return false;
    }
}

คุณต้องเขียน:

class Thing {  
    public int value;  

    public Thing (int x) {
        value = x;
    }

    public boolean equals (Object o) {
    Thing x = (Thing) o;
        if (x.value == value) return true;
        return false;
    }
}

ตอนนี้มันทำงาน;)


6
คุณไม่ควรทำสิ่ง x = (สิ่ง) o; โดยไม่ตรวจสอบก่อนว่าวัตถุอื่นเป็นโมฆะหรือไม่
steelshark

5

เพิ่งต้องการทราบว่าการใช้งานต่อไปนี้ไม่ถูกต้องเมื่อvalueไม่ใช่ชนิดดั้งเดิม:

public class Thing
{
    public Object value;  

    public Thing (Object x)
    {
        this.value = x;
    }

    @Override
    public boolean equals(Object object)
    {
        boolean sameSame = false;

        if (object != null && object instanceof Thing)
        {
            sameSame = this.value == ((Thing) object).value;
        }

        return sameSame;
    }
}

ในกรณีนั้นฉันขอเสนอสิ่งต่อไปนี้:

public class Thing {
    public Object value;  

    public Thing (Object x) {
        value = x;
    }

    @Override
    public boolean equals(Object object) {

        if (object != null && object instanceof Thing) {
            Thing thing = (Thing) object;
            if (value == null) {
                return (thing.value == null);
            }
            else {
                return value.equals(thing.value);
            }
        }

        return false;
    }
}

วิธีการใช้งานในขณะที่การกำจัดสิ่งที่ซ้ำกัน?
Sujay

4

โปสเตอร์อื่น ๆ ได้ตอบคำถามเกี่ยวกับการทำงานของ ()

คำถามที่สำคัญอย่างเท่าเทียมกันของคุณคือการใช้อย่างถูกต้องเท่ากับ () และคำตอบสำหรับเรื่องนี้ขึ้นอยู่กับสิ่งที่ก่อให้เกิดความเท่าเทียมกันของวัตถุสำหรับชั้นเรียนนี้โดยเฉพาะ ในตัวอย่างที่คุณให้ไว้ถ้าคุณมีวัตถุที่แตกต่างกันสองอย่างที่ทั้งคู่มี x = 5 พวกมันเท่ากันหรือไม่ มันขึ้นอยู่กับสิ่งที่คุณพยายามทำจริงๆ

หากคุณสนใจเพียงความเท่าเทียมกันของวัตถุดังนั้นการใช้งานเริ่มต้นของ. equals () (ที่จัดทำโดย Object) จะใช้ข้อมูลเฉพาะตัวเท่านั้น (เช่นนี้ == อื่น ๆ ) ถ้านั่นคือสิ่งที่คุณต้องการก็ไม่ต้องใช้เท่ากับ () ในชั้นเรียนของคุณ (ปล่อยให้มันสืบทอดมาจาก Object) รหัสที่คุณเขียนในขณะที่ชนิดที่ถูกต้องหากคุณกำลังหาตัวตนจะไม่ปรากฏในคลาสจริง b / c มันไม่ได้ให้ประโยชน์มากกว่าการใช้การเริ่มต้น Object.equals () การใช้งาน

หากคุณเพิ่งเริ่มต้นกับสิ่งนี้ฉันขอแนะนำหนังสือ Java ที่มีประสิทธิภาพโดย Joshua Bloch มันเป็นการอ่านที่ยอดเยี่ยมและครอบคลุมสิ่งต่าง ๆ (รวมถึงวิธีการใช้งานอย่างถูกต้องเท่ากับ) เมื่อคุณพยายามทำมากกว่าการเปรียบเทียบตามตัวตน


เพื่อจุดประสงค์ของฉันฉันพยายามดูว่าวัตถุที่มีค่าเท่ากันนั้นอยู่ใน ArrayList หรือไม่ ฉันคิดว่ามันเป็นแฮ็ค ขอบคุณสำหรับคำแนะนำหนังสือ
Mantas Vidutis

3

ทางลัดจากJavaDoc :

บูลีน มี (วัตถุ o)

ผลตอบแทนจริงถ้ารายการนี้มีองค์ประกอบที่ระบุ เป็นทางการมากขึ้นส่งคืนค่าจริงถ้าหากรายการนี้มีองค์ประกอบอย่างน้อยหนึ่งองค์ประกอบเช่นนั้น(o == null? e == null: o.equals (e))

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