วิธีการเท่ากับในคลาสวัตถุใช้เพื่อตรวจจับว่าวัตถุเท่ากับวัตถุอื่นหรือไม่ ในคลาสวัตถุวิธีนี้กำหนดว่าวัตถุสองชิ้นมีการอ้างอิงเดียวกันหรือไม่ หากวัตถุทั้งสองมีการอ้างอิงเหมือนกันพวกเขาจะต้องเท่ากัน จากมุมมองนี้มีเหตุผลที่จะใช้เป็นการดำเนินการเริ่มต้น อย่างไรก็ตามสำหรับชั้นเรียนส่วนใหญ่การตัดสินนี้ไม่มีความหมาย ตัวอย่างเช่นมันไม่มีความหมายอย่างสมบูรณ์ที่จะเปรียบเทียบว่าสอง printstreams มีค่าเท่ากันในลักษณะนี้หรือไม่ อย่างไรก็ตามมักจะจำเป็นต้องตรวจจับความเท่าเทียมกันของรัฐของวัตถุสองชิ้น หากสถานะของวัตถุทั้งสองเท่ากันวัตถุทั้งสองจะถือว่าเท่ากัน ดังนั้นโดยทั่วไปการเปรียบเทียบจะต้องเขียนใหม่ในชั้นเรียนที่กำหนดเอง
นี่คือคำแนะนำบางประการสำหรับการเขียนวิธีการที่สมบูรณ์แบบ ():
(1) พารามิเตอร์ที่ชัดเจนมีชื่อว่า OtherObject และจำเป็นต้องแปลงเป็นตัวแปรที่เรียกว่าอื่น ๆ ในภายหลัง
(2) ตรวจพบว่าสิ่งนี้และอื่น ๆ จะอ้างถึงวัตถุเดียวกันหรือไม่:
if (this == otherObject) ส่งคืนจริง;
คำสั่งนี้เป็นเพียงการเพิ่มประสิทธิภาพ ในความเป็นจริงนี่เป็นรูปแบบที่มักจะนำมาใช้ เนื่องจากการคำนวณสมการนี้มีราคาถูกกว่าการเปรียบเทียบฟิลด์ในชั้นหนึ่งทีละคน
(3) ตรวจสอบว่า OtherObject เป็นโมฆะหรือไม่และถ้าเป็นโมฆะให้ส่งคืนเท็จ การทดสอบนี้เป็นสิ่งจำเป็น
ถ้า (otherObject == null) ส่งคืนเท็จ;
(4) เปรียบเทียบว่าสิ่งนี้และอื่น ๆ เป็นของคลาสเดียวกันหรือไม่ หากความหมายของค่าเท่ากับการเปลี่ยนแปลงในแต่ละคลาสย่อยให้ใช้ getClass () เพื่อตรวจจับซึ่งใช้ตัวเองเป็นคลาสเป้าหมาย
ถ้า (getClass ()! = otherObject.getClass ()) ส่งคืนเท็จ;
หากคลาสย่อยทั้งหมดมีความหมายเดียวกันให้ใช้การตรวจจับอินสแตนซ์ของอินสแตนซ์
if (! (otherObject อินสแตนซ์ของ classname)) ส่งคืน false;
(5) แปลง OtherObject เป็นตัวแปรของประเภทที่เกี่ยวข้อง:
className other = (className) otherObject;
(6) ตอนนี้เริ่มเปรียบเทียบโดเมนทั้งหมดที่ต้องเปรียบเทียบ ใช้ == เพื่อเปรียบเทียบโดเมนประเภทพื้นฐานและใช้เท่ากับเพื่อเปรียบเทียบโดเมนวัตถุ ส่งคืนจริงถ้าฟิลด์ทั้งหมดตรงกันมิฉะนั้นจะส่งคืนเท็จ
return field1 == other.field1 && field2.equals (other.field2)
หาก Equals ถูกกำหนดใหม่ในคลาสย่อยคุณต้องรวมการโทร super.equals (อื่น ๆ ) หากการตรวจจับล้มเหลวมันเป็นไปไม่ได้ที่จะเท่ากัน หากโดเมนใน superclass เท่ากันให้เปรียบเทียบโดเมนอินสแตนซ์ในคลาสย่อย
สำหรับฟิลด์ประเภทอาร์เรย์คุณสามารถใช้อาร์เรย์แบบคงที่วิธี Equals เพื่อตรวจสอบว่าองค์ประกอบที่เกี่ยวข้องมีค่าเท่ากันหรือไม่
มาดูตัวอย่างการเปรียบเทียบของสตริง:
สตริง a = "abc"; สตริง b = "abc"; สตริง c = สตริงใหม่ ("abc"); สตริง d = สตริงใหม่ ("abc"); System.out.println (a == b); // true เนื่องจากค่าคงที่สตริงถูกแชร์ใน Java มีเพียงหนึ่งระบบคัดลอก system.out.println (a == c); // เท็จ A และ C เป็นของ 2 วัตถุที่แตกต่างกัน System.out.println (A.Equals (C)); // จริงเนื่องจากวิธีการเท่ากับของวัตถุสตริงเปรียบเทียบค่าในวัตถุมันจะส่งคืนจริง (แตกต่างจากวิธีการเท่ากับของวัตถุ) system.out.println (c == d); // false แม้ว่าค่าในวัตถุจะเหมือนกัน แต่เป็นของ 2 วัตถุที่แตกต่างกันดังนั้นพวกเขาจึงไม่เท่ากัน System.out.println (C.Equals (D)); // จริงพูดง่ายๆเมื่อเปรียบเทียบค่าคงที่สตริงมันจะเหมือนกับผลลัพธ์ที่ส่งคืนโดยเท่ากับ เมื่อคุณต้องการเปรียบเทียบค่าของวัตถุสตริงให้ใช้เท่ากับ
ดูตัวอย่างการใช้เท่ากับ:
แพ็คเกจบทที่ 05.Equalstest; นำเข้า Java.util.*; ระดับสาธารณะที่เท่าเทียมกัน {โมฆะสาธารณะคงที่หลัก (สตริง [] args) {พนักงาน Alice1 = พนักงานใหม่ ("Alice Adams", 75000, 1987, 12, 15, 15); พนักงาน Alice2 = Alice1; // อ้างอิงพนักงานวัตถุเดียวกัน Alice3 = พนักงานใหม่ ("Alice Adams", 75000, 1987, 12, 15); พนักงาน Bob = พนักงานใหม่ ("Bob Brandson", 50000, 1989, 10, 1); System.out.println ("Alice1 == Alice2:" + (Alice1 == Alice2)); System.out.println ("Alice1 == Alice3:" + (Alice1 == Alice3)); System.out.println ("Alice1.equals (Alice3):" + (Alice1.equals (Alice3))); System.out.println ("Alice1.equals (Bob):" + (Alice1.equals (Bob))); System.out.println (bob.toString ()); }} พนักงานชั้นเรียน {พนักงานสาธารณะ (สตริง n, double s, int ปี, เดือน int, วัน int) {name = n; เงินเดือน = S; ปฏิทิน Gregoriancalendar = New Gregoriancalendar (ปี, เดือน, วัน); hireday = calendar.getTime (); } สตริงสาธารณะ getName () {ชื่อคืน; } สาธารณะสองเท่า () {คืนเงินเดือน; } วันที่สาธารณะ getHireday () {return hireday; } โมฆะสาธารณะ Raisesalary (สองเท่า) {เพิ่มสองครั้ง = เงินเดือน * bypercent / 100; เงินเดือน += เพิ่ม; } @Override บูลีนสาธารณะเท่ากับ (Object OtherObject) {// การทดสอบอย่างรวดเร็วเพื่อดูว่าวัตถุถูกระบุหรือไม่ถ้า (นี่ == otherObject) กลับมาจริง; // ต้องส่งคืนเท็จหากพารามิเตอร์ที่ชัดเจนเป็นโมฆะถ้า (อื่น ๆ == null) ส่งคืนเท็จ; // ถ้าการจัดประเภทไม่ตรงกันพวกเขาจะไม่เท่ากันถ้า (getClass ()! = otherObject.getClass ()) ส่งคืนเท็จ // ตอนนี้เรารู้แล้วว่า OtherObject เป็นพนักงานที่ไม่ใช่พนักงานอื่น ๆ อื่น ๆ = (พนักงาน) อื่น ๆ // ทดสอบว่าฟิลด์ hava ระบุค่าส่งคืนชื่อ equals (อื่น ๆ ) && เงินเดือน == อื่น ๆ salary && hireday.equals (อื่น ๆ . hireday); } @Override public int hashCode () {return 7 * name.hashCode () + 11 * ใหม่สองเท่า (เงินเดือน) .HashCode () + 13 * hireday.hashCode (); } @Override สตริงสาธารณะ toString () {return getClass (). getName () + "[name =" + name + ", เงินเดือน =" + เงินเดือน + ", hireday =" + hireday + "]"; } ชื่อสตริงส่วนตัว; เงินเดือนสองเท่าส่วนตัว วันที่จ้างส่วนตัว } ผู้จัดการชั้นเรียนขยายพนักงาน {ผู้จัดการสาธารณะ (String n, Double S, Int Year, Int Month, Int Day) {super (n, s, ปี, เดือน, วัน, วัน); bouns = 0; } @Override สาธารณะ double getalary () {double basesalary = super.getSalary (); กลับ basesalary + bouns; } โมฆะสาธารณะ setBouns (double b) {bouns = b; } @Override บูลีนสาธารณะเท่ากับ (Object OtherObject) {ถ้า (! super.equals (otherObject)) ส่งคืน false; ผู้จัดการอื่น ๆ = (ผู้จัดการ) อื่น ๆ // super เท่ากับตรวจสอบว่าสิ่งนี้และอื่น ๆ อยู่ในคลาสเดียวกัน return bouns == อื่น ๆ bouns; } @Override public int hashCode () {return super.hashCode () + 17 * ใหม่ double (bouns) .hashCode (); } @Override สตริงสาธารณะ toString () {return super.toString () + "[bouns =" + bouns + "]"; } bouns คู่ส่วนตัว; - ลึกลงไปและแบ่งออกเป็น 2 หมวดหมู่ตาม "ชั้นเรียนจะแทนที่วิธี Equals ()"
(1) หากคลาสไม่ได้แทนที่เมธอดเท่ากับ () เมื่อเปรียบเทียบวัตถุสองชิ้นผ่านเท่ากับ () มันเป็นการเปรียบเทียบว่าวัตถุทั้งสองเป็นวัตถุเดียวกันหรือไม่ ในเวลานี้มันเทียบเท่ากับการเปรียบเทียบวัตถุทั้งสองนี้โดย "=="
(2) เราสามารถแทนที่วิธีการเท่ากับ () ของคลาสเพื่อให้เท่ากับ () เปรียบเทียบว่าวัตถุสองชิ้นมีค่าเท่ากันในรูปแบบอื่นหรือไม่ การปฏิบัติตามปกติคือ: หากเนื้อหาของวัตถุสองชิ้นมีค่าเท่ากันค่าเท่ากับ () จะกลับมาเป็นจริง มิฉะนั้นจะส่งคืน Fasle
ถัดไปให้เรายกตัวอย่างเพื่ออธิบายสองสถานการณ์ข้างต้น
1. กรณีของ "ไม่แทนที่เท่ากับ () วิธีการ"
รหัสมีดังนี้ (Equalstest1.java):
นำเข้า java.util.*; นำเข้า Java.lang.comparable;/*** @desc Equals () โปรแกรมทดสอบ */คลาสสาธารณะ Equalstest1 {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {// สร้างวัตถุบุคคลใหม่ 2 ชิ้นที่มีเนื้อหาเดียวกัน // ใช้เท่ากับเพื่อเปรียบเทียบว่าพวกเขาเป็นคนที่เท่าเทียมกัน p1 = บุคคลใหม่ ("eee", 100); บุคคล p2 = บุคคลใหม่ ("eee", 100); System.out.printf ("%s/n", p1.equals (p2)); } /*** @desc person class */ บุคคลชั้นเรียนแบบคงที่ส่วนตัว {อายุ int; ชื่อสตริง; บุคคลสาธารณะ (ชื่อสตริงอายุ int) {this.name = ชื่อ; this.age = อายุ; } Public String ToString () {return name + " -" + อายุ; - ผลการทำงาน:
คัดลอกรหัสดังนี้: เท็จ
การวิเคราะห์ผลลัพธ์เราใช้ P1.Equals (P2) เพื่อ "เปรียบเทียบว่า P1 และ P2 เท่ากัน" ในความเป็นจริงวิธี Equals () ของ Object.java เรียกว่านั่นคือ (P1 == P2) ที่เรียกว่า มันคือการเปรียบเทียบ "ไม่ว่าจะเป็น P1 และ P2 เป็นวัตถุเดียวกัน"
จากคำจำกัดความของ P1 และ P2 เราจะเห็นได้ว่าแม้ว่าเนื้อหาของพวกเขาจะเหมือนกัน แต่ก็เป็นวัตถุที่แตกต่างกันสองอย่าง! ดังนั้นผลการส่งคืนจึงเป็นเท็จ
2. สถานการณ์ของ "การเขียนทับเท่ากับ () วิธีการ"
เราแก้ไข Equalstest1.java ด้านบน: แทนที่เมธอด Equals ()
รหัสมีดังนี้ (Equalstest2.java):
นำเข้า java.util.*; นำเข้า Java.lang.comparable;/*** @desc Equals () โปรแกรมทดสอบ */คลาสสาธารณะ EqualStest2 {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {// สร้างวัตถุบุคคลใหม่ 2 ชิ้นที่มีเนื้อหาเดียวกัน // ใช้เท่ากับเพื่อเปรียบเทียบว่าพวกเขาเป็นคนที่เท่าเทียมกัน p1 = บุคคลใหม่ ("eee", 100); บุคคล p2 = บุคคลใหม่ ("eee", 100); System.out.printf ("%s/n", p1.equals (p2)); } /*** @desc person class */ บุคคลชั้นเรียนแบบคงที่ส่วนตัว {อายุ int; ชื่อสตริง; บุคคลสาธารณะ (ชื่อสตริงอายุ int) {this.name = ชื่อ; this.age = อายุ; } Public String ToString () {return name + " -" + อายุ; } / *** @DESC Override เท่ากับวิธี* / @Override บูลีนสาธารณะเท่ากับ (Object obj) {ถ้า (obj == null) {return false; } // ถ้าเป็นวัตถุเดียวกันให้ส่งคืนจริงมิฉะนั้นจะส่งคืนเท็จถ้า (นี้ == obj) {return true; } // ตัดสินว่าประเภทนั้นเหมือนกันถ้า (this.getClass ()! = obj.getClass ()) {return false; } บุคคลบุคคล = (บุคคล) obj; return name.equals (person.name) && age == person.age; - ผลการทำงาน:
คัดลอกรหัสดังนี้: จริง
การวิเคราะห์ผลลัพธ์:
เราแทนที่ฟังก์ชั่น Equals ของบุคคล () ใน Equalstest2.java: เมื่อชื่อและอายุของวัตถุสองคนมีค่าเท่ากันมันจะกลับมาเป็นจริง
ดังนั้นผลการเรียกใช้จะส่งกลับจริง
ต้องบอกว่ามาพูดคุยเกี่ยวกับข้อกำหนดของ Java สำหรับ Equals () มีประเด็นต่อไปนี้:
สมมาตร: ถ้า x.equals (y) ส่งคืน "จริง" ดังนั้น y.equals (x) ควรกลับ "จริง" ด้วย
Reflectivity: x.equals (x) ต้องกลับ "จริง"
การเปรียบเทียบ: ถ้า x.equals (y) ส่งคืน "true" และ y.equals (z) ส่งคืน "true" ดังนั้น z.equals (x) ควรกลับ "true" ด้วย
ความสอดคล้อง: ถ้า x.equals (y) ส่งคืน "จริง" ตราบใดที่เนื้อหาของ x และ y ยังคงไม่เปลี่ยนแปลงไม่ว่าคุณจะทำซ้ำ x.equals (y) กี่ครั้งการกลับมาจะเป็น "จริง"
ไม่ว่างเปล่า x.equals (null) มักจะส่งคืน "เท็จ" เสมอ; x.equals (วัตถุประเภทต่าง ๆ และ x) จะส่งคืน "เท็จ" เสมอ
ตอนนี้ลองทบทวนบทบาทของ Equals (): พิจารณาว่าวัตถุสองชิ้นมีค่าเท่ากันหรือไม่ เมื่อเราเขียนใหม่เท่ากับ () มันเป็นไปไม่ได้ที่จะเปลี่ยนฟังก์ชั่นของมัน!
ความแตกต่างระหว่าง Equals () และ == คืออะไร?
==: ฟังก์ชั่นของมันคือการพิจารณาว่าที่อยู่ของวัตถุสองชิ้นมีค่าเท่ากันหรือไม่ นั่นคือตรวจสอบว่าวัตถุทั้งสองเป็นวัตถุเดียวกันหรือไม่
Equals (): ฟังก์ชั่นของมันคือการตรวจสอบว่าวัตถุสองชิ้นมีค่าเท่ากันหรือไม่ อย่างไรก็ตามโดยทั่วไปมีเงื่อนไขการใช้งานสองเงื่อนไข (มีการอธิบายในรายละเอียดในส่วนก่อนหน้า 1):
กรณีที่ 1 ชั้นเรียนไม่ได้แทนที่วิธีการเท่ากับ () จากนั้นเมื่อเปรียบเทียบวัตถุสองชิ้นของคลาสนี้ถึง Equals () มันจะเทียบเท่ากับการเปรียบเทียบวัตถุทั้งสองนี้โดย "=="
กรณีที่ 2 ชั้นเรียนจะแทนที่เมธอดเท่ากับ () โดยทั่วไปเราแทนที่วิธี Equals () เพื่อสร้างเนื้อหาของวัตถุสองชิ้นเท่ากัน หากเนื้อหาของพวกเขาเท่ากันมันจะส่งคืนจริง (นั่นคือวัตถุทั้งสองถือว่าเท่ากัน)
ด้านล่างเปรียบเทียบความแตกต่างของพวกเขาโดยตัวอย่าง
รหัสมีดังนี้:
นำเข้า java.util.*; นำเข้า Java.lang.comparable;/*** @desc Equals () โปรแกรมทดสอบ */คลาสสาธารณะ EqualStest3 {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {// สร้างวัตถุบุคคลใหม่ 2 ชิ้นที่มีเนื้อหาเดียวกัน // ใช้เท่ากับเพื่อเปรียบเทียบว่าพวกเขาเป็นคนที่เท่าเทียมกัน p1 = บุคคลใหม่ ("eee", 100); บุคคล p2 = บุคคลใหม่ ("eee", 100); System.out.printf ("p1.equals (P2): %s/n", p1.equals (P2)); System.out.printf ("P1 == P2: %S/N", P1 == P2); } /*** @desc person class */ บุคคลชั้นเรียนแบบคงที่ส่วนตัว {อายุ int; ชื่อสตริง; บุคคลสาธารณะ (ชื่อสตริงอายุ int) {this.name = ชื่อ; this.age = อายุ; } Public String ToString () {return name + " -" + อายุ; } / *** @DESC Override เท่ากับวิธี* / @Override บูลีนสาธารณะเท่ากับ (Object obj) {ถ้า (obj == null) {return false; } // ถ้าเป็นวัตถุเดียวกันให้ส่งคืนจริงมิฉะนั้นจะส่งคืนเท็จถ้า (นี้ == obj) {return true; } // ตัดสินว่าประเภทนั้นเหมือนกันถ้า (this.getClass ()! = obj.getClass ()) {return false; } บุคคลบุคคล = (บุคคล) obj; return name.equals (person.name) && age == person.age; - ผลการทำงาน:
p1.equals (p2): truep1 == p2: false
การวิเคราะห์ผลลัพธ์:
ใน Equalstest3.java:
(1) P1.Equals (P2)
นี่คือการพิจารณาว่าเนื้อหาของ P1 และ P2 เท่ากันหรือไม่ เนื่องจากบุคคลแทนที่วิธี Equals () และนี้ Equals () นี้ใช้เพื่อตรวจสอบว่าเนื้อหาของ P1 และ P2 มีค่าเท่ากันเนื้อหาของ P1 และ P2 นั้นเท่ากันหรือไม่ ดังนั้นกลับมาเป็นจริง
(2) P1 == P2
นี่คือการพิจารณาว่า P1 และ P2 เป็นวัตถุเดียวกันหรือไม่ เนื่องจากพวกเขาเป็นคนใหม่สองคน ดังนั้นกลับมาเป็นเท็จ