जावा प्रतिबिंब का उपयोग करके निजी स्थिर अंतिम फ़ील्ड बदलें


478

मेरे पास एक private static finalफ़ील्ड के साथ एक क्लास है, दुर्भाग्य से, मुझे इसे रन-टाइम में बदलना होगा।

प्रतिबिंब का उपयोग करके मुझे यह त्रुटि मिलती है: java.lang.IllegalAccessException: Can not set static final boolean field

क्या मूल्य बदलने का कोई तरीका है?

Field hack = WarpTransform2D.class.getDeclaredField("USE_HACK");
hack.setAccessible(true);
hack.set(null, true);

4
ऐसा बुरा विचार। मैं स्रोत और recompile (या यहां तक ​​कि decompile / recompile) प्राप्त करने का प्रयास करूँगा।
बिल के

System.out एक सार्वजनिक स्थैतिक अंतिम क्षेत्र है, लेकिन इसे बदला भी जा सकता है।
विवादास्पद

19
@irreputable System.out/in/errइतने "विशेष" हैं कि जावा मेमोरी मॉडल को उनका विशेष उल्लेख करना होगा। वे उदाहरण नहीं हैं जिनका पालन किया जाना चाहिए।
टॉम हॉल्टिन -

8
अच्छी तरह से मेरी बात के बीच में एक हैक खोजने के लिए ws मेरी app काम कर रहा है जब तक कि जिम्मेदार जिम्मेदार अगली रिलीज में परिवर्तन नहीं करते हैं, इसलिए मुझे अब और हैक करने की आवश्यकता नहीं है ...
फिक्सिटैगैन

1
@ B K दस साल पहले से: यह इसे फिर से इकट्ठा करने के लिए महान होगा लेकिन यह एक तैनात सिस्टम पर है और मुझे इसे तब तक पैच करने की आवश्यकता है जब तक हम तैनात ऐप को अपडेट नहीं कर सकते हैं!
बिल के

जवाबों:


887

मान लिया जाए कि SecurityManagerआपको ऐसा करने से नहीं रोका जा रहा है, तो आप छुटकारा पाने के setAccessibleलिए चारों ओर घूमने privateऔर संशोधक को रीसेट करने finalऔर वास्तव में एक private static finalक्षेत्र को संशोधित करने के लिए उपयोग कर सकते हैं ।

यहाँ एक उदाहरण है:

import java.lang.reflect.*;

public class EverythingIsTrue {
   static void setFinalStatic(Field field, Object newValue) throws Exception {
      field.setAccessible(true);

      Field modifiersField = Field.class.getDeclaredField("modifiers");
      modifiersField.setAccessible(true);
      modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);

      field.set(null, newValue);
   }
   public static void main(String args[]) throws Exception {      
      setFinalStatic(Boolean.class.getField("FALSE"), true);

      System.out.format("Everything is %s", false); // "Everything is true"
   }
}

नहीं मान लिया गया SecurityExceptionहै, उपरोक्त कोड प्रिंट करता है "Everything is true"

वास्तव में यहाँ क्या किया गया है:

  • आदिम booleanमूल्यों trueऔर falseमें mainसंदर्भ प्रकार के autoboxed कर रहे हैं Boolean"स्थिरांक" Boolean.TRUEऔरBoolean.FALSE
  • public static final Boolean.FALSEसंदर्भित करने के लिए Booleanसंदर्भित को बदलने के लिए परावर्तन का उपयोग किया जाता हैBoolean.TRUE
  • नतीजतन, बाद में जब भी किसी falseको ऑटोबॉक्स किया जाता है Boolean.FALSE, तो यह उसी के Booleanरूप में संदर्भित होता है जिसके द्वारा संदर्भित किया जाता हैBoolean.TRUE
  • "false"अब जो कुछ था वह सब कुछ है"true"

संबंधित सवाल


चेतावनियां

जब भी आप ऐसा कुछ करते हैं तो अत्यधिक सावधानी बरतनी चाहिए। यह काम नहीं SecurityManagerकर सकता क्योंकि मौजूद हो सकता है, लेकिन भले ही यह उपयोग के पैटर्न के आधार पर न हो, यह काम कर भी सकता है और नहीं भी।

JLS 17.5.3 अंतिम क्षेत्रों का बाद में संशोधन

कुछ मामलों में, जैसे कि deserialization, सिस्टम को finalनिर्माण के बाद किसी ऑब्जेक्ट के फ़ील्ड को बदलने की आवश्यकता होगी । finalफ़ील्ड्स को प्रतिबिंब और अन्य कार्यान्वयन निर्भर साधनों के माध्यम से बदला जा सकता है। एकमात्र पैटर्न जिसमें यह वाजिब शब्दार्थ है जिसमें एक वस्तु का निर्माण किया जाता है और फिर finalऑब्जेक्ट के क्षेत्र अपडेट किए जाते हैं। ऑब्जेक्ट को अन्य थ्रेड्स के लिए दृश्यमान नहीं किया जाना चाहिए, और न ही finalफ़ील्ड्स को पढ़ना चाहिए , जब तक finalकि ऑब्जेक्ट के फ़ील्ड्स के सभी अपडेट पूर्ण न हों। किसी finalफ़ील्ड के फ़्रीजर्स , कंस्ट्रक्टर के अंत में दोनों होते हैं जिसमें finalफ़ील्ड सेट होता है, और finalप्रतिबिंब या अन्य विशेष तंत्र के माध्यम से फ़ील्ड के प्रत्येक संशोधन के तुरंत बाद ।

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

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

यह सभी देखें

  • जेएलएस 15.28 लगातार अभिव्यक्ति
    • यह संभावना नहीं है कि यह तकनीक एक आदिम के साथ काम करती है private static final boolean, क्योंकि यह संकलन-समय स्थिर के रूप में अप्रभावी है और इस प्रकार "नया" मान देखने योग्य नहीं हो सकता है

परिशिष्ट: बिटवाइज़ हेरफेर पर

अनिवार्य रूप से,

field.getModifiers() & ~Modifier.FINAL

Modifier.FINALसे करने के लिए इसी बिट बंद कर देता है field.getModifiers()&बिटवाइज़-एंड है, और ~बिटवाइज़-पूरक है।

यह सभी देखें


लगातार अभिव्यक्तियाँ याद रखें

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

public class A {
    private final String myVar = "Some Value";
}

इस उत्तर पर टिप्पणियों को पढ़ते हुए, विशेष रूप से @Phemo द्वारा एक, यह मुझे याद दिलाया कि लगातार अभिव्यक्तियाँ अलग-अलग हैं, इसलिए इसे संशोधित करना असंभव होगा । इसलिए आपको इस तरह दिखने के लिए अपना कोड बदलना होगा:

public class A {
    private final String myVar;

    private A() {
        myVar = "Some Value";
    }
}

यदि आप वर्ग के मालिक नहीं हैं ... तो मैं आपको महसूस करता हूँ!

इस व्यवहार के बारे में अधिक जानकारी के लिए इसे क्यों पढ़ें ?


41
@thecoop, @HalfBrian: इसमें कोई शक नहीं है कि यह EXTREMELY EVIL है , लेकिन इस उदाहरण को डिज़ाइन द्वारा चुना गया था। मेरा जवाब केवल दिखाता है कि कैसे, कुछ परिस्थितियों में, यह संभव है। सबसे घृणित उदाहरण जो मैं सोच सकता हूं, वह इस उम्मीद के साथ चुना गया है कि शायद लोगों को तकनीक के प्यार में पड़ने के बजाय तुरंत घृणा होगी।
पॉलीजेन लुब्रीकेंट जूल

59
यो डॉग। मैंने आपको प्रतिबिंब की तरह सुना, इसलिए मैंने फ़ील्ड पर प्रतिबिंबित किया ताकि आप प्रतिबिंबित करते समय प्रतिबिंबित कर सकें।
मैथ्यू फ्लास्चेन

11
ध्यान दें कि Boolean.FALSE निजी नहीं है। क्या यह वास्तव में "निजी अंतिम स्थिर" सदस्यों के साथ काम करता है?
mgaert

15
@ यह काम करता है, लेकिन आपको टारगेट क्लास getDeclaredField()के getField()लिए उपयोग करना है
eis

10
+1। उन लोगों के लिए जो कुछ बदलने की कोशिश करेंगे final String myConstant = "x";और असफल हो जाएंगे: याद रखें कि संकलित समय स्थिरांक को संकलक द्वारा इनबिल्ड किया जाएगा, इसलिए जब आप कोड लिखेंगे जैसे कि System.out.println(myConstant);इसे संकलित किया जाएगा System.out.println("x");क्योंकि संकलक संकलन समय पर निरंतर का मूल्य जानता है। इस समस्या से छुटकारा पाने के लिए आपको अपने स्थिरांक को रनटाइम पर इनिशियलाइज़ करना होगा final String myConstant = new String("x");। इसके अलावा final int myField = 11उपयोग final int myField = new Integer(11);याfinal Integer myField = 11;
Pshemo

58

यदि किसी static final booleanक्षेत्र को निर्दिष्ट मूल्य संकलन-समय पर जाना जाता है, तो यह एक स्थिर है। आदिम या Stringप्रकार के क्षेत्र संकलित समय-स्थिरांक हो सकते हैं। क्षेत्र को संदर्भित करने वाले किसी भी कोड में एक स्थिरांक को झुका दिया जाएगा। चूंकि क्षेत्र वास्तव में रनटाइम पर नहीं पढ़ा जाता है, इसलिए इसे बदलने से कोई प्रभाव नहीं पड़ेगा।

जावा भाषा विशिष्टता यह कहते हैं:

यदि कोई फ़ील्ड एक स्थिर चर (§4.12.4) है, तो कीवर्ड के अंतिम को हटाने या उसके मूल्य को बदलने से पहले से मौजूद बायनेरिज़ के साथ संगतता नहीं टूट जाएगी, जिसके कारण उन्हें नहीं चलना चाहिए, लेकिन वे उपयोग के लिए कोई नया मान नहीं देखेंगे जब तक वे recompiled हैं क्षेत्र के। यह सच है भले ही उपयोग स्वयं एक संकलन-समय स्थिर अभिव्यक्ति न हो (815.28)

यहाँ एक उदाहरण है:

class Flag {
  static final boolean FLAG = true;
}

class Checker {
  public static void main(String... argv) {
    System.out.println(Flag.FLAG);
  }
}

यदि आप विघटित होते हैं Checker, तो आप देखेंगे कि संदर्भित करने के बजाय Flag.FLAG, कोड केवल trueस्टैक पर 1 ( ) (मान ) 3 का मान बढ़ाता है ।

0:   getstatic       #2; //Field java/lang/System.out:Ljava/io/PrintStream;
3:   iconst_1
4:   invokevirtual   #3; //Method java/io/PrintStream.println:(Z)V
7:   return

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

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

1
यह @polygenel स्नेहक के उत्तर के साथ कैसे करता है, जहां वह बूलियन.फाल्से को फिर से परिभाषित करता है; - लेकिन आप सही हैं, मैंने यह व्यवहार तब देखा है जब चीजें सही तरीके से नहीं मिली थीं।
बिल के

26
@ बिल के - पॉलीजेन लुब्रीकेंट्स के उत्तर में, क्षेत्र एक संकलन समय स्थिर नहीं है। यह public static final Boolean FALSE = new Boolean(false)नहीं हैpublic static final boolean FALSE = false
erickson

17

जावा लैंग्वेज स्पेसिफिकेशन, चैप्टर 17, सेक्शन 17.5.4 "राइट-प्रोटेक्टेड फील्ड्स" से थोड़ी जिज्ञासा:

आम तौर पर, ऐसा क्षेत्र जो अंतिम और स्थैतिक होता है, उसे संशोधित नहीं किया जा सकता है। हालाँकि, System.in, System.out, और System.err स्थिर अंतिम क्षेत्र हैं, जिन्हें विरासत कारणों से, System.setIn, System.setOut, और System.setErr विधियों द्वारा बदलने की अनुमति दी जानी चाहिए। हम इन क्षेत्रों को साधारण अंतिम क्षेत्रों से अलग करने के लिए लिखने-संरक्षित होने के रूप में संदर्भित करते हैं।

स्रोत: http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.5.4


9

मैंने इसे जूर लाइब्रेरी के साथ भी एकीकृत किया

महज प्रयोग करें

      Reflect.on(yourObject).set("finalFieldName", finalFieldValue);

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


जब मैं यह (JDK12) आज़माता हूं, तो मुझे एक अपवाद मिलता है: "अंतिम ___ फ़ील्ड सेट नहीं कर सकता"।
आरोन इबा

@AaronIba जावा 12+ में अब इसकी अनुमति नहीं है।
नैट्स

7

शीर्ष क्रम के उत्तर के साथ आप थोड़ा सरल दृष्टिकोण का उपयोग कर सकते हैं। अपाचे कॉमन्स FieldUtilsक्लास में पहले से ही विशेष विधि है जो सामान कर सकती है। कृपया, FieldUtils.removeFinalModifierविधि पर एक नज़र डालें । आपको लक्ष्य फ़ील्ड आवृत्ति और पहुँच फ़ोरेंसिंग फ़्लैग निर्दिष्ट करना चाहिए (यदि आप गैर-सार्वजनिक फ़ील्ड के साथ खेलते हैं)। अधिक जानकारी आप यहाँ पा सकते हैं ।


वर्तमान में स्वीकृत उत्तर की तुलना में यह बहुत सरल समाधान है
बर्नी

4
क्या यह? एक विधि को कॉपी करना एक संपूर्ण पुस्तकालय को आयात करने की तुलना में एक सरल समाधान की तरह लगता है (जो कि आपके द्वारा कॉपी की जाने वाली विधि के समान काम कर रहा है)।
eski

1
जावा 12+ में काम नहीं करता है:java.lang.UnsupportedOperationException: In java 12+ final cannot be removed.
MrPowerGamerBR

6

सुरक्षा प्रबंधक की उपस्थिति के मामले में, कोई भी इसका उपयोग कर सकता है AccessController.doPrivileged

ऊपर दिए गए उत्तर से एक ही उदाहरण लेते हुए:

import java.lang.reflect.*;

public class EverythingIsTrue {
    static void setFinalStatic(Field field, Object newValue) throws Exception {
        field.setAccessible(true);
        Field modifiersField = Field.class.getDeclaredField("modifiers");

        // wrapping setAccessible 
        AccessController.doPrivileged(new PrivilegedAction() {
            @Override
            public Object run() {
                modifiersField.setAccessible(true);
                return null;
            }
        });

        modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
        field.set(null, newValue);
    }

    public static void main(String args[]) throws Exception {      
      setFinalStatic(Boolean.class.getField("FALSE"), true);
      System.out.format("Everything is %s", false); // "Everything is true"
    }
}

लैम्ब्डा अभिव्यक्ति में AccessController.doPrivileged, को सरल बनाया जा सकता है:

AccessController.doPrivileged((PrivilegedAction) () -> {
    modifiersField.setAccessible(true);
    return null;
});

1
यह भी जावा 12+ के साथ काम नहीं करता है।
dan1st

हाँ @ dan1st, आप सही हैं! कृपया इसे किसी समाधान के लिए देखें: stackoverflow.com/a/56043252/2546381
VanagaS

2

स्वीकृत उत्तर मेरे लिए काम किया जब तक कि JDK 1.8u91 पर तैनात नहीं किया गया। तब मुझे एहसास हुआ कि field.set(null, newValue);जब मैंने कॉल करने से पहले प्रतिबिंब के माध्यम से मूल्य पढ़ा था , तो यह लाइन में विफल रहा थाsetFinalStatic विधि को ।

संभवतः पढ़ने के कारण किसी भी तरह से जावा प्रतिबिंब इंटर्ल्स के अलग-अलग सेटअप होते हैं (अर्थात sun.reflect.UnsafeQualifiedStaticObjectFieldAccessorImplइसके बजाय असफल स्थिति मेंsun.reflect.UnsafeStaticObjectFieldAccessorImpl सफलता के मामले में), लेकिन मैं इसे आगे विस्तार से बता नहीं किया।

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

public static <T> T assignFinalField(Object object, Class<?> clazz, String fieldName, UnaryOperator<T> newValueFunction) {
    Field f = null, ff = null;
    try {
        f = clazz.getDeclaredField(fieldName);
        final int oldM = f.getModifiers();
        final int newM = oldM & ~Modifier.FINAL;
        ff = Field.class.getDeclaredField("modifiers");
        ff.setAccessible(true);
        ff.setInt(f,newM);
        f.setAccessible(true);

        T result = (T)f.get(object);
        T newValue = newValueFunction.apply(result);

        f.set(object,newValue);
        ff.setInt(f,oldM);

        return result;
    } ...

हालांकि सामान्य मामले के लिए यह पर्याप्त नहीं होगा।


2

होते हुए भी final एक क्षेत्र स्थिर इनिशियलाइज़र के बाहर संशोधित किया जा सकता है और (कम से कम जेवीएम हॉटस्पॉट) बिल्टकोड को पूरी तरह से ठीक करेगा।

समस्या यह है कि जावा कंपाइलर इसकी अनुमति नहीं देता है, लेकिन इसका उपयोग करके आसानी से बायपास किया जा सकता है objectweb.asm। यहाँ पूरी तरह से वैध क्लासफाइल है जो कि बायोटेक सत्यापन से गुजरता है और सफलतापूर्वक JVM HotSpot OpenJDK12 के तहत लोड और आरंभीकृत होता है:

ClassWriter cw = new ClassWriter(0);
cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, "Cl", null, "java/lang/Object", null);
{
    FieldVisitor fv = cw.visitField(Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL, "fld", "I", null, null);
    fv.visitEnd();
}
{
    // public void setFinalField1() { //... }
    MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "setFinalField1", "()V", null, null);
    mv.visitMaxs(2, 1);
    mv.visitInsn(Opcodes.ICONST_5);
    mv.visitFieldInsn(Opcodes.PUTSTATIC, "Cl", "fld", "I");
    mv.visitInsn(Opcodes.RETURN);
    mv.visitEnd();
}
{
    // public void setFinalField2() { //... }
    MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "setFinalField2", "()V", null, null);
    mv.visitMaxs(2, 1);
    mv.visitInsn(Opcodes.ICONST_2);
    mv.visitFieldInsn(Opcodes.PUTSTATIC, "Cl", "fld", "I");
    mv.visitInsn(Opcodes.RETURN);
    mv.visitEnd();
}
cw.visitEnd();

जावा में, वर्ग निम्नानुसार बोल रहा है:

public class Cl{
    private static final int fld;

    public static void setFinalField1(){
        fld = 5;
    }

    public static void setFinalField2(){
        fld = 2;
    }
}

जिसे संकलित नहीं किया जा सकता है javac जा सकता है, लेकिन जेवीएम द्वारा लोड और निष्पादित किया जा सकता है।

जेवीएम हॉटस्पॉट ने इस तरह के वर्गों का विशेष उपचार इस अर्थ में किया है कि यह ऐसे "स्थिरांक" को निरंतर तह में भाग लेने से रोकता है। यह जाँच क्लास इनिशियलाइज़ेशन के बाईटेकोड पुनर्लेखन चरण पर की जाती है :

// Check if any final field of the class given as parameter is modified
// outside of initializer methods of the class. Fields that are modified
// are marked with a flag. For marked fields, the compilers do not perform
// constant folding (as the field can be changed after initialization).
//
// The check is performed after verification and only if verification has
// succeeded. Therefore, the class is guaranteed to be well-formed.
InstanceKlass* klass = method->method_holder();
u2 bc_index = Bytes::get_Java_u2(bcp + prefix_length + 1);
constantPoolHandle cp(method->constants());
Symbol* ref_class_name = cp->klass_name_at(cp->klass_ref_index_at(bc_index));
if (klass->name() == ref_class_name) {
   Symbol* field_name = cp->name_ref_at(bc_index);
   Symbol* field_sig = cp->signature_ref_at(bc_index);

   fieldDescriptor fd;
   if (klass->find_field(field_name, field_sig, &fd) != NULL) {
      if (fd.access_flags().is_final()) {
         if (fd.access_flags().is_static()) {
            if (!method->is_static_initializer()) {
               fd.set_has_initialized_final_update(true);
            }
          } else {
            if (!method->is_object_initializer()) {
              fd.set_has_initialized_final_update(true);
            }
          }
        }
      }
    }
}

एकमात्र प्रतिबंध जो जेवीएम हॉटस्पॉट चेक करता है, वह यह है कि finalफ़ील्ड को उस वर्ग के बाहर संशोधित नहीं किया जाना चाहिए जिस पर finalफ़ील्ड घोषित की गई है।


0

बस एक साक्षात्कार साक्षात्कार पर उस प्रश्न को देखा, यदि संभव हो तो प्रतिबिंब के साथ या चर में अंतिम चर को बदलना। वास्तव में दिलचस्पी है, ताकि मैं क्या बन गया:

 /**
 * @author Dmitrijs Lobanovskis
 * @since 03/03/2016.
 */
public class SomeClass {

    private final String str;

    SomeClass(){
        this.str = "This is the string that never changes!";
    }

    public String getStr() {
        return str;
    }

    @Override
    public String toString() {
        return "Class name: " + getClass() + " Value: " + getStr();
    }
}

अंतिम स्ट्रिंग चर के साथ कुछ सरल वर्ग। तो मुख्य वर्ग में आयात java.lang.reflect.Field;

/**
 * @author Dmitrijs Lobanovskis
 * @since 03/03/2016.
 */
public class Main {


    public static void main(String[] args) throws Exception{

        SomeClass someClass = new SomeClass();
        System.out.println(someClass);

        Field field = someClass.getClass().getDeclaredField("str");
        field.setAccessible(true);

        field.set(someClass, "There you are");

        System.out.println(someClass);
    }
}

आउटपुट निम्नानुसार होगा:

Class name: class SomeClass Value: This is the string that never changes!
Class name: class SomeClass Value: There you are

Process finished with exit code 0

प्रलेखन के अनुसार https://docs.oracle.com/javase/tutorial/reflect/member/fieldValues.html


क्या आपने इस पोस्ट को देखा है ?
रवींद्र एचवी

यह प्रश्न एक staticअंतिम फ़ील्ड के बारे में पूछता है , इसलिए यह कोड काम नहीं करता है। setAccessible(true)केवल अंतिम उदाहरण फ़ील्ड सेट करने के लिए काम करता है।
रेडियोडैफ

0

यदि आपका क्षेत्र बस निजी है तो आप यह कर सकते हैं:

MyClass myClass= new MyClass();
Field aField= myClass.getClass().getDeclaredField("someField");
aField.setAccessible(true);
aField.set(myClass, "newValueForAString");

और फेंक / संभाल NoSuchFieldException


-4

पूरे एक बिंदु final फ़ील्ड का यह है कि इसे एक बार सेट करने के बाद पुन: असाइन नहीं किया जा सकता है। JVM विभिन्न स्थानों (जैसे बाहरी चरों को संदर्भित करने वाली आंतरिक कक्षाएं) में स्थिरता बनाए रखने के लिए इस ग्वारेंटी का उपयोग करता है। तो नहीं। ऐसा करने में सक्षम होने के कारण JVM टूट जाएगा!

इसका समाधान यह नहीं है कि इसे finalपहले घोषित किया जाए ।


4
इसके अलावा, finalमल्टीथ्रेडेड निष्पादन में एक विशेष भूमिका है - बदलते finalमूल्य जावा मेमोरी मॉडल को भी तोड़ देंगे।
पेटर तोलुक

1
और घोषित नहीं किया गया एक क्षेत्र घोषित नहीं किया finalजाना चाहिए static
टॉम हॉकिन -

2
@ टॉम: सामान्य तौर पर यह शायद सच है, लेकिन मैं सभी स्थिर परिवर्तनशील चरों को बदल नहीं सकता।
bcat

7
@ टोम: क्या आपने कभी पढ़ा कि सिंगलनेट बुराई क्यों हैं? मैंने किया! अब मुझे पता है कि वे केवल जावा में बुराई करते हैं। और केवल एक उपयोगकर्ता परिभाषित क्लास लोडर की उपलब्धता के कारण। और जब से मैं यह सब जानता हूं और मैं उपयोगकर्ता को परिभाषित क्लास लोडर का उपयोग नहीं करता हूं, मैं बिना किसी खेद के सिंगललेट का उपयोग करता हूं। और ऐसा स्काला करता है जहां सिंगलटन एक प्रथम श्रेणी की भाषा की विशेषता है - यह एकल गीत बुराई है एक प्रसिद्ध मिथ्या मिथक है
मार्टिन

3
@ मर्टिन मुझे पता है कि आपकी टिप्पणी पुरानी है, और शायद आपके विचार अब तक बदल गए हैं, लेकिन मुझे लगा कि मैं सिर्फ यही जोड़ूंगा: सिंगलेट्स उन कारणों से बुरे हैं जिनका जावा से कोई लेना-देना नहीं है। वे आपके कोड में छिपी हुई जटिलता को जोड़ते हैं । इसके अतिरिक्त, वे यह जानकर भी बिना इकाई परीक्षण के असंभव बना सकते हैं कि एन सिंगलनेट को भी पहले कॉन्फ़िगर किया जाना चाहिए। वे निर्भरता इंजेक्शन के विरोधी हैं। आपकी टीम यह निर्णय ले सकती है कि छिपी हुई जटिलता के नुकसान सिंग्लेटों की सुविधा से कम नहीं हैं, लेकिन कई टीमें अच्छे कारण के लिए विपरीत रुख अपनाती हैं।
क्रश करें
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.