জাভা প্রতিবিম্ব ব্যবহার করে ব্যক্তিগত স্ট্যাটিক চূড়ান্ত ক্ষেত্র পরিবর্তন করুন


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
এমন বাজে ধারণা। আমি এর পরিবর্তে উত্সটি পেতে এবং পুনরায় কম্পাইল করার চেষ্টা করব (বা এমনকি ডিকম্পাইল / পুনর্নির্মাণ)।
বিল কে

System.out একটি সর্বজনীন স্থির চূড়ান্ত ক্ষেত্র, তবে এটিও পরিবর্তন করা যেতে পারে।
অপরিবর্তনীয়

19
@irreputable System.out/in/errএতটা "বিশেষ" যে জাভা মেমোরি মডেলগুলিতে তাদের বিশেষ উল্লেখ করতে হবে। তারা অনুসরণ করা উচিত উদাহরণ নয়।
টম হাটিন -

8
আমার পয়েন্ট ডাব্লুএস এর মধ্যে একটি হ্যাক সন্ধান করার জন্য আমার অ্যাপ্লিকেশনটি কাজ করার আগ পর্যন্ত কাজ করতে হবে যতক্ষণ না পরের রিলিজের সময়ে আমার আর হ্যাক করার দরকার নেই ...
ফিক্সটাগেইন

1
@ বিল কে দশ বছর আগে থেকে: এটি পুনরায় সংকলন করা মহান হবে তবে এটি একটি মোতায়েন করা সিস্টেমে রয়েছে এবং যতক্ষণ না আমরা মোতায়েন অ্যাপটিকে আপডেট করতে পারি না ততক্ষণ আমার এটি প্যাচ করা দরকার!
বিল কে

উত্তর:


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স্বনির্ধারিত টাইপগুলিতে অটোবক্স হয়BooleanBoolean.TRUEBoolean.FALSE
  • প্রতিবিম্ব দ্বারা চিহ্নিত public static final Boolean.FALSEরেফারেন্স পরিবর্তন করতে ব্যবহৃত Booleanহয়Boolean.TRUE
  • ফলস্বরূপ, পরবর্তীতে যখনই একটি falseঅটোবক্স হয়Boolean.FALSE , এটি একই বোঝায় Booleanএকের পর নামে পরিচিত যেমনBoolean.TRUE
  • যা ছিল সব "false" এখন"true"

সম্পর্কিত প্রশ্নাবলী


আদেশ সহকারে

আপনি যখনই এরকম কিছু করেন তখন চরম যত্ন নেওয়া উচিত। এটি SecurityManagerউপস্থিত হতে পারে কারণ একটি উপস্থিত থাকতে পারে, তবে এটি ব্যবহার না করে, প্যাটার্নের উপর নির্ভর করে এটি কাজ করতেও পারে বা নাও পারে।

জেএলএস 17.5.3 চূড়ান্ত ক্ষেত্রগুলির পরবর্তী পরিবর্তন

কিছু ক্ষেত্রে যেমন ডিসরিয়ালাইজেশন, সিস্টেমকে finalনির্মাণের পরে কোনও বস্তুর ক্ষেত্র পরিবর্তন করতে হবে । finalপ্রতিবিম্ব এবং অন্যান্য বাস্তবায়ন নির্ভর উপায়ের মাধ্যমে ক্ষেত্রগুলি পরিবর্তন করা যেতে পারে। কেবলমাত্র প্যাটার্নটিতে এটিতে যুক্তিসঙ্গত শব্দার্থবিজ্ঞান রয়েছে এটি হ'ল একটি বস্তু যা নির্মিত হয় এবং তারপরে finalঅবজেক্টের ক্ষেত্রগুলি আপডেট হয় updated অবজেক্টটি অন্যান্য থ্রেডগুলিতে দৃশ্যমান করা উচিত নয় এবং 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";
}

এই উত্তরটি সম্পর্কে মন্তব্যগুলি পড়ুন, বিশেষত @ ফেমো দ্বারা লেখা, এটি আমাকে মনে করিয়ে দিয়েছে যে কনস্ট্যান্ট এক্সপ্রেশনগুলি ভিন্নভাবে পরিচালিত হয় সুতরাং এটি পরিবর্তন করা অসম্ভব । অতএব আপনার এই কোডটি দেখতে আপনার কোডটি পরিবর্তন করতে হবে:

public class A {
    private final String myVar;

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

আপনি যদি শ্রেণীর মালিক না হন ... আমি আপনাকে অনুভব করি!

এই আচরণটি কেন এটি পড়তে হবে সে সম্পর্কে আরও তথ্যের জন্য ?


41
@ থিকোপ, @ হালফব্রায়ান: সন্দেহ নেই যে এটি অত্যন্ত দুষ্টু , কিন্তু এই উদাহরণটি ডিজাইন দ্বারা বেছে নেওয়া হয়েছিল। আমার উত্তরটি কেবলমাত্র কিছু পরিস্থিতিতে কীভাবে এটি সম্ভব তা দেখায়। আমি সবচেয়ে ঘৃণ্য উদাহরণটি যা ভাবতে পারি তা হ'ল এই প্রত্যাশার সাথে বেছে নেওয়া হয়েছে যে সম্ভবত কৌশলগুলি প্রেমে পড়ার পরিবর্তে লোকেরা তাত্ক্ষণিকভাবে বিরক্ত হবে।
পলিজেনুব্রিকেন্ট

59
ইও, ডগ আমি আপনাকে প্রতিবিম্বের মতো শুনেছি, তাই আমি ফিল্ডে প্রতিবিম্বিত করেছি যাতে আপনি প্রতিফলিত হওয়ার সময় প্রতিবিম্বিত করতে পারেন।
ম্যাথু ফ্ল্যাশেন

11
মনে রাখবেন যে বুলিয়ান.ফালএসআই ব্যক্তিগত নয় oes এটি কি "ব্যক্তিগত চূড়ান্ত স্ট্যাটিক" সদস্যদের সাথে কাজ করে?
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;
আদিমগুলির

58

যদি কোনও static final booleanক্ষেত্রের জন্য নির্ধারিত মানটি সংকলন সময়ে জানা যায় তবে এটি একটি ধ্রুবক। আদিম ক্ষেত্র বা String প্রকারের সংকলন-সময় ধ্রুবক হতে পারে। ক্ষেত্রের উল্লেখ করে যে কোনও কোডে একটি ধ্রুবক অন্তর্ভুক্ত করা হবে। যেহেতু ক্ষেত্রটি আসলে রানটাইমে পড়া হয় না তাই এটি পরিবর্তন করার পরে কোনও প্রভাব পড়বে না।

জাভা ল্যাঙ্গুএজ স্পেসিফিকেশন এই বলে:

যদি ক্ষেত্রটি একটি স্থির পরিবর্তনশীল (§4.12.4) হয়, তবে কীওয়ার্ডটি চূড়ান্ত করা বা এর মান পরিবর্তন করা পূর্ব-বিদ্যমান বাইনারিগুলির সাথে চালনা না করায় সামঞ্জস্যতা ভঙ্গ করবে না, তবে তারা ব্যবহারের জন্য কোনও নতুন মান দেখতে পাবে না ক্ষেত্রের যদি না তারা পুনরায় সংযুক্ত না হয়। এমনকি যদি ব্যবহারটি নিজেই কোনও সংকলন-সময় ধ্রুবক অভিব্যক্তি না হয় (1515 is)

এখানে একটি উদাহরণ:

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) উপরে কেবল 1 ( ) এর মান দেয় ।

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
এই পোলিজেলিউব্রিকেন্টস এর উত্তর দিয়ে কীভাবে তিনি বুলিয়ান.ফালসকে নতুন সংজ্ঞা দিয়েছিলেন? - তবে আপনি সঠিক, আমি যখন এই জিনিসগুলি সঠিকভাবে পুনরায় সংকলন করিনি তখন আমি এই আচরণটি দেখেছি।
বিল কে

26
@ বিল কে - পলিজেনলুব্রিকেন্টসের উত্তরে, ক্ষেত্রটি কোনও সংকলনের সময় ধ্রুবক নয়। এটি public static final Boolean FALSE = new Boolean(false)নয়public static final boolean FALSE = false
এরিকসন

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যার সাথে পূর্ববর্তী সমাধানগুলি মিস হচ্ছে বলে মনে হচ্ছে। তবে এটি খুব সাবধানে ব্যবহার করুন, কেবল তখনই যখন অন্য কোনও ভাল সমাধান হয় না।


যখন আমি এটি (জেডিকে 12) চেষ্টা করি তখন আমি একটি ব্যতিক্রম পাই: "চূড়ান্ত ___ ক্ষেত্র সেট করতে পারি না"।
হারুন ইবা

@ আরোনআইবা এটি আর জাভা 12+ এ অনুমোদিত নয়।
নাটস

7

শীর্ষ স্থানযুক্ত উত্তরের সাথে আপনি কিছুটা সহজ পদ্ধতির ব্যবহার করতে পারেন। অ্যাপাচি কমন্স FieldUtilsক্লাসে ইতিমধ্যে নির্দিষ্ট পদ্ধতি রয়েছে যা স্টাফ করতে পারে। দয়া করে FieldUtils.removeFinalModifierপদ্ধতিটি একবার দেখুন । আপনার লক্ষ্য ক্ষেত্রের উদাহরণ এবং অ্যাক্সেসিবিলিটি বাধ্যতামূলক পতাকাটি নির্দিষ্ট করা উচিত (আপনি যদি সর্বজনীন ক্ষেত্রের সাথে খেলেন)। আরও তথ্য আপনি এখানে পেতে পারেন ।


এটি বর্তমানে গৃহীত উত্তরের চেয়ে অনেক সহজ সমাধান
বার্নি

4
তাই কি? একটি পদ্ধতি অনুলিপি করা সম্পূর্ণ লাইব্রেরি আমদানির চেয়ে সহজ সমাধান বলে মনে হচ্ছে (যা আপনি অনুলিপি করছেন সেই পদ্ধতির মতোই এটি করছে)।
এসকি

1
জাভা 12+ এ কাজ করে না:java.lang.UnsupportedOperationException: In java 12+ final cannot be removed.
মিঃপাওয়ারগেমারবিআর

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

জেডিকে 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। এখানে পুরোপুরি বৈধ ক্লাসফাইল যা বাইকোড যাচাইকরণটি পাস করে এবং জেভিএম হটস্পট ওপেনজেডি কে 12 এর অধীনে সাফল্যের সাথে লোড এবং আর্কিটাইজড:

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 ক্ষেত্রের হ'ল এটি একবার সেট হয়ে গেলে তাকে পুনরায় নিয়োগ দেওয়া যাবে না। জেভিএম বিভিন্ন স্থানে অবিচ্ছিন্নতা বজায় রাখতে এই গ্যারান্টি ব্যবহার করে (যেমন বাইরের ভেরিয়েবলগুলি উল্লেখ করে অভ্যন্তরীণ শ্রেণিগুলি)। তাই না এমনটা করতে পারলে জেভিএম ভেঙে যাবে!

সমাধানটি finalপ্রথম স্থানে এটি ঘোষণা করা নয় ।


4
অধিকন্তু, finalমাল্টিথ্রেডেড মৃত্যুদন্ড কার্যকর করার ক্ষেত্রে বিশেষ ভূমিকা আছে - finalমান পরিবর্তন করা জাভা মেমরির মডেলটিকেও ভেঙে দেবে।
পটার তারেক

1
আর একটি ক্ষেত্র ঘোষণা করা finalঘোষণা করা উচিত নয় static
টম হাটিন -

2
@ টম: সাধারণভাবে এটি সম্ভবত সত্য, তবে আমি সমস্ত স্ট্যাটিক পরিবর্তনশীল ভেরিয়েবলগুলিকে নিষিদ্ধ করব না ।
বি কেট

7
@ টম: আপনি কি কখনও পড়তে পেরেছেন যে সিলেটলেটগুলি কেন খারাপ? আমি করেছিলাম! এখন আমি জানি যে তারা কেবল জাভাতে খারাপ। এবং কেবলমাত্র কোনও ব্যবহারকারী সংজ্ঞায়িত শ্রেণি লোডার এর avilabilty এর কারণে। এবং যেহেতু আমি এগুলি সব জানি এবং আমি ব্যবহারকারী সংজ্ঞায়িত শ্রেণি লোডার ব্যবহার করি না আমি দুঃখ ছাড়াই সিঙ্গলেটগুলি ব্যবহার করি। এবং একইভাবে স্কেল যেখানে সিঙ্গেলটন প্রথম শ্রেণীর ভাষার বৈশিষ্ট্য sing যে একক শত্রুরা মন্দ তা হ'ল একটি বহুল প্রচলিত মিথ
মার্টিন

3
@ মার্টিন আমি জানি যে আপনার মন্তব্যটি পুরানো, এবং সম্ভবত আপনার মতামত এখনই পরিবর্তিত হয়েছে, তবে আমি ভেবেছিলাম যে আমি কেবল এটি যুক্ত করব: সিঙ্গলেটগুলি জাভাটির সাথে কোনও সম্পর্কযুক্ত না হওয়ার কারণে খারাপ। তারা আপনার কোডটিতে লুকানো জটিলতা যুক্ত করে । এছাড়াও, এন সিলেটলেটগুলিও প্রথমে কনফিগার করা উচিত তা জেনেও তারা পরীক্ষার একক তৈরি করা অসম্ভব করে তুলতে পারে। এগুলি নির্ভরতা ইনজেকশনের বিরোধী। আপনার দল সিদ্ধান্ত নিতে পারে যে গোপন জটিলতার সমস্যাগুলি সিঙ্গলটনের সুবিধার চেয়ে বেশি নয়, তবে অনেক দলই সঙ্গত কারণে বিপরীত অবস্থান গ্রহণ করে।
ক্রাশ করুন
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.