2008-10-15 9 views
41

में अपरिवर्तनीय वस्तुओं की पहचान कैसे करूं, मेरे कोड में, मैं ऑब्जेक्ट्स का संग्रह बना रहा हूं जिसे एक फैशन में विभिन्न थ्रेडों द्वारा एक्सेस किया जाएगा जो ऑब्जेक्ट्स अपरिवर्तनीय हैं, केवल सुरक्षित हैं। जब मेरे संग्रह में एक नई वस्तु डालने का प्रयास किया जाता है, तो मैं यह देखने के लिए परीक्षण करना चाहता हूं कि यह अपरिवर्तनीय है (यदि नहीं, तो मैं अपवाद फेंक दूंगा)।मैं जावा

एक बात मैं क्या कर सकते हैं कुछ अच्छी तरह से ज्ञात अपरिवर्तनीय प्रकार की जाँच करने के लिए है:

private static final Set<Class> knownImmutables = new HashSet<Class>(Arrays.asList(
     String.class, Byte.class, Short.class, Integer.class, Long.class, 
     Float.class, Double.class, Boolean.class, BigInteger.class, BigDecimal.class 
)); 

... 

public static boolean isImmutable(Object o) { 
    return knownImmutables.contains(o.getClass()); 
} 

यह वास्तव में मुझे हो जाता है जिस तरह के 90%, लेकिन कभी कभी अपने उपयोगकर्ताओं के सरल अपरिवर्तनीय प्रकार बनाने के लिए चाहते हैं उनके खुद:

public class ImmutableRectangle { 
    private final int width; 
    private final int height; 
    public ImmutableRectangle(int width, int height) { 
     this.width = width; 
     this.height = height; 
    } 
    public int getWidth() { return width; } 
    public int getHeight() { return height; } 
} 

वहाँ किसी तरह (प्रतिबिंब शायद का उपयोग) है कि मैं मज़बूती से पता लगा सकता है कि क्या एक वर्ग अपरिवर्तनीय है है? झूठी सकारात्मक (सोचने पर यह अपरिवर्तनीय है) स्वीकार्य नहीं है लेकिन झूठी नकारात्मक (सोचने पर यह म्यूटेबल होने पर सोच रहा है) हैं।

जोड़ने के लिए संपादित: अंतर्दृष्टिपूर्ण और सहायक उत्तरों के लिए धन्यवाद। जैसा कि कुछ उत्तरों ने बताया, मैंने अपने सुरक्षा उद्देश्यों को परिभाषित करने के लिए उपेक्षित किया। यहां खतरा अनजान डेवलपर्स है - यह फ्रेमवर्क कोड का एक टुकड़ा है जिसका उपयोग बड़ी संख्या में लोगों द्वारा किया जाएगा जो थ्रेडिंग के बारे में कुछ भी नहीं जानते हैं और दस्तावेज़ीकरण नहीं पढ़ेंगे। मुझे दुर्भावनापूर्ण डेवलपर्स के खिलाफ बचाव करने की आवश्यकता नहीं है - mutate a String पर पर्याप्त चालाक या अन्य शेंगेनियां भी यह समझने के लिए पर्याप्त समझदार होंगे कि यह इस मामले में सुरक्षित नहीं है। कोडबेस का स्टेटिक विश्लेषण एक विकल्प है, जब तक कि यह स्वचालित हो, लेकिन कोड समीक्षा की गणना नहीं की जा सकती है क्योंकि प्रत्येक समीक्षा में थ्रेडिंग-समझदार समीक्षकों की कोई गारंटी नहीं है।

उत्तर

29

यह पता लगाने का कोई भरोसेमंद तरीका नहीं है कि कोई वर्ग अपरिवर्तनीय है या नहीं। ऐसा इसलिए है क्योंकि एक वर्ग की संपत्ति को कई तरीकों से बदला जा सकता है और आप उन सभी को प्रतिबिंब के माध्यम से नहीं पहचान सकते हैं।

इस के करीब पाने के लिए एक ही रास्ता है:

  • केवल प्रकार है कि अपरिवर्तनीय हैं के अंतिम गुण (आदिम प्रकार और वर्गों तुम जानते हो अपरिवर्तनीय हैं) की अनुमति,
  • वर्ग आवश्यकता अंतिम मैच में ही होने के लिए
  • आवश्यकता होती है कि वे एक आधार वर्ग उपलब्ध कराने (जो अपरिवर्तनीय होने की गारंटी है)

तो फिर तुम निम्न कोड के साथ देख सकते हैं कि वस्तु आपके पास मैं है से विरासत mmutable:

static boolean isImmutable(Object obj) { 
    Class<?> objClass = obj.getClass(); 

    // Class of the object must be a direct child class of the required class 
    Class<?> superClass = objClass.getSuperclass(); 
    if (!Immutable.class.equals(superClass)) { 
     return false; 
    } 

    // Class must be final 
    if (!Modifier.isFinal(objClass.getModifiers())) { 
     return false; 
    } 

    // Check all fields defined in the class for type and if they are final 
    Field[] objFields = objClass.getDeclaredFields(); 
    for (int i = 0; i < objFields.length; i++) { 
     if (!Modifier.isFinal(objFields[i].getModifiers()) 
       || !isValidFieldType(objFields[i].getType())) { 
      return false; 
     } 
    } 

    // Lets hope we didn't forget something 
    return true; 
} 

static boolean isValidFieldType(Class<?> type) { 
    // Check for all allowed property types... 
    return type.isPrimitive() || String.class.equals(type); 
} 

अद्यतन: के रूप में टिप्पणी में सुझाव दिया है, यह बजाय एक निश्चित वर्ग के लिए जाँच की सुपर क्लास पर recurse के लिए बढ़ाया जा सकता है। यह भी प्रयोग किया जाता है कि isValidFieldType विधि में Immutable है। यह शायद काम कर सकता है और मैंने कुछ परीक्षण भी किया है। लेकिन यह मामूली नहीं है। आप केवल कॉल के साथ सभी फ़ील्ड प्रकारों की जांच नहीं कर सकते हैं, क्योंकि स्ट्रिंग पहले से ही इस परीक्षण में विफल रहता है (इसका क्षेत्र hash अंतिम नहीं है!)। इसके अलावा आप आसानी से अंतहीन रिकर्सन में चल रहे हैं, जिससे स्टैक ओवरव्लोएरर्स;) अन्य समस्याएं जेनेरिकों के कारण हो सकती हैं, जहां आपको अपरिपक्वता के लिए अपने प्रकार की जांच भी करनी होगी।

मुझे लगता है कि कुछ काम के साथ, इन संभावित समस्याओं को किसी भी तरह हल किया जा सकता है। लेकिन फिर, आपको खुद से पहले पूछना होगा कि क्या यह वास्तव में इसके लायक है (प्रदर्शन के अनुसार)। वर्ग नहीं setters है

तो यह उत्परिवर्तित नहीं किया जा सकता, मानकों इसके साथ बनाया गया था या तो "आदिम" प्रकार के होते हैं या खुद को परिवर्तनशील नहीं दी:

+0

शायद "isValidFieldType" अचूक करने के लिए एक पुनरावर्तन कर सकता है। :-) – marcospereira

+0

मार्कोस्पेरिया के संशोधन के साथ, यह काफी उपयोगी हो सकता है! हम सुपरक्लस (ऑब्जेक्ट को एक विशेष मामले के रूप में अनुमति देने) पर भी भर्ती कर सकते हैं जो एक सामान्य पूर्वजों से प्राप्त करने की आवश्यकता को खत्म कर देगा। यह अच्छा है! – mcherm

+0

ये अच्छे सुझाव हैं। मैंने सादगी और प्रदर्शन के लिए सुपरक्लास और सदस्यों पर रिकर्सिंग से बचने की कोशिश की (रिकर्सन काफी व्यापक हो सकता है)। लेकिन मैं इन सुझावों को anweser में जोड़ दूंगा। –

8

मूल रूप से नहीं।

आप स्वीकार किए गए वर्गों की एक विशाल सफेद सूची बना सकते हैं, लेकिन मुझे लगता है कि संग्रह के लिए दस्तावेज में लिखने के लिए कम पागल तरीका यह होगा कि यह संग्रह अपरिवर्तनीय होना चाहिए।

संपादित करें: अन्य लोगों ने एक अपरिवर्तनीय एनोटेशन होने का सुझाव दिया है। यह ठीक है, लेकिन आपको दस्तावेज़ों की भी आवश्यकता है। अन्यथा लोग सोचेंगे कि "अगर मैं अपनी कक्षा में यह एनोटेशन डालता हूं तो मैं इसे संग्रह में संग्रहीत कर सकता हूं" और इसे किसी भी चीज, अपरिवर्तनीय और उत्परिवर्तनीय वर्गों पर समान रूप से चकित कर देगा। वास्तव में, अगर लोगों को लगता है कि एनोटेशन उनकी कक्षा अपरिवर्तनीय बनाता है तो मुझे एक अपरिवर्तनीय एनोटेशन होने से सावधान रहना होगा।

+0

इसके अलावा, जेसीआईपी पुस्तक में java.util.Date जैसे प्रभावशाली अपरिवर्तनीय वर्गों के बारे में चर्चा है, जो व्यावहारिक रूप से अपरिवर्तनीय के रूप में उपयोग किए जाते हैं, भले ही वे – ddimitrov

9

मेरी कंपनी में हमने @Immutable नामक एक विशेषता को परिभाषित किया है। यदि आप इसे कक्षा में संलग्न करना चुनते हैं, तो इसका मतलब है कि आप वादा करते हैं कि आप अपरिवर्तनीय हैं।

यह प्रलेखन के लिए काम करता है, और आपके मामले में यह फ़िल्टर के रूप में काम करेगा।

बेशक आप अभी भी लेखक के आधार पर अपरिवर्तनीय होने के बारे में अपना शब्द रखते हुए हैं, लेकिन लेखक ने स्पष्ट रूप से एनोटेशन को जोड़ा है, यह एक उचित धारणा है।तब

@Immutable 
public class ImmutableRectangle { 
    private final int width; 
    private final int height; 
    public ImmutableRectangle(int width, int height) { 
     this.width = width; 
     this.height = height; 
    } 
    public int getWidth() { return width; } 
    public int getHeight() { return height; } 
} 

:

+0

न हों, यदि आप लेखक के आधार पर अपना शब्द रखते हैं अपरिवर्तनीय बिंदु क्या है? यह कुछ भी नहीं जोड़ रहा है, और अगर लोग सोचते हैं कि एनोटेशन * उनकी कक्षा को अपरिवर्तनीय बनाता है तो यह संभावित रूप से नुकसान पहुंचा सकता है .. – SCdF

+0

विचार उम्मीद है कि निकट भविष्य में आपके पास कुछ स्थिर कोड विश्लेषण होगा - शायद आपके आईडीई में एकीकृत - जाने के लिए अपने कोड के माध्यम से और जांचें कि आपके @Imutable एनोटेटेड कक्षाएं * वास्तव में अपरिवर्तनीय हैं। –

+0

जेसन की कंपनी (जिस पर मैं भी काम करता हूं) में, हम भी लिखे गए कोड की प्रत्येक पंक्ति की समीक्षा करते हैं। इसलिए, यदि आप उस वर्ग पर @Imututable विशेषता डालते हैं जो अपरिवर्तनीय नहीं है, तो आप इसे बुलाएंगे। जेसन से पूछो, मैंने इसे कई बार किया है। –

3

आप प्रतिबिंब के साथ रनटाइम पर मेटाडाटा (एनोटेशन) जोड़ सकते हैं और जाँच उन्हें, इस तरह के लिए अपने ग्राहकों पूछ सकते हैं:

मेटाडाटा:

@Retention(RetentionPolicy.RUNTIME) 
@Target(ElementType.CLASS) 
public @interface Immutable{ } 

क्लाइंट कोड कक्षा पर प्रतिबिंब का उपयोग करके, जांच करें कि क्या यह एनोटेशन है (मैं कोड पेस्ट करता हूं लेकिन इसके बॉयलरप्लेट को आसानी से ऑनलाइन पाया जा सकता है)

+0

आप लोगों को उस गैर-अपरिवर्तनीय कक्षाओं पर केवल उस टिप्पणी को रखने से कैसे रोकेंगे? – SCdF

+0

आप उन्हें रोक नहीं सकते हैं। यदि आप कुछ का उपयोग करने के निर्देशों का पालन नहीं कर सकते हैं, तो आपको इसे प्रोग्राम करने का प्रयास नहीं करना चाहिए। –

+0

@ सिमॉन, ठीक है, तो फिर एनोटेशन का क्या मतलब है? क्या आप यह नहीं मान सकते कि वे संग्रह के बारे में दस्तावेज पढ़ने के लिए पर्याप्त स्मार्ट हैं और इस प्रकार यह जानते हैं कि यह केवल अपरिवर्तनीय चीजों के लिए है? – SCdF

4

यह एक और संकेत हो सकता है।

इसके अलावा कोई तरीकों ओवरराइड किया जा सकता है, सभी क्षेत्रों अंतिम और निजी हैं,

मैं तुम्हारे लिए कुछ कल कोड करने के लिए कोशिश करता हूँ, लेकिन प्रतिबिंब का उपयोग साइमन के कोड बहुत अच्छा लग रहा है।

इसी समय जोश ब्लॉक द्वारा "प्रभावी जावा" पुस्तक की प्रतिलिपि लेने की कोशिश करें, इसमें इस विषय से संबंधित एक आइटम है। हालांकि यह सुनिश्चित नहीं है कि एक अतुल्य वर्ग का पता लगाने के लिए, यह दिखाता है कि एक अच्छा कैसे बनाया जाए।

आइटम कहा जाता है: "अचल स्थिति का पक्ष लें"

लिंक: http://java.sun.com/docs/books/effective/

2

अन्य answerers जैसा पहले ही कहा है, IMHO वहाँ पता लगाने के लिए अगर एक वस्तु वास्तव में अपरिवर्तनीय है कोई विश्वसनीय तरीका है।

मैं बस संलग्न होने के दौरान जांचने के लिए एक इंटरफ़ेस "अपरिवर्तनीय" पेश करूंगा। यह एक संकेत के रूप में काम करता है कि आप जो भी कारण कर रहे हैं उसके लिए केवल अपरिवर्तनीय वस्तुएं डाली जानी चाहिए।

interface Immutable {} 

class MyImmutable implements Immutable{...} 

public void add(Object o) { 
    if (!(o instanceof Immutable) && !checkIsImmutableBasePrimitive(o)) 
    throw new IllegalArgumentException("o is not immutable!"); 
    ... 
} 
4

मेरे कोड में, मैं जिन वस्तुओं पर एक फैशन है कि केवल सुरक्षित है अगर वस्तुओं अपरिवर्तनीय हैं में विभिन्न धागे द्वारा पहुँचा जा जाएगा का एक संग्रह बनाने रहा हूँ।

आपके प्रश्न का सीधा जवाब नहीं है, लेकिन ध्यान रखें कि अपरिवर्तनीय वस्तुएं स्वचालित रूप से थ्रेड सुरक्षित (दुखी) होने की गारंटी नहीं देती हैं। कोड को थ्रेड सुरक्षित होने के लिए साइड-इफेक्ट मुक्त होना चाहिए, और यह काफी कठिन है।

मान लीजिए आप इस वर्ग के होते हैं:

class Foo { 
    final String x; 
    final Integer y; 
    ... 

    public bar() { 
    Singleton.getInstance().foolAround(); 
    } 
} 

फिर foolAround() विधि कुछ गैर धागा सुरक्षित संचालन, जो आपके ऐप्लिकेशन को उड़ाने होगा शामिल हो सकता है। और प्रतिबिंब का उपयोग करके इसका परीक्षण करना संभव नहीं है, क्योंकि वास्तविक संदर्भ केवल विधि निकाय में पाया जा सकता है, न कि फ़ील्ड या खुला इंटरफ़ेस में।

इसके अलावा, अन्य सही हैं: आप कक्षा के सभी घोषित क्षेत्रों के लिए स्कैन कर सकते हैं, जांचें कि उनमें से प्रत्येक अंतिम और एक अपरिवर्तनीय वर्ग है, और आप कर चुके हैं। मुझे नहीं लगता कि अंतिम होने की विधियां एक आवश्यकता है।

इसके अलावा, रिकर्सिवली अचल स्थिति के लिए निर्भर क्षेत्रों सावधानीपूर्वक जांच करें, आप मंडलियों के साथ खत्म हो सकता है:

class A { 
    final B b; // might be immutable... 
} 

class B { 
    final A a; // same so here. 
} 

वर्ग ए और बी पूरी तरह से अडिग (और कुछ प्रतिबिंब हैक्स के माध्यम से संभावित रूप से प्रयोग करने योग्य) हैं, लेकिन अनुभवहीन रिकर्सिव कोड एक अंतहीन लूप जांच ए में जाएगा, फिर बी, फिर ए, बाद में बी, ...

आप इसे 'देखा' मानचित्र के साथ ठीक कर सकते हैं जो चक्रों को अस्वीकार करता है, या कुछ वास्तव में चालाक कोड के साथ निर्णय लेता है कि कक्षाएं अपरिवर्तनीय हैं यदि उनके सभी निर्भर केवल खुद के आधार पर अपरिवर्तनीय हैं, लेकिन यह वास्तव में कॉम होने वाला है plicated ...

+0

ये वास्तव में अच्छी चेतावनियां हैं, जिनमें से मैंने वास्तव में विचार नहीं किया था। मुझे संदेह है कि मुझे पुनरावर्ती निहित अपरिवर्तनीय वस्तु के खिलाफ बचाव करने की आवश्यकता है (सबसे सरल मामला एक अपरिवर्तनीय वस्तु होगी जो खुद को एक क्षेत्र में रखेगा!), लेकिन दूसरा खतरे का एक सा है। – mcherm

28

Java Concurrency in Practice से Immutable एनोटेशन का उपयोग करें। उपकरण FindBugs तब कक्षाओं का पता लगाने में मदद कर सकता है जो उत्परिवर्तनीय हैं लेकिन नहीं होना चाहिए।

+0

अपना कोड चलाने के दौरान वह FindBugs को कैसे लागू कर सकता है? एक समझदार वस्तु को जोड़ा गया है, तो मैं क्या समझता हूं कि वह रनटाइम पर जांचना चाहता है? – dhiller

+0

वह मिसैनोटेटेड कक्षाओं की संख्या को कम करने और रनटाइम पर एनोटेशन का उपयोग करने के लिए बिल्ड समय पर Findbugs का उपयोग कर सकते हैं। – ddimitrov

+6

मुझे एहसास नहीं हुआ था कि Findbugs ने यह विश्लेषण किया - यह बहुत अच्छा है! मैंने दस्तावेज़ों पर एक नज़र डाली और ऐसा लगता है कि यह केवल सत्यापित करता है कि एक एनोटेटेड क्लास के सभी फ़ील्ड अंतिम हैं (लेकिन यह सत्यापित नहीं करता है कि उनमें सभी अपरिवर्तनीय वस्तुएं हैं)। – mcherm

3

सभी सिफारिशों को कक्षा को अंतिम होने की आवश्यकता क्यों है? यदि आप प्रत्येक ऑब्जेक्ट की कक्षा की जांच करने के लिए प्रतिबिंब का उपयोग कर रहे हैं, और आप प्रोग्रामेटिक रूप से निर्धारित कर सकते हैं कि वह वर्ग अपरिवर्तनीय (अपरिवर्तनीय, अंतिम फ़ील्ड) है, तो आपको कक्षा की आवश्यकता होने की आवश्यकता नहीं है।

+2

इसके अलावा, हो रही * वर्ग * अंतिम है * निश्चित रूप से * कोई पर असर: यहाँ एक Maven निर्भरता के रूप में एनोटेशन हैं इसकी अपरिवर्तनीयता। इसका मतलब है कि इसे बढ़ाया नहीं जा सकता है। – bendin

+0

क्योंकि गैर-अंतिम अपरिवर्तनीय से प्राप्त कक्षा एक उत्परिवर्तनीय गुण जोड़ सकती है। – Ingo

+1

लेकिन आप वास्तविक समय को निष्पादन समय पर जानते हैं। –

0

जावा के लिए क्षमताओं के कार्यान्वयन, joe-e देखें।

0

कुछ जो बिल्टिन कक्षाओं के उच्च प्रतिशत के लिए काम करता है वह तुलनात्मक उदाहरण के लिए परीक्षण है। उन वर्गों के लिए जो तिथि की तरह अपरिवर्तनीय नहीं हैं, उन्हें अक्सर ज्यादातर मामलों में अपरिवर्तनीय माना जाता है।

2

इस प्रयास करें:

public static boolean isImmutable(Object object){ 
    if (object instanceof Number) { // Numbers are immutable 
     if (object instanceof AtomicInteger) { 
      // AtomicIntegers are mutable 
     } else if (object instanceof AtomicLong) { 
      // AtomLongs are mutable 
     } else { 
      return true; 
     } 
    } else if (object instanceof String) { // Strings are immutable 
     return true; 
    } else if (object instanceof Character) { // Characters are immutable 
     return true; 
    } else if (object instanceof Class) { // Classes are immutable 
     return true; 
    } 

    Class<?> objClass = object.getClass(); 

    // Class must be final 
    if (!Modifier.isFinal(objClass.getModifiers())) { 
      return false; 
    } 

    // Check all fields defined in the class for type and if they are final 
    Field[] objFields = objClass.getDeclaredFields(); 
    for (int i = 0; i < objFields.length; i++) { 
      if (!Modifier.isFinal(objFields[i].getModifiers()) 
          || !isImmutable(objFields[i].getType())) { 
        return false; 
      } 
    } 

    // Lets hope we didn't forget something 
    return true; 
} 
3

आप jcabi-aspects से AOP और @Immutable एनोटेशन का उपयोग कर सकते हैं:

@Immutable 
public class Foo { 
    private String data; 
} 
// this line will throw a runtime exception since class Foo 
// is actually mutable, despite the annotation 
Object object = new Foo(); 
0
मेरी जानकारी के लिए

, वहाँ अपरिवर्तनीय वस्तुओं है कि 100% सही है की पहचान करने के लिए कोई रास्ता नहीं है। हालांकि, मैंने आपको करीब लाने के लिए एक पुस्तकालय लिखा है। यह यह निर्धारित करने के लिए कक्षा के बाइटकोड का विश्लेषण करता है कि यह अपरिवर्तनीय है या नहीं, और रनटाइम पर निष्पादित हो सकता है। यह सख्त तरफ है, इसलिए यह ज्ञात अपरिवर्तनीय वर्गों को श्वेतसूची की अनुमति देता है।

आप इसे बाहर की जाँच कर सकते हैं: www.mutabilitydetector.org

यह आप अपने आवेदन में इस तरह कोड लिखने की अनुमति देता है:

/* 
* Request an analysis of the runtime class, to discover if this 
* instance will be immutable or not. 
*/ 
AnalysisResult result = analysisSession.resultFor(dottedClassName); 

if (result.isImmutable.equals(IMMUTABLE)) { 
    /* 
    * rest safe in the knowledge the class is 
    * immutable, share across threads with joyful abandon 
    */ 
} else if (result.isImmutable.equals(NOT_IMMUTABLE)) { 
    /* 
    * be careful here: make defensive copies, 
    * don't publish the reference, 
    * read Java Concurrency In Practice right away! 
    */ 
} 

यह अपाचे 2.0 लाइसेंस के अंतर्गत स्वतंत्र और खुला स्रोत है।

0

मैं सराहना करते हैं और काम Grundlefleck उसकी अस्थिरता डिटेक्टर में डाल दिया गया है की राशि प्रशंसा करता हूँ, लेकिन मुझे लगता है यह एक overkill का एक सा है।

(ध्यान दें:: यह मेरी टिप्पणी यहाँ की एक प्रति है: https://stackoverflow.com/a/28111150/773113) आप इस प्रकार एक सरल लेकिन व्यावहारिक रूप से बहुत पर्याप्त डिटेक्टर लिख सकते हैं (व्यावहारिक कि है,)

सबसे पहले, आप नहीं कर रहे हैं सिर्फ एक विधि लिखने जा रहा है जो निर्धारित करता है कि कक्षा अपरिवर्तनीय है या नहीं; इसके बजाय, आपको एक अपरिवर्तनीय डिटेक्टर कक्षा लिखनी होगी, क्योंकि इसे कुछ राज्य बनाए रखना होगा। डिटेक्टर की स्थिति अब तक की सभी कक्षाओं की खोजी अपरिवर्तनीयता होगी। यह न केवल प्रदर्शन के लिए उपयोगी है, बल्कि यह वास्तव में जरूरी है क्योंकि कक्षा में एक परिपत्र संदर्भ हो सकता है, जिससे एक सरल अपरिवर्तनीय डिटेक्टर अनंत रिकर्सन में पड़ सकता है। Unknown, Mutable, Immutable, और Calculating:

एक वर्ग की अचल चार संभावित मान हैं। आप शायद एक नक्शा बनाना चाहते हैं जो प्रत्येक कक्षा को जोड़ता है जिसे आपने अब तक अपरिवर्तनीय मूल्य के लिए सामना किया है। बेशक, Unknown को वास्तव में लागू करने की आवश्यकता नहीं है, क्योंकि यह किसी भी वर्ग की अंतर्निहित स्थिति होगी जो अभी तक मानचित्र में नहीं है।

इसलिए, जब आप एक वर्ग की जांच शुरू करते हैं, आप इसे मानचित्र में एक Calculating मान के साथ संबद्ध है, और जब आप समाप्त कर, आप या तो Immutable या Mutable साथ Calculating बदलें।

प्रत्येक कक्षा के लिए, आपको केवल फ़ील्ड सदस्यों की जांच करने की आवश्यकता है, कोड नहीं। बाइटकोड की जांच करने का विचार गुमराह है।

सबसे पहले, आपको चाहिए नहीं जाँच है कि क्या एक वर्ग अंतिम है; कक्षा की अंतिमता इसकी अपरिवर्तनीयता को प्रभावित नहीं करती है। इसके बजाय, एक तरीका है जिसके अपरिवर्तनीय पैरामीटर उम्मीद सब से पहले अचल स्थिति डिटेक्टर आह्वान वास्तविक उद्देश्य यह है कि पारित किया गया था के वर्ग की अचल बात पर जोर देना चाहिए। यदि पैरामीटर के प्रकार के एक अंतिम वर्ग है, इसलिए अंतिम प्रदर्शन के लिए अच्छा है, लेकिन सख्ती से आवश्यक नहीं बोल इस परीक्षा छोड़ा जा सकता है। परिवर्तनशील रूप में माना जा करने के लिए इसके अलावा, के रूप में आप और नीचे देखेंगे, एक क्षेत्र है जिसका प्रकार एक गैर अंतिम वर्ग की है की घोषणा वर्ग का कारण होगा, लेकिन फिर भी हुए घोषणा की कि वर्ग की एक समस्या, गैर अंतिम की नहीं समस्या है अपरिवर्तनीय सदस्य वर्ग।अपरिवर्तनीय कक्षाओं का लंबा पदानुक्रम होना बिल्कुल ठीक है, जिसमें सभी गैर-पत्ती नोड्स निश्चित रूप से गैर-अंतिम होना चाहिए।

आपको नहीं देखना चाहिए कि कोई फ़ील्ड निजी है या नहीं; कक्षा के लिए सार्वजनिक क्षेत्र होने के लिए यह बिल्कुल ठीक है, और क्षेत्र की दृश्यता किसी भी तरह से, आकार, या रूप में घोषित कक्षा की अपरिवर्तनीयता को प्रभावित नहीं करती है। आपको केवल यह जांचने की आवश्यकता है कि फ़ील्ड अंतिम है या नहीं और इसका प्रकार अपरिवर्तनीय है।

कक्षा की जांच करते समय, आप सबसे पहले क्या करना चाहते हैं, यह super कक्षा की अपरिवर्तनीयता निर्धारित करने के लिए है। यदि सुपर उत्परिवर्तनीय है, तो वंशज भी परिभाषा द्वारा परिवर्तनीय है।

उसके बाद, आप केवल वर्ग के घोषित क्षेत्रों, नहीं सभी क्षेत्रों की जांच करने की जरूरत है।

यदि कोई फ़ील्ड गैर-फाइनल है, तो आपकी कक्षा उत्परिवर्तनीय है।

यदि कोई फ़ील्ड अंतिम है, लेकिन फ़ील्ड का प्रकार उत्परिवर्तनीय है, तो आपकी कक्षा उत्परिवर्तनीय है। (Arrays परिभाषा mutable द्वारा हैं।)

यदि कोई फ़ील्ड अंतिम है, और फ़ील्ड का प्रकार Calculating है, तो उसे अनदेखा करें और अगले फ़ील्ड पर जाएं। यदि सभी फ़ील्ड या तो अपरिवर्तनीय हैं या Calculating हैं, तो आपकी कक्षा अपरिवर्तनीय है।

यदि फ़ील्ड का प्रकार एक इंटरफेस, या एक अमूर्त वर्ग, या एक गैर-अंतिम वर्ग है, तो इसे म्यूटेबल के रूप में माना जाना चाहिए, क्योंकि वास्तविक कार्यान्वयन के बारे में आपके पास बिल्कुल नियंत्रण नहीं है। यह एक दुर्बल समस्या की तरह प्रतीत हो सकता है, क्योंकि इसका मतलब है कि एक UnmodifiableCollection के अंदर एक संशोधित संग्रह लपेटना अभी भी अपरिवर्तनीय परीक्षण में विफल रहेगा, लेकिन यह वास्तव में ठीक है, और इसे निम्नलिखित कार्यवाही के साथ संभाला जा सकता है।

कुछ कक्षाओं में गैर-अंतिम फ़ील्ड हो सकते हैं और अभी भी प्रभावी रूप से अपरिवर्तनीय हो सकते हैं। इसका एक उदाहरण String वर्ग है। इस श्रेणी में आने वाले अन्य वर्ग वे वर्ग हैं जिनमें प्रदर्शन निगरानी उद्देश्यों (आमंत्रण काउंटर इत्यादि) के लिए पूरी तरह से गैर-अंतिम सदस्य होते हैं, जो कक्षाएं पॉपसिकल अपरिवर्तनीयता (इसे देखें) लागू करती हैं, और कक्षाएं जिनमें इंटरफेस होते हैं, किसी भी दुष्प्रभाव का कारण नहीं है। इसके अलावा, यदि किसी वर्ग में व्यापक म्यूटेबल फ़ील्ड होते हैं लेकिन वादा है कि हैशकोड() और बराबर() की गणना करते समय उन्हें ध्यान में न लेना, तो क्लास बहु-थ्रेडिंग की बात करते समय असुरक्षित है, लेकिन इसे अभी भी माना जा सकता है मानचित्र में एक कुंजी के रूप में इसका उपयोग करने के उद्देश्य से अपरिवर्तनीय।

  1. मैन्युअल जोड़ने वर्गों (और इंटरफेस) अपने अचल स्थिति डिटेक्टर के लिए: तो, इन सभी मामलों दो तरीकों में से एक में संभाला जा सकता है। यदि आप जानते हैं कि एक निश्चित वर्ग प्रभावी रूप से अपरिवर्तनीय है, इस तथ्य के बावजूद कि इसके लिए अपरिवर्तनीय परीक्षण विफल हो जाता है, तो आप अपने डिटेक्टर में मैन्युअल रूप से एक प्रविष्टि जोड़ सकते हैं जो इसे Immutable से संबद्ध करता है। इस तरह, डिटेक्टर कभी यह जांचने का प्रयास नहीं करेगा कि यह अपरिवर्तनीय है, यह हमेशा 'हाँ, यह है' कहेंगे।

  2. @ImmutabilityOverride एनोटेशन पेश करना। आपका अपरिवर्तनीय डिटेक्टर किसी क्षेत्र पर इस एनोटेशन की उपस्थिति की जांच कर सकता है, और यदि मौजूद है, तो यह क्षेत्र इस तथ्य के बावजूद अपरिवर्तनीय हो सकता है कि क्षेत्र गैर-अंतिम हो सकता है या इसका प्रकार उत्परिवर्तनीय हो सकता है। डिटेक्टर कक्षा पर इस एनोटेशन की उपस्थिति की भी जांच कर सकता है, इस प्रकार कक्षा को अपने खेतों की जांच करने के लिए भी परेशान किए बिना अपरिवर्तनीय के रूप में व्यवहार कर सकता है।

मुझे आशा है कि इससे भविष्य की पीढ़ियों में मदद मिलेगी।

संबंधित मुद्दे