कोई जावा वर्ग को अपरिवर्तनीय कैसे बना सकता है, अपरिवर्तनीयता की क्या आवश्यकता है और क्या इसका उपयोग करने का कोई फायदा है?
@Immutable
एनोटेशन की जाँच jcabi-पहलुओं
कोई जावा वर्ग को अपरिवर्तनीय कैसे बना सकता है, अपरिवर्तनीयता की क्या आवश्यकता है और क्या इसका उपयोग करने का कोई फायदा है?
@Immutable
एनोटेशन की जाँच jcabi-पहलुओं
जवाबों:
अपरिवर्तनीय वस्तु क्या है?
एक अपरिवर्तनीय वस्तु वह है जो राज्य के तुरंत बाद बदल नहीं जाएगी।
किसी वस्तु को अपरिवर्तनीय कैसे बनाया जाए?
सामान्य तौर पर, एक अपरिवर्तनीय वस्तु को एक वर्ग को परिभाषित करके बनाया जा सकता है, जिसमें उसके किसी भी सदस्य को उजागर नहीं किया जाता है, और उसके पास कोई भी निवासी नहीं होता है।
निम्न वर्ग एक अपरिवर्तनीय वस्तु का निर्माण करेगा:
class ImmutableInt {
private final int value;
public ImmutableInt(int i) {
value = i;
}
public int getValue() {
return value;
}
}
जैसा कि उपर्युक्त उदाहरण में देखा जा सकता है, ImmutableInt
वस्तु का तात्कालिकता होने पर ही मूल्य निर्धारित किया जा सकता है, और केवल एक गेटर ( getValue
) होने से वस्तु की स्थिति को तात्कालिकता के बाद नहीं बदला जा सकता है।
हालाँकि, इस बात का ध्यान रखा जाना चाहिए कि ऑब्जेक्ट द्वारा संदर्भित सभी ऑब्जेक्ट अपरिवर्तनीय होने चाहिए, या ऑब्जेक्ट की स्थिति को बदलना संभव हो सकता है।
उदाहरण के लिए, किसी ऐरे के संदर्भ को देखने या ArrayList
एक गॉटर के माध्यम से प्राप्त करने की अनुमति देकर आंतरिक स्थिति को ऐरे या संग्रह को बदलकर बदलने की अनुमति होगी:
class NotQuiteImmutableList<T> {
private final List<T> list;
public NotQuiteImmutableList(List<T> list) {
// creates a new ArrayList and keeps a reference to it.
this.list = new ArrayList(list);
}
public List<T> getList() {
return list;
}
}
उपरोक्त कोड के साथ समस्या यह है कि इसके ArrayList
माध्यम से प्राप्त किया जा सकता है getList
और हेरफेर किया जा सकता है, जिससे वस्तु की स्थिति में ही परिवर्तन हो जाएगा, इसलिए अपरिवर्तनीय नहीं है।
// notQuiteImmutableList contains "a", "b", "c"
List<String> notQuiteImmutableList= new NotQuiteImmutableList(Arrays.asList("a", "b", "c"));
// now the list contains "a", "b", "c", "d" -- this list is mutable.
notQuiteImmutableList.getList().add("d");
इस समस्या को हल करने का एक तरीका यह है कि एक सरणी या संग्रह की एक प्रति वापस लौटा दी जाए जब एक गेट से बुलाया जाए:
public List<T> getList() {
// return a copy of the list so the internal state cannot be altered
return new ArrayList(list);
}
अपरिवर्तनीयता का लाभ क्या है?
अपरिवर्तनीयता का लाभ संगामिति के साथ आता है। उत्परिवर्तनीय वस्तुओं में शुद्धता बनाए रखना मुश्किल है, क्योंकि कई धागे एक ही वस्तु की स्थिति को बदलने की कोशिश कर सकते हैं, जिससे कुछ धागे एक ही वस्तु की एक अलग स्थिति को देखते हैं, जो कि रीड्स के समय और उक्त पर निर्भर करता है। वस्तु।
एक अपरिवर्तनीय वस्तु होने से, कोई यह सुनिश्चित कर सकता है कि वस्तु को देखने वाले सभी धागे उसी स्थिति को देख रहे होंगे, क्योंकि अपरिवर्तनीय वस्तु की स्थिति नहीं बदलेगी।
return Collections.unmodifiableList(list);
सूची पर केवल पढ़ने के लिए एक दृश्य लौटा सकते हैं ।
final
भी बनानी पड़ती है। अन्यथा इसे एक सेटर विधि (या अन्य प्रकार के उत्परिवर्तन विधियों और परस्पर क्षेत्रों) के साथ बढ़ाया जा सकता है।
final
यदि वर्ग के पास केवल private
फ़ील्ड हैं क्योंकि उन्हें उपवर्गों से एक्सेस नहीं किया जा सकता है।
पहले से दिए गए उत्तरों के अलावा, मैं प्रभावी जावा, 2 डी एड में अपरिवर्तनीयता के बारे में पढ़ने की सलाह दूंगा, क्योंकि कुछ विवरण हैं जो याद करने में आसान हैं (जैसे रक्षात्मक प्रतियां)। साथ ही, प्रभावी जावा 2 एड। हर जावा डेवलपर के लिए अवश्य पढ़ें।
आप इस तरह एक वर्ग को अपरिवर्तनीय बनाते हैं:
public final class Immutable
{
private final String name;
public Immutable(String name)
{
this.name = name;
}
public String getName() { return this.name; }
// No setter;
}
जावा वर्ग को अपरिवर्तनीय बनाने के लिए निम्नलिखित आवश्यकताएं हैं:
final
(ताकि बाल कक्षाएं नहीं बनाई जा सकें)final
(ताकि हम ऑब्जेक्ट निर्माण के बाद इसका मूल्य नहीं बदल सकें)अपरिवर्तनीय कक्षाएं उपयोगी हैं क्योंकि
- वे थ्रेड-सुरक्षित हैं।
- वे आपके डिजाइन के बारे में कुछ गहरा भी व्यक्त करते हैं: "इसे बदल नहीं सकते।", जब यह लागू होता है, तो यह वही है जो आपको चाहिए।
मुख्य रूप से दो तरह से अपरिवर्तनीयता प्राप्त की जा सकती है
final
पुनर्मूल्यांकन से बचने के लिए उदाहरण विशेषताओं का उपयोग करनाअपरिहार्यता के लाभ ऐसी धारणाएं हैं जिन्हें आप इन वस्तुओं पर बना सकते हैं:
अपरिवर्तनीय वर्ग इसे तुरंत मानने के बाद मूल्यों को पुन: असाइन नहीं कर सकते। निर्माणकर्ता अपने निजी चर को मान प्रदान करता है। जब तक ऑब्जेक्ट अशक्त नहीं हो जाता है, तब तक सेटर विधियों की अनुपलब्धता के कारण मूल्यों को नहीं बदला जा सकता है।
अचल होने के लिए निम्नलिखित को पूरा करना चाहिए,
/**
* Strong immutability - by making class final
*/
public final class TestImmutablity {
// make the variables private
private String Name;
//assign value when the object created
public TestImmutablity(String name) {
this.Name = name;
}
//provide getters to access values
public String getName() {
return this.Name;
}
}
Advanteges: अपरिवर्तनीय वस्तुओं में मृत्यु होने तक इसके आरंभिक मूल्य होते हैं।
अपरिवर्तनीय वर्ग वे हैं जिनकी वस्तुओं को निर्माण के बाद नहीं बदला जा सकता है।
अपरिवर्तनीय वर्ग के लिए उपयोगी है
उदाहरण
स्ट्रिंग क्लास
कोड उदाहरण
public final class Student {
private final String name;
private final String rollNumber;
public Student(String name, String rollNumber) {
this.name = name;
this.rollNumber = rollNumber;
}
public String getName() {
return this.name;
}
public String getRollNumber() {
return this.rollNumber;
}
}
एक जावा वर्ग को अपरिवर्तनीय कैसे बनाया जा सकता है?
JDK 14+ से जिसमें JEP 359 है , हम " records
" का उपयोग कर सकते हैं । यह इम्यूटेबल क्लास बनाने का सबसे सरल और ऊधम मुक्त तरीका है।
एक रिकॉर्ड क्लास एक उथली अपरिवर्तनीय , पारदर्शी वाहक है जिसे रिकॉर्ड के रूप में जाना जाता है फ़ील्ड के एक निश्चित सेट के लिए जो रिकॉर्ड के लिए विवरण components
प्रदान करता है state
। प्रत्येक component
एक final
फ़ील्ड को जन्म देता है जो प्रदान किए गए मूल्य और मूल्य accessor
को पुनः प्राप्त करने का एक तरीका रखता है । फ़ील्ड नाम और एक्सेसर नाम घटक के नाम से मेल खाते हैं।
आइए एक अपरिवर्तनीय आयत बनाने के उदाहरण पर विचार करें
record Rectangle(double length, double width) {}
किसी भी निर्माता को घोषित करने की आवश्यकता नहीं है, समान और हैशकोड विधियों को लागू करने की आवश्यकता नहीं है। बस किसी भी रिकॉर्ड के लिए नाम और राज्य का विवरण चाहिए।
var rectangle = new Rectangle(7.1, 8.9);
System.out.print(rectangle.length()); // prints 7.1
यदि आप ऑब्जेक्ट निर्माण के दौरान मान को मान्य करना चाहते हैं, तो हमें स्पष्ट रूप से निर्माता को घोषित करना होगा।
public Rectangle {
if (length <= 0.0) {
throw new IllegalArgumentException();
}
}
रिकॉर्ड का शरीर स्थिर विधियों, स्थिर क्षेत्रों, स्थिर आरंभीकरण, निर्माणकर्ताओं, उदाहरण विधियों, और नेस्टेड प्रकारों की घोषणा कर सकता है।
उदाहरण के तरीके
record Rectangle(double length, double width) {
public double area() {
return this.length * this.width;
}
}
स्थिर क्षेत्र, विधियाँ
चूंकि राज्य घटकों का हिस्सा होना चाहिए इसलिए हम रिकॉर्ड में फ़ील्ड जोड़ नहीं सकते हैं। लेकिन, हम स्थैतिक क्षेत्रों और विधियों को जोड़ सकते हैं:
record Rectangle(double length, double width) {
static double aStaticField;
static void aStaticMethod() {
System.out.println("Hello Static");
}
}
अपरिवर्तनीयता की क्या आवश्यकता है और क्या इसका उपयोग करने का कोई फायदा है?
पहले से पोस्ट किए गए उत्तर, अपरिवर्तनीयता की आवश्यकता को उचित ठहराने के लिए पर्याप्त हैं और यह पेशेवरों के लिए है
अपरिवर्तनीय वस्तु बनाने का दूसरा तरीका Immutables.org लाइब्रेरी का उपयोग कर रहा है:
यह मानते हुए कि आवश्यक निर्भरता को जोड़ा गया था, अमूर्त अभिगम विधियों के साथ एक सार वर्ग बनाएं। आप इंटरफेस या एनोटेशन (@interface) के साथ एनोटेट करके भी ऐसा कर सकते हैं:
package info.sample;
import java.util.List;
import java.util.Set;
import org.immutables.value.Value;
@Value.Immutable
public abstract class FoobarValue {
public abstract int foo();
public abstract String bar();
public abstract List<Integer> buz();
public abstract Set<Long> crux();
}
अब उत्पन्न करने योग्य अपरिवर्तनीय कार्यान्वयन का उपयोग करना संभव है:
package info.sample;
import java.util.List;
public class FoobarValueMain {
public static void main(String... args) {
FoobarValue value = ImmutableFoobarValue.builder()
.foo(2)
.bar("Bar")
.addBuz(1, 3, 4)
.build(); // FoobarValue{foo=2, bar=Bar, buz=[1, 3, 4], crux={}}
int foo = value.foo(); // 2
List<Integer> buz = value.buz(); // ImmutableList.of(1, 3, 4)
}
}
एक अपरिवर्तनीय वर्ग बस एक ऐसा वर्ग है जिसके उदाहरणों को संशोधित नहीं किया जा सकता है।
प्रत्येक उदाहरण में निहित सभी जानकारी ऑब्जेक्ट के जीवनकाल के लिए तय की जाती है, इसलिए कोई भी परिवर्तन कभी नहीं देखा जा सकता है।
अपरिवर्तनीय कक्षाएं म्यूट करने योग्य कक्षाओं की तुलना में डिजाइन, कार्यान्वित और उपयोग करना आसान हैं।
एक कक्षा को अपरिवर्तनीय बनाने के लिए, इन पाँच नियमों का पालन करें:
ऑब्जेक्ट की स्थिति को संशोधित करने वाले तरीके प्रदान न करें
सुनिश्चित करें कि कक्षा को बढ़ाया नहीं जा सकता।
सभी क्षेत्रों को अंतिम रूप दें।
सभी क्षेत्रों को निजी बनाएं।
किसी भी परिवर्तनशील घटकों के लिए विशेष पहुंच सुनिश्चित करें।
अपरिवर्तनीय वस्तुएं स्वाभाविक रूप से धागा-सुरक्षित हैं; उन्हें कोई सिंक्रनाइज़ेशन की आवश्यकता नहीं है।
अपरिवर्तनीय वस्तुओं को स्वतंत्र रूप से साझा किया जा सकता है।
अपरिवर्तनीय वस्तुएं अन्य वस्तुओं के लिए महान बिल्डिंग ब्लॉक बनाती हैं
@ जेक, अंतिम क्षेत्र और वर्ग में बसने से कक्षा अपरिवर्तनीय नहीं होगी। अंतिम कीवर्ड केवल यह सुनिश्चित करते हैं कि एक चर कभी आश्वस्त नहीं होता है। आपको गेट्टर विधियों में सभी क्षेत्रों की गहरी प्रतिलिपि वापस करने की आवश्यकता है। यह सुनिश्चित करेगा कि, गेट्टर विधि से ऑब्जेक्ट प्राप्त करने के बाद, ऑब्जेक्ट की आंतरिक स्थिति परेशान नहीं होती है।
एक गैर-देशी अंग्रेजी बोलने वाले के रूप में, मैं "अपरिवर्तनीय वर्ग" की आम व्याख्या को नापसंद करता हूं "निर्माण की गई वस्तुएं अपरिवर्तनीय हैं"; बल्कि, मैं स्वयं यह व्याख्या करने के लिए झुक गया कि "वर्ग वस्तु ही अपरिवर्तनीय है"।
उस ने कहा, "अपरिवर्तनीय वर्ग" एक तरह की अपरिवर्तनीय वस्तु है। अंतर यह है कि उत्तर देने से क्या लाभ होता है। मेरी जानकारी / व्याख्या के लिए, अपरिवर्तनीय वर्ग अपनी वस्तुओं को रनटाइम व्यवहार संशोधनों से रोकता है।
यहाँ अधिकांश उत्तर अच्छे हैं, और कुछ ने नियमों का उल्लेख किया है, लेकिन मुझे इन नियमों का पालन करने की आवश्यकता क्यों और कब महसूस होती है, यह मुझे अच्छा लगता है। तो नीचे स्पष्टीकरण दे रहा हूं
और निश्चित रूप से अगर हम उन अंतिम चर के लिए सेटर्स का उपयोग करने की कोशिश करते हैं, तो कंपाइलर त्रुटि फेंक देता है।
public class ImmutableClassExplored {
public final int a;
public final int b;
/* OR
Generally we declare all properties as private, but declaring them as public
will not cause any issues in our scenario if we make them final
public final int a = 109;
public final int b = 189;
*/
ImmutableClassExplored(){
this. a = 111;
this.b = 222;
}
ImmutableClassExplored(int a, int b){
this.a = a;
this.b= b;
}
}
क्या हमें वर्ग को 'अंतिम' घोषित करने की आवश्यकता है?
1. केवल आदिम सदस्य होने पर: हमारे पास समस्या नहीं है यदि वर्ग में केवल आदिम सदस्य हैं, तो हमें वर्ग को अंतिम घोषित करने की आवश्यकता नहीं है।
2. वस्तुओं को सदस्य चर के रूप में देना: यदि हमारे पास सदस्य चर के रूप में वस्तुएं हैं तो हमें उन वस्तुओं के सदस्यों को भी अंतिम बनाना होगा। इसका मतलब है कि हमें पेड़ को गहराई से नीचे गिराने और सभी वस्तुओं / आदिमों को अंतिम रूप देने की आवश्यकता है जो हर समय संभव नहीं हो सकते हैं। इसलिए वर्कअराउंड क्लास फाइनल करना है जो इनहेरिटेंस को रोकता है। तो वहाँ उपश्रेणी ओवरराइडिंग getter तरीकों का कोई सवाल ही नहीं है।
@ लोमूक के उद्घोषणा का उपयोग अपरिवर्तनीय वर्ग उत्पन्न करने के लिए किया जा सकता है। यह नीचे दिए गए कोड की तरह सरल है।
@Value
public class LombokImmutable {
int id;
String name;
}
लोम्बोक की साइट पर प्रलेखन के अनुसार:
@Value @ दाता का अपरिवर्तनीय रूप है; सभी फ़ील्ड डिफ़ॉल्ट रूप से निजी और अंतिम बनाई जाती हैं, और बसने वाले उत्पन्न नहीं होते हैं। डिफ़ॉल्ट रूप से वर्ग को भी अंतिम बना दिया जाता है, क्योंकि अपरिवर्तनशीलता ऐसी चीज नहीं है जिसे उपवर्ग पर मजबूर किया जा सकता है। जैसे @Data, उपयोगी toString (), बराबर () और hashCode () विधियाँ भी उत्पन्न होती हैं, प्रत्येक फ़ील्ड में एक गेटर विधि मिलती है, और एक कंस्ट्रक्टर जो प्रत्येक तर्क को कवर करता है (अंतिम फ़ील्ड को छोड़कर जो क्षेत्र घोषणा में आरंभीकृत होता है) भी उत्पन्न होता है। ।
record
उपयोग किया जा सकता है तो लोम्बोक का उपयोग क्यों करें ?