ওভাররাইড করার সময় কোন বিষয়গুলি / সমস্যাগুলি অবশ্যই বিবেচনা করা উচিত equals
এবং hashCode
?
ওভাররাইড করার সময় কোন বিষয়গুলি / সমস্যাগুলি অবশ্যই বিবেচনা করা উচিত equals
এবং hashCode
?
উত্তর:
equals()
( Javadoc ) একজন সমানতা সম্পর্ক সংজ্ঞায়িত করতে হবে (এটা হতে হবে আত্মবাচক , প্রতিসম এবং সকর্মক )। তদ্ব্যতীত, এটি অবশ্যই সামঞ্জস্যপূর্ণ হতে হবে (যদি বস্তুগুলি সংশোধন না করা হয় তবে অবশ্যই এটির একই মানটি ফেরত যেতে হবে)। তদ্ব্যতীত, o.equals(null)
সর্বদা মিথ্যা ফিরে আসতে হবে।
hashCode()
( জাভাদোক ) অবশ্যই সামঞ্জস্যপূর্ণ হতে হবে (যদি পদটিকে শর্তে পরিবর্তিত না করা হয় তবে equals()
এটি অবশ্যই একই মানটি ফেরত রাখতে হবে)।
সম্পর্ক দুটি পদ্ধতির মধ্যে হল:
যখনই
a.equals(b)
, তখনa.hashCode()
অবশ্যই একই হতে হবেb.hashCode()
।
আপনি যদি একটিটিকে ওভাররাইড করে থাকেন তবে আপনার অন্যটিকে ওভাররাইড করা উচিত।
আপনি ক্ষেত্রগুলির একই সেট ব্যবহার করুন যা আপনি গণনা equals()
করতে ব্যবহার করেন hashCode()
।
অ্যাপাচি কমন্স ল্যাং লাইব্রেরি থেকে ইকুয়ালস বিল্ডার এবং হ্যাশকোডবিল্ডার দুর্দান্ত সহায়ক ক্লাসগুলি ব্যবহার করুন । একটি উদাহরণ:
public class Person {
private String name;
private int age;
// ...
@Override
public int hashCode() {
return new HashCodeBuilder(17, 31). // two randomly chosen prime numbers
// if deriving: appendSuper(super.hashCode()).
append(name).
append(age).
toHashCode();
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Person))
return false;
if (obj == this)
return true;
Person rhs = (Person) obj;
return new EqualsBuilder().
// if deriving: appendSuper(super.equals(obj)).
append(name, rhs.name).
append(age, rhs.age).
isEquals();
}
}
যখন ব্যবহার করে একটি হ্যাশ ভিত্তিক সংগ্রহ বা ম্যাপ যেমন HashSet , LinkedHashSet , HashMap , hashtable , অথবা WeakHashMap , নিশ্চিত করুন যে হ্যাশকোড () কী বস্তুর যে আপনার সংগ্রহে মধ্যে কখনোই করা যখন বস্তুর সংগ্রহে রয়েছে পরিবর্তন করুন। এটি নিশ্চিত করার বুলেটপ্রুফ উপায়টি হ'ল আপনার কীগুলি অপরিবর্তনীয় করে তোলা, এতে অন্যান্য সুবিধাও রয়েছে ।
instanceof
যদি প্রথম অপারেন্ডটি নাল হয় তবে মিথ্যা ফেরত দেওয়ার পরে প্রথম নাল চেকের প্রয়োজন নেই (কার্যকর জাভা আবার)।
হাইবারনেটের মতো অবজেক্ট-রিলেশনশিপ ম্যাপার (ওআরএম) ব্যবহার করে অবিচ্ছিন্ন ক্লাসগুলির সাথে যদি আপনি আচরণ করছেন এমনটি বিবেচনা করার মতো কিছু বিষয় রয়েছে, যদি আপনি ভাবেন না যে এটি ইতিমধ্যে অযৌক্তিকভাবে জটিল ছিল!
অলস বোঝা বস্তুগুলি সাবক্লাস হয়
যদি আপনার অবজেক্টগুলি একটি ওআরএম ব্যবহার করে অবিচল থাকে, তবে অনেক ক্ষেত্রে ডেটা স্টোর থেকে খুব তাড়াতাড়ি বস্তু লোড করা এড়াতে আপনি গতিশীল প্রক্সিগুলির সাথে ডিল করবেন। এই প্রক্সিগুলি আপনার নিজের শ্রেণীর সাবক্লাস হিসাবে প্রয়োগ করা হয়েছে। এর অর্থ this.getClass() == o.getClass()
ফিরে আসবে false
। উদাহরণ স্বরূপ:
Person saved = new Person("John Doe");
Long key = dao.save(saved);
dao.flush();
Person retrieved = dao.retrieve(key);
saved.getClass().equals(retrieved.getClass()); // Will return false if Person is loaded lazy
আপনি যদি কোনও ওআরএম নিয়ে কাজ করছেন তবে ব্যবহার করা o instanceof Person
হ'ল একমাত্র জিনিস যা সঠিকভাবে আচরণ করবে।
অলস বোঝা বস্তুর নালার ক্ষেত্র রয়েছে
ওআরএমগুলি সাধারণত অলস বোঝা বস্তুগুলির লোড করার জন্য জেটরগুলি ব্যবহার করে। এর অর্থ এই যে person.name
হতে হবে null
যদি person
, অলস লোড হয় এমনকি যদি person.getName()
বাহিনী লোড হচ্ছে এবং আয় "জন ডো"। আমার অভিজ্ঞতায়, এই ফসলগুলি প্রায়শই বেশি হয় hashCode()
এবং equals()
।
আপনি যদি একটি ORM সাথে এসেছেন অধিনস্ত, সবসময় getters, এবং কখনও ক্ষেত্র রেফারেন্স ব্যবহার নিশ্চিত করতে hashCode()
এবং equals()
।
কোনও বস্তু সংরক্ষণ করা তার অবস্থার পরিবর্তন করবে
অবিচ্ছিন্ন অবজেক্টগুলি প্রায়শই কোনও id
ক্ষেত্র অবজেক্টের কী ধরে রাখে। এই ক্ষেত্রটি স্বয়ংক্রিয়ভাবে আপডেট হবে যখন কোনও অবজেক্টটি প্রথম সংরক্ষণ করা হবে। মধ্যে একটি আইডি ক্ষেত্র ব্যবহার করবেন না hashCode()
। তবে আপনি এটি ব্যবহার করতে পারেন equals()
।
একটি প্যাটার্ন যা আমি প্রায়শই ব্যবহার করি is
if (this.getId() == null) {
return this == other;
}
else {
return this.getId().equals(other.getId());
}
কিন্তু: আপনি অন্তর্ভুক্ত থাকতে পারে না getId()
যে hashCode()
। আপনি যদি করেন, যখন কোনও বস্তু স্থির থাকে, তখন তার hashCode
পরিবর্তন ঘটে। যদি বস্তুটি একটিতে থাকে তবে আপনি HashSet
এটি আর "কখনই খুঁজে পাবেন না"।
আমার Person
উদাহরণে, আমি সম্ভবত এর getName()
জন্য hashCode
এবং getId()
আরও getName()
(কেবলমাত্র প্যারানাইয়ার জন্য) ব্যবহার করব equals()
। যদি "সংঘর্ষ" হওয়ার কিছু ঝুঁকি থাকে hashCode()
তবে তা ঠিক আছে, তবে কখনই ঠিক হবে না equals()
।
hashCode()
থেকে বৈশিষ্ট্যের অ-পরিবর্তনশীল সাবসেট ব্যবহার করা উচিত equals()
Saving an object will change it's state
! hashCode
অবশ্যই ফিরে আসবেন int
, তাহলে আপনি কীভাবে ব্যবহার করবেন getName()
? আপনি কি এর জন্য একটি উদাহরণ দিতে পারেনhashCode
সম্পর্কে একটি ব্যাখ্যা obj.getClass() != getClass()
।
এই বিবৃতিটি equals()
বন্ধুত্বপূর্ণভাবে উত্তরাধিকারী হওয়ার ফলাফল । জেএলএস (জাভা ভাষার স্পেসিফিকেশন) নির্দিষ্ট করে যে যদি A.equals(B) == true
তা হলে B.equals(A)
আবারও ফিরে আসতে হবে true
। যদি আপনি সেই বিবৃতিটি উত্তরাধিকার সূত্রে ক্লাস করে যেগুলি ওভাররাইড করে equals()
(এবং এর আচরণ পরিবর্তন করে) এই স্পেসিফিকেশনটি ভেঙে দেয়।
বিবৃতি বাদ দিলে কী ঘটে যায় তার নিম্নলিখিত উদাহরণটি বিবেচনা করুন:
class A {
int field1;
A(int field1) {
this.field1 = field1;
}
public boolean equals(Object other) {
return (other != null && other instanceof A && ((A) other).field1 == field1);
}
}
class B extends A {
int field2;
B(int field1, int field2) {
super(field1);
this.field2 = field2;
}
public boolean equals(Object other) {
return (other != null && other instanceof B && ((B)other).field2 == field2 && super.equals(other));
}
}
এরকম new A(1).equals(new A(1))
এছাড়াও, new B(1,1).equals(new B(1,1))
সত্য খুঁজে দিতে, যেমন এটি করা উচিত স্থাপিত।
এটি দেখতে খুব সুন্দর দেখাচ্ছে, তবে দেখুন যদি আমরা উভয় শ্রেণি ব্যবহারের চেষ্টা করি তবে কী ঘটে:
A a = new A(1);
B b = new B(1,1);
a.equals(b) == true;
b.equals(a) == false;
অবশ্যই, এটি ভুল।
যদি আপনি প্রতিসামগ্রিক অবস্থা নিশ্চিত করতে চান। a = b if b = a এবং লিসকোভ প্রতিস্থাপনের নীতি super.equals(other)
কেবল B
উদাহরণের ক্ষেত্রে নয়, উদাহরণস্বরূপ চেক করুন A
:
if (other instanceof B )
return (other != null && ((B)other).field2 == field2 && super.equals(other));
if (other instanceof A) return super.equals(other);
else return false;
যা আউটপুট দেবে:
a.equals(b) == true;
b.equals(a) == true;
যেখানে, যদি এটির a
কোনও রেফারেন্স না হয় B
, তবে এটি ক্লাসের একটি রেফারেন্স হতে পারে A
(কারণ আপনি এটি প্রসারিত করেন), এক্ষেত্রে super.equals()
আপনিও কল করেন ।
ThingWithOptionSetA
সমান হতে পারে Thing
যে সমস্ত অতিরিক্ত বিকল্পের ডিফল্ট মান রয়েছে এবং একইভাবে একটি এর জন্য ThingWithOptionSetB
, তবে উভয় অবজেক্টের সমস্ত বেস-ভিত্তিক বৈশিষ্ট্যগুলি তাদের ডিফল্টগুলির সাথে মিলে গেলে কেবল ThingWithOptionSetA
একটির সমান তুলনা করা সম্ভব হবে ThingWithOptionSetB
তবে আমি দেখতে পাচ্ছি না যে আপনি এটির জন্য কীভাবে পরীক্ষা করছেন।
B b2 = new B(1,99)
তারপর, b.equals(a) == true
এবং a.equals(b2) == true
কিন্তু b.equals(b2) == false
।
উত্তরাধিকার-বান্ধব প্রয়োগের জন্য, তাল কোহেনের সমাধানটি দেখুন, আমি কীভাবে সমান () পদ্ধতিটি সঠিকভাবে প্রয়োগ করব?
সারসংক্ষেপ:
ইফেক্টিভ জাভা প্রোগ্রামিং ল্যাঙ্গুয়েজ গাইড (অ্যাডিসন-ওয়েসলি, ২০০১) বইয়ে জোশুয়া ব্লচ দাবি করেছেন যে "সমান চুক্তি রক্ষার জন্য অস্থায়ী শ্রেণি বাড়াতে এবং কোনও দিক যুক্ত করার সহজ উপায় নেই।" তাল একমত না।
তার সমাধানটি হ'ল অন্য সংখ্যক অন্ধভাবেই কোয়েস্টস () উভয় উপায়ে কল করে সমান () প্রয়োগ করা। অন্ধভাবেইকুয়ালস () উপক্লাস দ্বারা ওভাররাইড করা হয়, সমান () উত্তরাধিকার সূত্রে প্রাপ্ত হয়, এবং কখনই ওভাররাইড হয় না।
উদাহরণ:
class Point {
private int x;
private int y;
protected boolean blindlyEquals(Object o) {
if (!(o instanceof Point))
return false;
Point p = (Point)o;
return (p.x == this.x && p.y == this.y);
}
public boolean equals(Object o) {
return (this.blindlyEquals(o) && o.blindlyEquals(this));
}
}
class ColorPoint extends Point {
private Color c;
protected boolean blindlyEquals(Object o) {
if (!(o instanceof ColorPoint))
return false;
ColorPoint cp = (ColorPoint)o;
return (super.blindlyEquals(cp) &&
cp.color == this.color);
}
}
নোট করুন যে লিসকভ সাবস্টিটিউশন নীতিটি সন্তুষ্ট করতে হলে সমান () অবশ্যই উত্তরাধিকারের স্তরক্রম জুড়ে কাজ করতে হবে।
if (this.getClass() != o.getClass()) return false
তবে নমনীয় যে এটি কেবলমাত্র মিথ্যা ফেরত দেয় যদি উত্পন্ন শ্রেণি (এস) সমান পরিবর্তন করতে বিরক্ত করে। এটা কি সঠিক?
এখনও অবাক হয়ে যায় যে কেউ এর জন্য পেয়ারা গ্রন্থাগারের সুপারিশ করেনি।
//Sample taken from a current working project of mine just to illustrate the idea
@Override
public int hashCode(){
return Objects.hashCode(this.getDate(), this.datePattern);
}
@Override
public boolean equals(Object obj){
if ( ! obj instanceof DateAndPattern ) {
return false;
}
return Objects.equal(((DateAndPattern)obj).getDate(), this.getDate())
&& Objects.equal(((DateAndPattern)obj).getDate(), this.getDatePattern());
}
this
মধ্যে this.getDate()
উপায়ে কিছুই (গোলমাল ছাড়া)
if (!(otherObject instanceof DateAndPattern)) {
। হেনান এবং স্টিভ কুও (যদিও এটি ব্যক্তিগত পছন্দের বিষয়) এর সাথে সম্মত হন তবে তা তবে +1 করুন।
সুপার ক্লাসে জাভা.লং.অবজেক্ট হিসাবে দুটি পদ্ধতি রয়েছে। আমাদের সেগুলি কাস্টম অবজেক্টে ওভাররাইড করা দরকার।
public boolean equals(Object obj)
public int hashCode()
সমান অবজেক্টগুলিকে অবশ্যই একই হ্যাশ কোড তৈরি করা উচিত যতক্ষণ না তারা সমান হয় তবে অসম বস্তুগুলিতে স্বতন্ত্র হ্যাশ কোড তৈরি করার প্রয়োজন হয় না।
public class Test
{
private int num;
private String data;
public boolean equals(Object obj)
{
if(this == obj)
return true;
if((obj == null) || (obj.getClass() != this.getClass()))
return false;
// object must be Test at this point
Test test = (Test)obj;
return num == test.num &&
(data == test.data || (data != null && data.equals(test.data)));
}
public int hashCode()
{
int hash = 7;
hash = 31 * hash + num;
hash = 31 * hash + (null == data ? 0 : data.hashCode());
return hash;
}
// other methods
}
আপনি যদি আরও কিছু পেতে চান তবে দয়া করে এই লিঙ্কটি http://www.javaranch.com/j Journal/2002/10/ equalhash.html হিসাবে চেক করুন
এটি অন্য একটি উদাহরণ, http://java67.blogspot.com/2013/04/example-of-overriding-equals-hashcode-compareTo-java-method.html
আনন্দ কর! @। @
সদস্যের সাম্যতা যাচাই করার আগে শ্রেণি সমতার জন্য আপনার চেক করার কয়েকটি উপায় রয়েছে এবং আমি মনে করি উভয়ই সঠিক পরিস্থিতিতে কার্যকর।
instanceof
অপারেটরটি ব্যবহার করুন ।this.getClass().equals(that.getClass())
।আমি final
সমান রূপায়ণে # 1 ব্যবহার করি বা এমন একটি ইন্টারফেস প্রয়োগ করি যা সমান জন্য একটি অ্যালগরিদম নির্ধারণ করে (যেমন java.util
সংগ্রহের ইন্টারফেসগুলি — যেমন (obj instanceof Set)
আপনি প্রয়োগ করছেন এমন ইন্টারফেসের সাথে যাচাই করার সঠিক উপায় )। সমতুল্য যখন ওভাররাইড করা যায় তখন এটি সাধারণত একটি খারাপ পছন্দ কারণ এটি প্রতিসাম্য সম্পত্তিকে ভেঙে দেয়।
# 2 বিকল্পটি সমান ওভারাইডিং বা প্রতিসাম্যতা ভঙ্গ না করে ক্লাসটিকে নিরাপদে প্রসারিত করতে দেয়।
আপনার ক্লাসটি যদি হয় Comparable
তবে equals
এবং compareTo
পদ্ধতিগুলিও সামঞ্জস্যপূর্ণ হওয়া উচিত। এখানে একটি Comparable
শ্রেণিতে সমান পদ্ধতির জন্য একটি টেম্পলেট রয়েছে :
final class MyClass implements Comparable<MyClass>
{
…
@Override
public boolean equals(Object obj)
{
/* If compareTo and equals aren't final, we should check with getClass instead. */
if (!(obj instanceof MyClass))
return false;
return compareTo((MyClass) obj) == 0;
}
}
final
এবং compareTo()
পদ্ধতিটি বাছাইয়ের ক্রমটিকে বিপরীত করার জন্য ওভাররাইড করা হয় তবে সাবক্লাস এবং সুপারক্লাসের উদাহরণগুলি সমান হিসাবে বিবেচনা করা উচিত নয়। যখন এই বস্তুগুলি গাছের সাথে একত্রে ব্যবহৃত হত, তখন একটি instanceof
প্রয়োগ অনুসারে "সমান" কীগুলি খুঁজে পাওয়া যায় না।
সমান জন্য, দেখব সমান অফ সিক্রেটস দ্বারা Angelika ল্যাঙ্গার । আমি এটা খুব ভালবাসি. তিনি জাভা জেনেরিক্স সম্পর্কে দুর্দান্ত জিজ্ঞাসিত প্রশ্ন । তার অন্যান্য নিবন্ধগুলি এখানে দেখুন ("কোর জাভাতে" স্ক্রোল করুন), যেখানে তিনি পার্ট -২ এবং "মিশ্র প্রকারের তুলনা" নিয়েও চলেছেন। তাদের পড়তে মজা করুন!
সমান () পদ্ধতি দুটি বস্তুর সাম্য নির্ধারণ করতে ব্যবহৃত হয়।
10 এর int মান সর্বদা 10 এর সমান হয় তবে এই সমান () পদ্ধতিটি দুটি বস্তুর সমতা সম্পর্কে। যখন আমরা বস্তু বলি, এর বৈশিষ্ট্য থাকবে। সমতা সম্পর্কে সিদ্ধান্ত নিতে সেই বৈশিষ্ট্যগুলি বিবেচনা করা হয়। সমতা নির্ধারণের জন্য সমস্ত সম্পত্তি বিবেচনায় নিতে হবে এবং শ্রেণি সংজ্ঞা এবং প্রসঙ্গে শ্রদ্ধার সাথে এটি সিদ্ধান্ত নেওয়া যেতে পারে তা প্রয়োজনীয় নয়। তারপরে সমান () পদ্ধতিটি ওভাররাইড করা যায়।
আমাদের যখনই সমান () পদ্ধতির ওভাররাইড হয় তখন আমাদের হ্যাশকোড () পদ্ধতিটি সর্বদা ওভাররাইড করা উচিত। তা না হলে কী হবে? আমরা যদি আমাদের অ্যাপ্লিকেশনটিতে হ্যাশ টেবিল ব্যবহার করি তবে এটি আশানুরূপ আচরণ করবে না। যেহেতু হ্যাশকোড সঞ্চিত মানগুলির সাম্যতা নির্ধারণে ব্যবহৃত হয়, এটি কোনও চাবির জন্য সঠিক আনুষঙ্গিক মান প্রদান করে না।
প্রদত্ত ডিফল্ট বাস্তবায়ন হ্যাজকোড () পদ্ধতি অবজেক্ট শ্রেণিতে অবজেক্টের অভ্যন্তরীণ ঠিকানা ব্যবহার করে এবং এটি পূর্ণসংখ্যায় রূপান্তরিত করে এবং ফেরত দেয়।
public class Tiger {
private String color;
private String stripePattern;
private int height;
@Override
public boolean equals(Object object) {
boolean result = false;
if (object == null || object.getClass() != getClass()) {
result = false;
} else {
Tiger tiger = (Tiger) object;
if (this.color == tiger.getColor()
&& this.stripePattern == tiger.getStripePattern()) {
result = true;
}
}
return result;
}
// just omitted null checks
@Override
public int hashCode() {
int hash = 3;
hash = 7 * hash + this.color.hashCode();
hash = 7 * hash + this.stripePattern.hashCode();
return hash;
}
public static void main(String args[]) {
Tiger bengalTiger1 = new Tiger("Yellow", "Dense", 3);
Tiger bengalTiger2 = new Tiger("Yellow", "Dense", 2);
Tiger siberianTiger = new Tiger("White", "Sparse", 4);
System.out.println("bengalTiger1 and bengalTiger2: "
+ bengalTiger1.equals(bengalTiger2));
System.out.println("bengalTiger1 and siberianTiger: "
+ bengalTiger1.equals(siberianTiger));
System.out.println("bengalTiger1 hashCode: " + bengalTiger1.hashCode());
System.out.println("bengalTiger2 hashCode: " + bengalTiger2.hashCode());
System.out.println("siberianTiger hashCode: "
+ siberianTiger.hashCode());
}
public String getColor() {
return color;
}
public String getStripePattern() {
return stripePattern;
}
public Tiger(String color, String stripePattern, int height) {
this.color = color;
this.stripePattern = stripePattern;
this.height = height;
}
}
কোড আউটপুট উদাহরণ:
bengalTiger1 and bengalTiger2: true
bengalTiger1 and siberianTiger: false
bengalTiger1 hashCode: 1398212510
bengalTiger2 hashCode: 1398212510
siberianTiger hashCode: –1227465966
আমি খুঁজে পেয়েছি যে একটি দুটি জিনিস দুটি একে অপরের সাথে রেফারেন্স ধারণ করে (একটি উদাহরণ পিতা-মাতার সাথে সমস্ত সন্তানের প্রাপ্তির জন্য সুবিধার পদ্ধতির সাথে সন্তানের সম্পর্ক)।
উদাহরণস্বরূপ হাইবারনেট ম্যাপিংগুলি করার সময় এই ধরণের জিনিসগুলি মোটামুটি সাধারণ।
আপনি যদি আপনার হ্যাশকোডের সম্পর্কের উভয় প্রান্তকে অন্তর্ভুক্ত করেন বা পরীক্ষার সমান হয় তবে এটি পুনরাবৃত্ত লুপে প্রবেশ করা সম্ভব যা স্ট্যাকওভারফ্লো এক্সপেশনে শেষ হয়।
সহজ সমাধানটি পদ্ধতিগুলিতে getChildren সংগ্রহকে অন্তর্ভুক্ত না করা।
equals()
। যদি কোনও পাগল বিজ্ঞানী আমার একটি সদৃশ তৈরি করে তবে আমরা সমান হতে পারি। তবে আমাদের একই পিতা থাকতেন না।