2013-08-08 7 views
9

कृपया नीचे दिए गए कोड का संदर्भ लें। जब मैं कोड चलाता हूं, तो मैं अंतिम गैर स्थैतिक चर के मान को बदलने में सक्षम हूं। लेकिन अगर मैं अंतिम स्थैतिक चर के मान को बदलने की कोशिश करता हूं तो यह java.lang.IllegalAccessException फेंकता है।अंतिम चर बदलना, स्थिर और गैर स्थैतिक अंतिम चर के बीच अंतर क्यों

मेरा प्रश्न यह है कि यह गैर स्थैतिक अंतिम परिवर्तनीय या इसके विपरीत के मामले में अपवाद नहीं फेंकता है। अंतर क्यों?

import java.lang.reflect.Field; 
import java.util.Random; 

public class FinalReflection { 

    final static int stmark = computeRandom(); 
    final int inmark = computeRandom(); 

    public static void main(String[] args) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException { 
     FinalReflection obj = new FinalReflection(); 
     System.out.println(FinalReflection.stmark); 
     System.out.println(obj.inmark); 
     Field staticFinalField = FinalReflection.class.getDeclaredField("stmark"); 
     Field instanceFinalField = FinalReflection.class.getDeclaredField("inmark"); 
     staticFinalField.setAccessible(true); 
     instanceFinalField.setAccessible(true); 

     instanceFinalField.set(obj, 100); 
     System.out.println(obj.inmark); 

     staticFinalField.set(FinalReflection.class, 101); 
     System.out.println(FinalReflection.stmark); 

    } 

    private static int computeRandom() { 
     return new Random().nextInt(5); 
    } 
} 
+1

मैंने कोड पोस्ट किया है जो अपवाद नहीं देता है। लेकिन यह निश्चित रूप से एक हैक है। –

उत्तर

10
FinalReflectionobj = new FinalReflection(); 
System.out.println(FinalReflection.stmark); 
System.out.println(obj.inmark); 
Field staticFinalField = FinalReflection.class.getDeclaredField("stmark"); 
Field instanceFinalField = FinalReflection.class.getDeclaredField("inmark"); 
staticFinalField.setAccessible(true); 
instanceFinalField.setAccessible(true); 

//EXTRA CODE 
//Modify the final using reflection 
Field modifiersField = Field.class.getDeclaredField("modifiers"); 
modifiersField.setAccessible(true); 
modifiersField.setInt(staticFinalField, staticFinalField.getModifiers() & ~Modifier.FINAL); 


instanceFinalField.set(obj, 100); 
System.out.println(obj.inmark); 
staticFinalField.set(FinalReflection.class, 101); 
System.out.println(FinalReflection.stmark); 

यह समाधान कुछ कमियां के बिना नहीं आती है, यह सभी मामलों में काम नहीं कर सकता:

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

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

+0

@assylias कोई अतिरिक्त कोड भाग –

+2

@assylias नहीं देखता है, यदि कोई सुरक्षा प्रबंधक नहीं है तो यह आपको स्थिर अंतिम फ़ील्ड भी बदलने की अनुमति देगा। –

+0

ध्यान दें कि यह निरंतर अभिव्यक्ति के साथ प्रारंभिक स्थाई अंतिम प्राइमेटिव के साथ काम नहीं करेगा। – assylias

0

अंतिम के लिए, इसे प्रारंभ होने पर रनटाइम पर अलग-अलग मान असाइन किए जा सकते हैं।

Class Test{  
public final int a; 
} 

Test t1 = new Test(); 
t1.a = 10; 
Test t2 = new Test(); 
t1.a = 20; 

इस प्रकार प्रत्येक उदाहरण के क्षेत्र के अलग-अलग मूल्य होते हैं।

स्थैतिक फ़ाइनल के लिए, सभी उदाहरण समान मूल्य साझा करते हैं, और पहली बार प्रारंभ के बाद बदला नहीं जा सकता है।

Class TestStatic{ 
    public static final int a; 
} 

Test t1 = new Test(); 
t1.a = 10; 
Test t2 = new Test(); 
t1.a = 20; // ERROR, CAN'T BE ALTERED AFTER THE FIRST INITIALIZATION. 
+0

+1 में मदद करेगा। हां मैं आप जो कह रहा हूं उससे सहमत हूं। –

+0

लेकिन वह कक्षा के केवल एक ही उदाहरण का उपयोग करता है। और पहले असाइनमेंट के बाद एक गैर स्थैतिक अंतिम चर बदलने योग्य नहीं है। इसलिए यह स्पष्टीकरण गलत है। –

2

javadoc स्पष्ट है:

है कि अंतर्निहित क्षेत्र अंतिम है, विधि एक IllegalAccessException फेंकता है जब तक setAccessible (सही) इस फील्ड वस्तु के लिए सफल रहा है और क्षेत्र गैर स्थिर है।

एक JLS दृष्टिकोण से, कैसे प्रतिबिंब काम करना चाहिए की सही व्यवहार निर्दिष्ट किया जाता है नहीं है, लेकिन JLS 17.5.4 में:

आम तौर पर, एक क्षेत्र है कि अंतिम और स्थिर संशोधित नहीं किया जा सकता है।

एक वर्कअराउंड remove the final modifier through reflection है।

+1

एक्सेलेंट उत्तर, लेकिन मुझे लगता है कि सवाल यह है: जावा डिजाइनरों ने इसका फैसला क्यों किया? – morgano

+0

@ मॉर्गनो अगर ऐसा है तो एसओ शायद पूछने के लिए सबसे अच्छी जगह नहीं है! यह निश्चित रूप से सभी प्रकार के मुद्दों का कारण बनता है। उदाहरण के लिए आदिम स्थिरांक संकलन समय पर रेखांकित हैं, इसलिए आप रनटाइम पर उन्हें तब तक नहीं बदल सकते जब तक आप अंतर्निहित बाइटकोड नहीं बदलते। उत्कृष्ट जानकारी के लिए – assylias

+0

@assylias धन्यवाद। लेकिन हाँ, मेरे सवाल को मॉर्गनो ने जो कहा उससे थोड़ा गठबंधन किया गया था। लेकिन हाँ मैं इस बात से सहमत नहीं हो सका कि एसओ यह पूछने का सबसे अच्छा स्थान नहीं हो सकता है। मैं इसे अगली बार दिमाग में रखूंगा। वैसे भी आदिम मूलभूत और गैर स्थैतिक अंतिम चर दोनों के लिए जाना जाता है। computeRandom() के बजाय संशोधित कोड मान 5 चलाने का प्रयास करें। – veritas

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