একটি জাভা স্ট্রিং আসলেই পরিবর্তনযোগ্য?


399

আমরা সকলেই জানি যা Stringজাভাতে পরিবর্তনযোগ্য, তবে নিম্নলিখিত কোডটি পরীক্ষা করে দেখুন:

String s1 = "Hello World";  
String s2 = "Hello World";  
String s3 = s1.substring(6);  
System.out.println(s1); // Hello World  
System.out.println(s2); // Hello World  
System.out.println(s3); // World  

Field field = String.class.getDeclaredField("value");  
field.setAccessible(true);  
char[] value = (char[])field.get(s1);  
value[6] = 'J';  
value[7] = 'a';  
value[8] = 'v';  
value[9] = 'a';  
value[10] = '!';  

System.out.println(s1); // Hello Java!  
System.out.println(s2); // Hello Java!  
System.out.println(s3); // World  

এই প্রোগ্রামটি কেন এভাবে পরিচালিত হয়? এবং কেন মান s1এবং s2পরিবর্তিত হয়, কিন্তু না s3?


394
প্রতিবিম্ব সহ আপনি সমস্ত ধরণের মূ .় কৌশল করতে পারেন। তবে আপনি ক্লাসে যে তাত্ক্ষণিক কাজটি করেন তা ততক্ষণে আপনি "ওয়ারেন্টি অকার্যকর থাকলে অপসারণ করা" স্টিকারটি ভঙ্গ করছেন।
সিএওও

16
@ দর্শনপ্যাটেল প্রতিবিম্ব অক্ষম করতে সিকিউরিটি ম্যানেজার ব্যবহার করুন
সান প্যাট্রিক ফ্লয়েড

39
যদি আপনি সত্যিই (Integer)1+(Integer)2=42কোনও জিনিসগুলির সাথে ঝামেলা করতে চান তবে আপনি এটিকে এটি তৈরি করতে পারেন যাতে ক্যাশেড অটোবক্সিংয়ের সাথে জগাখিচির মাধ্যমে; (অসন্তুষ্ট-বোমা-জাভা-সংস্করণ) ( thedailywtf.com/Articles/Disgruntled-Bomb-Java-Edition.aspx )
রিচার্ড টিংলে

15
আপনি এই উত্তরটি দেখে বিস্মিত হতে পারেন আমি প্রায় 5 বছর আগে লিখেছিলাম stackoverflow.com/a/1232332/27423 - এটি সি # তে পরিবর্তনযোগ্য তালিকার কথা তবে এটি মূলত একই জিনিস: আমি কীভাবে ব্যবহারকারীদের আমার ডেটা পরিবর্তন করতে বাধা দেব? এবং উত্তর, আপনি পারবেন না; প্রতিবিম্ব এটি খুব সহজ করে তোলে। মূলধারার একটি ভাষায় যে সমস্যাটি নেই এটি হ'ল জাভাস্ক্রিপ্ট, কারণ এতে কোনও প্রতিবিম্ব সিস্টেম নেই যা বন্ধের অভ্যন্তরে স্থানীয় ভেরিয়েবলগুলি অ্যাক্সেস করতে পারে, তাই ব্যক্তিগতভাবে ব্যক্তিগতটির অর্থ ব্যক্তিগত (যদিও এর কোনও কীওয়ার্ড নেই!)
ড্যানিয়েল আর্উইকার

49
কেউ কি শেষ পর্যন্ত প্রশ্ন পড়ছে ?? প্রশ্নটি হল, দয়া করে আমাকে পুনরাবৃত্তি করুন: "কেন এই প্রোগ্রামটি এভাবে চলবে? এস 1 এবং এস 2 এর মান কেন পরিবর্তন হয় এবং এস 3 এর পরিবর্তিত হয় না?" প্রশ্নটি নয় কেন এস 1 এবং এস 2 পরিবর্তিত হয়! প্রশ্নটি হল: এস 3 কেন পরিবর্তন হয়নি?
রোল্যান্ড পিহলাকাস

উত্তর:


403

String অপরিবর্তনীয় * তবে এর অর্থ হ'ল আপনি এটির সর্বজনীন এপিআই ব্যবহার করে এটি পরিবর্তন করতে পারবেন না।

আপনি এখানে যা করছেন তা প্রতিবিম্বটি ব্যবহার করে সাধারণ API এড়িয়ে চলে। একইভাবে, আপনি এনামগুলির মান পরিবর্তন করতে পারেন, পূর্ণসংখ্যার অটোবক্সিংয়ে ব্যবহৃত লুকিং টেবিল পরিবর্তন করতে পারেন etc.

এখন, কারণ s1এবং s2পরিবর্তনের মানটি হ'ল তারা উভয়ই একই ইন্টার্নযুক্ত স্ট্রিংকে বোঝায়। সংকলক এটি করে (অন্যান্য উত্তর দ্বারা উল্লিখিত)।

কারণ s3নেই না আসলে একটু আমাকে বিস্ময়কর ছিল, যেমন আমি ভেবেছিলাম এটা ভাগ হবে valueঅ্যারে ( এটা জাভার পূর্ববর্তী সংস্করণ করেছিল , জাভা 7u6 আগে)। তবে এর উত্স কোডটি Stringদেখে আমরা দেখতে পাচ্ছি যে valueসাবস্ট্রিংয়ের জন্য অক্ষর অ্যারেটি আসলে অনুলিপি করা হয়েছে (ব্যবহার করে Arrays.copyOfRange(..))। এ কারণেই এটি অপরিবর্তিত থাকে।

এই জাতীয় SecurityManagerকাজগুলিতে দূষিত কোড এড়ানোর জন্য আপনি একটি ইনস্টল করতে পারেন । তবে মনে রাখবেন যে কয়েকটি গ্রন্থাগার এই ধরণের প্রতিবিম্ব কৌশলগুলি (সাধারণত ওআরএম সরঞ্জামগুলি, এওপি লাইব্রেরি ইত্যাদি) ব্যবহারের উপর নির্ভর করে।

*) আমি প্রথমে লিখেছিলাম যে Stringগুলি আসলেই পরিবর্তনযোগ্য নয়, কেবল "কার্যকর অপরিবর্তনীয়"। এটি বর্তমান বাস্তবায়নে বিভ্রান্তিকর হতে পারে String, যেখানে valueঅ্যারেটি সত্যই চিহ্নিত করা হয়েছে private final। এটি এখনও লক্ষণীয়, যদিও জাভাতে কোনও অ্যারেকে অপরিবর্তনীয় হিসাবে ঘোষণা করার কোনও উপায় নেই, তাই সঠিক অ্যাক্সেস পরিবর্তনকারী এমনকি এমনকি এটির শ্রেণীর বাইরে প্রকাশ না করার জন্য যত্ন নেওয়া উচিত care


এই বিষয়টিকে অত্যধিক জনপ্রিয় বলে মনে হচ্ছে, এখানে আরও কিছু পড়ার পরামর্শ দেওয়া হয়েছে: জাভাজোন ২০০৯ থেকে হাইঞ্জ কাবুটজের প্রতিচ্ছবি ম্যাডনেস টক , যা ওপিতে প্রচুর বিষয়গুলি জুড়েছে, অন্য প্রতিচ্ছবি সহ ... ভাল ... উন্মাদনা।

এটি কখনও কখনও কেন দরকারী তা জুড়ে। এবং কেন, বেশিরভাগ সময় আপনার এড়ানো উচিত। :-)


7
প্রকৃতপক্ষে, Stringইন্টার্নিং জেএলএসের অংশ ( "একটি স্ট্রিং আক্ষরিক সর্বদা স্ট্রিংয়ের একই উদাহরণটিকে বোঝায়" )। তবে আমি একমত, Stringশ্রেণীর প্রয়োগের বিবরণ গণনা করা ভাল অভ্যাস নয় ।
হেরাল্ডকে

3
সম্ভবত কারণগুলি substringঅনুলিপিটি বিদ্যমান অ্যারের "বিভাগ" ব্যবহার না করার পরিবর্তে হ'ল অন্যথায় যদি আমার কাছে বিশাল স্ট্রিং থাকে sএবং tএটি থেকে একটি ছোট্ট ছোট্ট স্ট্রিং বের করে আনে এবং আমি পরে ছেড়ে চলে যাই sতবে রেখে দেওয়া হয় t, তবে বিশাল অ্যারেটি জীবিত রাখা হত (আবর্জনা সংগ্রহ করা হয়নি)। সুতরাং প্রতিটি স্ট্রিংয়ের মানটির নিজস্ব অ্যাરેযুক্তি থাকা আরও প্রাকৃতিক?
জেপ্প স্টিগ নীলসন

10
স্ট্রিং এবং এর সাবস্ট্রিংগুলির মধ্যে অ্যারে ভাগ করে নেওয়াও বোঝায় যে প্রতিটি String উদাহরণকে রেফারিত অ্যারে এবং দৈর্ঘ্যের মধ্যে অফসেট মনে রাখার জন্য ভেরিয়েবল বহন করতে হয়েছিল। স্ট্রিংয়ের মোট সংখ্যা এবং একটি অ্যাপ্লিকেশনটিতে সাধারণ স্ট্রিং এবং সাবস্ট্রিংগুলির মধ্যে আদর্শ অনুপাতের ভিত্তিতে এড়াতে হবে না এমন একটি ওভারহেড। যেহেতু তাদের প্রতিটি স্ট্রিং অপারেশনের জন্য মূল্যায়ন করতে হয়েছিল তার অর্থ প্রতিটি স্ট্রিং অপারেশনটি কেবল একটি ক্রিয়াকলাপের জন্য, একটি সস্তা সাবস্ট্রিংয়ের সুবিধার জন্য ধীর করে দেওয়া
হোলার

2
@ হোলজার - হ্যাঁ, আমার বোঝার বিষয়টি হল যে সাম্প্রতিক জেভিএমগুলিতে অফসেট ক্ষেত্রটি বাদ পড়েছে। এমনকি এটি উপস্থিত থাকাকালীন এটি প্রায়শই ব্যবহৃত হয় না।
হট লিক্স

2
@ সুপের্যাট: আপনার নেটিভ কোড রয়েছে কিনা তা বিবেচ্য নয়, একই জেভিএমের মধ্যে স্ট্রিং এবং সাবস্ট্রিংয়ের জন্য আলাদা বাস্তবায়ন রয়েছে বা byte[]এএসসিআইআই স্ট্রিংগুলির char[]জন্য স্ট্রিং রয়েছে এবং অন্যদের জন্য বোঝায় যে প্রতিটি ক্রিয়াকলাপটি আগে কোন ধরণের স্ট্রিং রয়েছে তা যাচাই করতে হবে অপারেটিং। এই স্ট্রিংগুলি ব্যবহার করে পদ্ধতিগুলিতে কোডটি প্রবেশের পথে বাধা দেয় যা কলারের প্রসঙ্গ তথ্য ব্যবহার করে আরও অনুকূলিতকরণের প্রথম ধাপ। এটি একটি বড় প্রভাব।
হোলার

93

জাভাতে, যদি দুটি স্ট্রিং প্রিমিটিভ ভেরিয়েবল একই আক্ষরিক সাথে আরম্ভ করা হয় তবে এটি উভয় ভেরিয়েবলের জন্য একই রেফারেন্স বরাদ্দ করে:

String Test1="Hello World";
String Test2="Hello World";
System.out.println(test1==test2); // true

আরম্ভ

সেই কারণেই তুলনাটি সত্য হয়। তৃতীয় স্ট্রিং ব্যবহার করে তৈরি করা হয়েছে substring()যা একই দিকে নির্দেশ করার পরিবর্তে একটি নতুন স্ট্রিং তৈরি করে ।

সাব স্ট্রিং

আপনি যখন প্রতিবিম্ব ব্যবহার করে একটি স্ট্রিং অ্যাক্সেস করেন, আপনি আসল পয়েন্টার পাবেন:

Field field = String.class.getDeclaredField("value");
field.setAccessible(true);

সুতরাং এটিতে পরিবর্তনটি এটিতে একটি পয়েন্টার ধারণ করে স্ট্রিং পরিবর্তন করবে, তবে s3নতুন স্ট্রিংয়ের সাথে তৈরি হওয়ার কারণে substring()এটি পরিবর্তিত হবে না।

পরিবর্তন


এটি কেবল আক্ষরিক জন্য কাজ করে এবং একটি সংকলন-সময় অপ্টিমাইজেশন।
স্পেসপ্রেজ

2
@ জাফড 42 সত্য নয় আপনি internঅ-আক্ষরিক স্ট্রিংয়ে ম্যানুয়ালি কল করতে পারেন এবং সুবিধাগুলি কাটাতে পারেন।
ক্রিস হেইস

নোট, যদিও: আপনি ন্যায়বিচার ব্যবহার করতে চান intern। সমস্ত কিছুকে অভ্যন্তরীণ করা আপনার খুব বেশি লাভ করে না এবং আপনি মিশ্রণে প্রতিচ্ছবি যুক্ত করার সময় কিছু মাথা-ঘোরানো মুহুর্তের উত্স হতে পারেন।
সিএইচও

Test1এবং Test1সঙ্গে সঙ্গতিহীন হয় test1==test2এবং জাভা নামকরণ নিয়মাবলী অনুসরণ করো না।
c0der

50

আপনি স্ট্রিংয়ের অপরিবর্তনীয়তা রোধ করতে প্রতিফলন ব্যবহার করছেন - এটি "আক্রমণ" এর একটি রূপ।

আপনি এরকম অনেকগুলি উদাহরণ তৈরি করতে পারেন (উদাহরণস্বরূপ আপনি এমনকি কোনও Voidবস্তুকে ইনস্ট্যান্ট করতেও পারেন ), তবে এর অর্থ এই নয় যে স্ট্রিং "অপরিবর্তনীয়" নয়।

এমন ব্যবহারের ক্ষেত্রে রয়েছে যেখানে এই ধরণের কোডটি আপনার সুবিধার জন্য ব্যবহার করা যেতে পারে এবং "ভাল কোডিং" হতে পারে, যেমন সম্ভবতম মুহুর্তে (জিসির আগে) মেমরি থেকে পাসওয়ার্ড সাফ করা

সুরক্ষা ব্যবস্থাপকের উপর নির্ভর করে আপনি আপনার কোডটি কার্যকর করতে পারবেন না।


30

আপনি স্ট্রিং অবজেক্টের "প্রয়োগের বিশদ" অ্যাক্সেস করতে প্রতিবিম্বটি ব্যবহার করছেন। অপরিবর্তনীয়তা হ'ল কোনও বস্তুর পাবলিক ইন্টারফেসের বৈশিষ্ট্য।


24

দৃশ্যমানতা পরিবর্তনকারী এবং চূড়ান্ত (অর্থাত অপরিবর্তনীয়তা) জাভাতে দূষিত কোডের বিরুদ্ধে পরিমাপ নয়; এগুলি কেবল ভুল থেকে রক্ষা করার জন্য এবং কোডটিকে আরও রক্ষণাবেক্ষণ করার জন্য (সিস্টেমের অন্যতম বৃহত বিক্রয় কেন্দ্র) tools এজন্য আপনি অভ্যন্তরীণ প্রয়োগের বিশদটি Stringপ্রতিবিম্বের মাধ্যমে ব্যাকিং চর অ্যারের মতো অ্যাক্সেস করতে পারবেন ।

আপনি যে দ্বিতীয় প্রভাবটি দেখেন তা হ'ল সমস্ত Stringপরিবর্তন হয় যখন দেখায় যে আপনি কেবল পরিবর্তন করেন s1। এটি জাভা স্ট্রিং লিটারেলের একটি নির্দিষ্ট সম্পত্তি যা তারা স্বয়ংক্রিয়ভাবে অভ্যন্তরীণ হয়, অর্থাৎ ক্যাশেড। একই মান সহ দুটি স্ট্রিং লিটারাল আসলে একই জিনিস হবে। আপনি যখন newএটির সাথে একটি স্ট্রিং তৈরি করবেন তখন স্বয়ংক্রিয়ভাবে অভ্যন্তরীণ হবে না এবং আপনি এই প্রভাবটি দেখতে পাবেন না।

#substringসাম্প্রতিক অবধি (জাভা 7u6) একইভাবে কাজ করেছে, যা আপনার প্রশ্নের মূল সংস্করণে আচরণটি ব্যাখ্যা করবে। এটি কোনও নতুন ব্যাকিং চর অ্যারে তৈরি করে নি তবে মূল স্ট্রিং থেকে আবার ব্যবহার করেছে; এটি কেবলমাত্র একটি নতুন স্ট্রিং অবজেক্ট তৈরি করেছে যা সেই অ্যারের কেবলমাত্র একটি অংশ উপস্থাপন করতে অফসেট এবং দৈর্ঘ্য ব্যবহার করেছিল। এটি স্ট্রিংস যেমন অপরিবর্তনীয় হিসাবে সাধারণত কাজ করে - আপনি যদি তা না ছড়িয়ে দেন। এর এই সম্পত্তিটির #substringঅর্থ হ'ল যে এর থেকে তৈরি একটি ছোট্ট স্ট্রস্ট্রিং এখনও বিদ্যমান থাকলে পুরো আসল স্ট্রিংটি আবর্জনা সংগ্রহ করা যায় না।

বর্তমান জাভা এবং প্রশ্নের বর্তমান সংস্করণ হিসাবে আপনার কোনও আশ্চর্য আচরণ নেই #substring


2
আসলে, দৃশ্যমানতা সংশোধনকারীদের হয় (বা অন্তত ছিল) সুরক্ষা againts ক্ষতিকারক কোড হিসাবে উদ্দীষ্ট - তবে, আপনি যদি একটি SecurityManager (System.setSecurityManager ()) সুরক্ষা সক্রিয় করতে সেট করতে হবে। এটি আসলে কতটা সুরক্ষিত তা অন্য প্রশ্ন ...
স্লেসকে

2
একটি আপভোটের দাবিদার কারণ আপনি জোর দিয়েছিলেন যে অ্যাক্সেস মডিফায়ারগুলি কোডটি 'সুরক্ষা' দেওয়ার উদ্দেশ্যে নয় । এটি জাভা এবং .NET উভয় ক্ষেত্রেই ব্যাপকভাবে ভুল বোঝাবুঝি বলে মনে হচ্ছে। যদিও আগের মন্তব্যটি এর বিরোধিতা করে না; আমি জাভা সম্পর্কে খুব বেশি জানি না, তবে। নেট এ অবশ্যই সত্য। কোনও ভাষায়ই ব্যবহারকারীদের ধরে নেওয়া উচিত নয় যে এটি তাদের কোড হ্যাক-প্রুফ করে।
টম ডাব্লু

finalপ্রতিবিম্বের মাধ্যমেও চুক্তি লঙ্ঘন করা সম্ভব নয় । এছাড়াও, জাভা 7u6 যেহেতু অন্য উত্তরে উল্লিখিত হয়েছে, #substringঅ্যারে ভাগ করে না।
ntoskrnl

প্রকৃতপক্ষে, সময়ের সাথে এর আচরণ finalবদলেছে ...: -ও হেইঞ্জের "প্রতিবিম্ব ম্যাডনেস" আলাপ অনুসারে আমি অন্য থ্রেডে পোস্ট করেছি, যার finalঅর্থ ফাইনাল জেডিকে ১.১, ১.৩ এবং ১.৪ এ ছিল, তবে সর্বদা ১.২ ব্যবহার করে প্রতিচ্ছবি ব্যবহার করে পরিবর্তন করা যেতে পারে , এবং 1.5 এবং 6 বেশিরভাগ ক্ষেত্রে ...
হেরাল্ডকে

1
finalnativeসিরিয়ালাইজড ইনফর্মেন্সের ক্ষেত্রগুলি পড়ার পাশাপাশি System.setOut(…)চূড়ান্ত System.outভেরিয়েবলটি সংশোধন করার সময় সিরিয়ালাইজেশন কাঠামোর দ্বারা করা কোডের মাধ্যমে ক্ষেত্রগুলি পরিবর্তন করা যেতে পারে । পরেরটি সবচেয়ে আকর্ষণীয় বৈশিষ্ট্য কারণ অ্যাক্সেস ওভাররাইড সহ প্রতিচ্ছবি static finalক্ষেত্রগুলি পরিবর্তন করতে পারে না ।
হলগার

11

স্ট্রিং অপরিবর্তনীয়তা ইন্টারফেস দৃষ্টিকোণ থেকে। আপনি ইন্টারফেসটি বাইপাস করতে এবং স্ট্রিং ইনস্টেন্সগুলির ইন্টার্নালগুলি সরাসরি সংশোধন করতে প্রতিবিম্বটি ব্যবহার করছেন।

s1এবং s2উভয়ই পরিবর্তিত হয়েছে কারণ তারা উভয়ই একই "ইন্টার্ন" স্ট্রিংয়ের ক্ষেত্রে বরাদ্দ করা হয়েছে। স্ট্রিং সমতা এবং ইন্টার্নিং সম্পর্কে এই নিবন্ধ থেকে আপনি সেই অংশটি সম্পর্কে আরও কিছু জানতে পারেন । আপনার স্যাম্পল কোডটিতে, এটি ফিরে পেয়ে আপনি অবাক হয়ে s1 == s2যাবেন true!


10

জাভার কোন সংস্করণ আপনি ব্যবহার করছেন? জাভা ১.7.০.০_06 থেকে, ওরাকল স্ট্রিংয়ের অভ্যন্তরীণ উপস্থাপনা, বিশেষত সাবস্ট্রিংকে পরিবর্তন করেছে।

ওরাকল টিউনস জাভার অভ্যন্তরীণ স্ট্রিং প্রতিনিধিত্ব থেকে উদ্ধৃত :

নতুন দৃষ্টান্তে, স্ট্রিং অফসেট এবং গণনা ক্ষেত্রগুলি সরানো হয়েছে, সুতরাং সাবস্ট্রিংগুলি আর অন্তর্নিহিত চরটি [] মান ভাগ করে না।

এই পরিবর্তন সহ, এটি প্রতিবিম্ব ছাড়াই ঘটতে পারে (???)।


2
ওপি যদি কোনও পুরানো সান / ওরাকল জেআরই ব্যবহার করে, তবে সর্বশেষ বিবৃতিটি "জাভা!" মুদ্রণ করবে (তিনি ঘটনাক্রমে পোস্ট হিসাবে)। এটি কেবল স্ট্রিং এবং সাব স্ট্রিংয়ের মধ্যে মান অ্যারের ভাগ করে নেওয়া প্রভাবিত করে। আপনি প্রতিফলনের মতো কৌশলগুলি ছাড়াই মানটি পরিবর্তন করতে পারবেন না।
হেরাল্ডকে

7

এখানে সত্যিই দুটি প্রশ্ন আছে:

  1. স্ট্রিং কি আসলেই অপরিবর্তনীয়?
  2. এস 3 কেন পরিবর্তন হয় না?

পয়েন্ট 1: রম ব্যতীত আপনার কম্পিউটারে কোনও অপরিবর্তনীয় মেমরি নেই। আজকাল এমনকি রমও মাঝে মাঝে লিখিত হয়। সর্বদা কোথাও না কোথাও কোনও কোড থাকে (এটি কার্নেল বা নেটিভ কোড যা আপনার পরিচালিত পরিবেশকে অগ্রাহ্য করে) যা আপনার স্মৃতি ঠিকানায় লিখতে পারে। সুতরাং, "বাস্তবতা" এ, না তারা একেবারেই স্থায়ী নয়।

2 পয়েন্ট: এটি কারণ স্ট্রিংিং সম্ভবত একটি নতুন স্ট্রিং উদাহরণ বরাদ্দ করা হচ্ছে, সম্ভবত অ্যারে অনুলিপি করছে। সাবস্ট্রিংকে এমনভাবে প্রয়োগ করা সম্ভব যে এটি কোনও অনুলিপি করবে না, তবে এর অর্থ এটি নেই। এতে জড়িত ট্রেড অফস রয়েছে।

উদাহরণস্বরূপ, reallyLargeString.substring(reallyLargeString.length - 2)প্রচুর পরিমাণে মেমরি জীবিত রাখার জন্য একটি রেফারেন্স রাখা উচিত , বা কেবল কয়েকটি বাইট?

এটি স্ট্রটারিং কীভাবে প্রয়োগ করা হয় তার উপর নির্ভর করে। একটি গভীর অনুলিপি কম স্মৃতি বাঁচিয়ে রাখবে, তবে এটি কিছুটা ধীরে চলবে। একটি অগভীর অনুলিপি আরও স্মৃতি বাঁচিয়ে রাখবে, তবে এটি আরও দ্রুত হবে। একটি গভীর অনুলিপি ব্যবহার করে হ্যাপের খণ্ডনও হ্রাস করতে পারে, কারণ স্ট্রিং অবজেক্ট এবং এর বাফারকে একটি পৃথক 2 টি পৃথক হিপ বরাদ্দের বিপরীতে বরাদ্দ দেওয়া যেতে পারে।

যাই হোক না কেন, দেখে মনে হচ্ছে আপনার জেভিএম সাবস্ট্রিং কলগুলির জন্য গভীর অনুলিপি ব্যবহার করা বেছে নিয়েছে।


3
প্লাস্টিকের মধ্যে আবদ্ধ কোনও ফটোগ্রাফিক প্রিন্টের মতোই রিয়েল রম অপরিবর্তনীয়। ওয়েফার (বা মুদ্রণ) রাসায়নিকভাবে বিকাশ করা হলে প্যাটার্নটি স্থায়ীভাবে সেট করা হয়। র‌্যাম চিপস সহ বৈদ্যুতিক-পরিবর্তিত স্মৃতিগুলি "সত্য" রম হিসাবে আচরণ করতে পারে যদি এটি লেখার জন্য প্রয়োজনীয় নিয়ন্ত্রণ সংকেতগুলি যে সার্কিটটি ইনস্টল করা হয় তার সাথে অতিরিক্ত বৈদ্যুতিক সংযোগ যুক্ত না করে উত্সাহিত করা যায় না। এম্বেড থাকা ডিভাইসগুলির জন্য এটি র‌্যাম অন্তর্ভুক্ত করা অসাধারণ নয় যা কারখানায় সেট করা আছে এবং ব্যাক-আপ ব্যাটারি দ্বারা রক্ষণাবেক্ষণ করা হয় এবং বাট্টে ব্যর্থ হলে কার বিষয়বস্তুগুলি ফ্যাক্টরীটিকে পুনরায় লোড করা প্রয়োজন।
সুপারক্যাট

3
@ সুপের্যাট: যদিও আপনার কম্পিউটার সেই এম্বেড থাকা সিস্টেমগুলির মধ্যে একটি নয়। :) সত্য হার্ড-ওয়্যার্ড রমগুলি পিসিগুলিতে এক বা দুই দশক ধরে প্রচলিত হয়নি; এই দিনগুলিতে সমস্ত কিছুর EEPROM এবং ফ্ল্যাশ। মূলত প্রতিটি ব্যবহারযোগ্য-দৃশ্যমান ঠিকানা যা মেমরিকে বোঝায়, সম্ভাব্য লিখনযোগ্য মেমরিকে বোঝায়।
সিএওও

@ সিএইচও: অনেকগুলি ফ্ল্যাশ চিপগুলি অংশে এমনভাবে রচনা-সুরক্ষিত রাখার অনুমতি দেয় যা যদি একে একে পূর্বাবস্থায় ফেলা যায় তবে সাধারণ ক্রিয়াকলাপের জন্য প্রয়োজনীয় বিভিন্ন ভোল্টেজ প্রয়োগ করা প্রয়োজন (যা মাদারবোর্ডগুলি সজ্জিত করতে পারে না)। আমি আশা করি মাদারবোর্ডগুলি সেই বৈশিষ্ট্যটি ব্যবহার করবে। আরও, আমি আজকের কম্পিউটারগুলি সম্পর্কে নিশ্চিত নই, তবে historতিহাসিকভাবে কিছু কম্পিউটারের র‌্যামের একটি অঞ্চল রয়েছে যা বুট পর্যায়ে রাইট-সুরক্ষিত ছিল এবং কেবল পুনরায় সেট করেই এটির সুরক্ষিত হতে পারে না (যা কার্যকরভাবে রম থেকে শুরু করতে বাধ্য করবে)।
সুপারক্যাট

2
@ সুপের্যাট আমি মনে করি আপনি বিষয়টির বিন্দুটি মিস করছেন, এটি হ'ল র‌্যামে সঞ্চিত স্ট্রিংগুলি কখনও সত্যিকারের স্থাবর হতে পারে না।
স্কট উইসনিউস্কি

5

@ হারল্ডকের জবাব যোগ করতে - এটি একটি সুরক্ষা হ্যাক যা অ্যাপ্লিকেশনটিতে মারাত্মক প্রভাব ফেলতে পারে।

প্রথম জিনিসটি স্ট্রিং পুলে সঞ্চিত ধ্রুবক স্ট্রিংয়ের একটি পরিবর্তন। স্ট্রিংটিকে একটি হিসাবে ঘোষণা করা হলে String s = "Hello World";, এটি আরও সম্ভাব্য পুনঃব্যবহারের জন্য একটি বিশেষ অবজেক্ট পুলে স্থান করে দিচ্ছে। সমস্যাটি হ'ল সংকলক সংকলনের সময় সংশোধিত সংস্করণটির জন্য একটি রেফারেন্স রাখবে এবং একবার ব্যবহারকারী এই পুলে স্ট্রাইংটি রানটাইম-এ সংশোধন করার পরে কোডের সমস্ত তথ্য পরিবর্তিত সংস্করণটির দিকে নির্দেশ করবে। এটি নিম্নলিখিত বাগের ফলস্বরূপ:

System.out.println("Hello World"); 

মুদ্রণ করবে:

Hello Java!

আমি যখন এমন ঝুঁকিপূর্ণ স্ট্রিংগুলির উপর ভারী গণনা বাস্তবায়ন করছিলাম তখন আমার আরও একটি সমস্যা ছিল। গণনার সময় 1000000 টির মধ্যে 1 টির মতো একটি বাগ ঘটেছিল যা ফলাফলকে অনির্দিষ্টবাদী করে তোলে। আমি জেআইটি স্যুইচ অফ করে সমস্যাটি সন্ধান করতে পেরেছিলাম - জেআইটি বন্ধ হয়ে যাওয়ার সাথে সাথে আমি সর্বদা একই ফল পাচ্ছিলাম। আমার ধারণা হ'ল কারণটি ছিল এই স্ট্রিং সিকিউরিটি হ্যাক যা জেআইটি অপ্টিমাইজেশন চুক্তিগুলিকে ভেঙে দিয়েছে।


এটি একটি থ্রেড-সুরক্ষা সমস্যা হতে পারে যা জেআইটি ছাড়াই ধীর সম্পাদন সময় এবং কম স্বচ্ছলতা দ্বারা মুখোশযুক্ত ছিল।
টেড পেনিংস 7'14

@ টেডপেনিংস আমার বিবরণ থেকে এটি হতে পারে, আমি বিশদে খুব বেশি যেতে চাইনি। আমি আসলে এটি স্থানীয়করণের চেষ্টা করে কয়েক দিন কাটিয়েছি। এটি ছিল একক থ্রেডযুক্ত অ্যালগরিদম যা দুটি ভিন্ন ভাষায় লেখা দুটি পাঠ্যের মধ্যে একটি দূরত্ব গণনা করে। আমি ইস্যুটির জন্য দুটি সম্ভাব্য সংশোধনগুলি পেয়েছি - একটি হ'ল জেআইটি বন্ধ করে দেওয়া এবং দ্বিতীয়টি হ'ল String.format("")আভ্যন্তরীণ লুপগুলির মধ্যে একটিটির আক্ষরিক অর্থে কোনও বিকল্প যুক্ত করা । এটি কিছু অন্যান্য-তত্কালীন-জেআইটি-ব্যর্থতার ইস্যু হওয়ার সুযোগ রয়েছে তবে আমি বিশ্বাস করি এটিই জেআইটি, কারণ এই ইস্যুটি কোনও অপ-বিকল্প যুক্ত করার পরে আর পুনরুত্পাদন করা হয়নি।
আন্দ্রে চাশেভ

আমি JDK K 7u9 এর প্রথম সংস্করণ দিয়ে এটি করছিলাম, তাই এটি হতে পারে।
আন্দ্রে চাশেভ

1
@ অ্যান্ড্রে চাশেভ: "আমি ইস্যুটির জন্য দুটি সম্ভাব্য সংশোধন পেয়েছি" ... তৃতীয় সম্ভাব্য স্থিরতা, অভ্যন্তরীণ স্থানগুলিতে হ্যাক Stringনা করা, আপনার মনে আসে নি?
হোলার

1
@ টেড পেনিংস: থ্রেড-সুরক্ষা সমস্যা এবং জেআইটি ইস্যুগুলি প্রায়শই একই রকম হয়। জেআইটিকে কোড উত্পন্ন করার অনুমতি দেওয়া হয়েছে যা finalফিল্ড থ্রেড সুরক্ষা গ্যারান্টির উপর নির্ভর করে যা অবজেক্ট নির্মাণের পরে ডেটা সংশোধন করার সময় ভেঙে যায়। সুতরাং আপনি এটি আপনার পছন্দ মতো জেআইটি ইস্যু বা এমটি ইস্যু হিসাবে দেখতে পারেন। আসল সমস্যাটি হ্যাক করা Stringএবং ডেটা পরিবর্তন করা যা অপরিবর্তনীয় বলে আশা করা যায়।
হলগার

5

পুলিংয়ের ধারণা অনুসারে, একই মানযুক্ত সমস্ত স্ট্রিং ভেরিয়েবল একই মেমরি ঠিকানার দিকে নির্দেশ করবে। সুতরাং এস 1 এবং এস 2, উভয়ই "হ্যালো ওয়ার্ল্ড" এর একই মান সমেত, একই স্মৃতি অবস্থানের দিকে নির্দেশ করবে (বলুন এম 1)।

অন্যদিকে, এস 3-এ "ওয়ার্ল্ড" রয়েছে, সুতরাং এটি আলাদা মেমরির বরাদ্দকে নির্দেশ করবে (বলুন এম 2))

সুতরাং এখন যা হচ্ছে তা হচ্ছে এস 1 এর মান পরিবর্তন করা হচ্ছে (চর [] মানটি ব্যবহার করে)। সুতরাং মেমরি অবস্থান এম 1 এর মান এস 1 এবং এস 2 উভয় দ্বারা পরিবর্তিত হয়েছে।

সুতরাং ফলস্বরূপ, মেমরি অবস্থান এম 1 সংশোধন করা হয়েছে যা এস 1 এবং এস 2 এর মান পরিবর্তনের কারণ হয়ে থাকে।

তবে অবস্থানের মান 2 এর মান অপরিবর্তিত রয়েছে, সুতরাং এস 3-তে একই মূল মান রয়েছে।


5

এস 3 এর পরিবর্তিত না হওয়ার কারণটি হ'ল জাভাতে যখন আপনি একটি স্ট্রিংয়ের জন্য মান অক্ষরের অ্যারেটিকে একটি স্ট্রিং করেন অভ্যন্তরীণভাবে অনুলিপি করা হয় (অ্যারেএস.কোপিওফ্রেঞ্জ () ব্যবহার করে)।

s1 এবং s2 একই কারণ জাভাতে তারা উভয়ই একই ইন্টার্নযুক্ত স্ট্রিংকে বোঝায়। এটি জাভাতে নকশা দ্বারা।


2
এই উত্তরটি আপনার আগে উত্তরগুলিতে কীভাবে কিছু যুক্ত করেছিল?
ধূসর

এছাড়াও মনে রাখবেন যে এটি একটি সম্পূর্ণ নতুন আচরণ এবং কোনও অনুমানের দ্বারা গ্যারান্টিযুক্ত নয়।
পাওলো ইবারম্যান

String.substring(int, int)জাভা 7u6 দিয়ে পরিবর্তনটি বাস্তবায়ন করা হয়েছে। 7u6 আগে, জেভিএম শুধু মূল একটি পয়েন্টার রাখা হবে String's char[]একটি সূচক এবং দৈর্ঘ্য সঙ্গে একসঙ্গে। 7u6 এর পরে, এটি স্ট্রিংগুলিকে একটি নতুন প্রতিলিপি করে তোলে সেখানে বিভিন্ন উপকারিতা Stringরয়েছে cons
এরিক জাবলো

2

স্ট্রিং পরিবর্তনযোগ্য, কিন্তু প্রতিবিম্বের মাধ্যমে আপনাকে স্ট্রিং ক্লাস পরিবর্তন করার অনুমতি দেওয়া হয়েছে। আপনি কেবল স্ট্রিং ক্লাসটিকে রিয়েল-টাইমে পরিবর্তনযোগ্য হিসাবে পুনরায় সংজ্ঞায়িত করেছেন। আপনি চাইলে পাবলিক বা প্রাইভেট বা স্ট্যাটিক হওয়ার পদ্ধতিগুলি পুনরায় সংজ্ঞায়িত করতে পারেন।


2
আপনি যদি ক্ষেত্র / পদ্ধতিগুলির দৃশ্যমানতা পরিবর্তন করেন এটি কার্যকর হয় না কারণ সংকলন সময়ে তারা ব্যক্তিগত হয়
বোহেমিয়ান

1
আপনি পদ্ধতিগুলিতে অ্যাক্সেসযোগ্যতা পরিবর্তন করতে পারেন তবে আপনি তাদের সর্বজনীন / বেসরকারী স্থিতি পরিবর্তন করতে পারবেন না এবং আপনি এগুলি স্থির করতে পারবেন না।
ধূসর

1

[দাবি অস্বীকার করার বিষয়টি ইচ্ছাকৃতভাবে মতামত দেওয়ার একটি স্টাইল, কারণ আমি মনে করি যে আরও একটি "বাড়ির বাচ্চাদের কাছে এটি করবেন না" উত্তরটি নিশ্চিত করা হয়েছে]

পাপটি হ'ল লাইন field.setAccessible(true);যা একটি ব্যক্তিগত ক্ষেত্রে অ্যাক্সেসের অনুমতি দিয়ে পাবলিক এপিআই লঙ্ঘন করার কথা বলে। সুরক্ষা পরিচালককে কনফিগার করে লকড করে দেওয়া যায় এমন একটি বিশাল দৈত্য সুরক্ষা গর্ত রয়েছে।

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

প্রতিচ্ছবি ব্যবহার করে অ্যাক্সেস সংশোধককে লঙ্ঘন না করে এ জাতীয় বিবরণগুলির উপর নির্ভর করা কেবল ভাল ধারণা নয়। এই শ্রেণীর মালিক কেবলমাত্র সাধারণ পাবলিক এপিআই সমর্থন করে এবং ভবিষ্যতে বাস্তবায়ন পরিবর্তন করতে বিনামূল্যে।

আপনার কাছে বন্দুক থাকার সময় আপনাকে এই জাতীয় বিপজ্জনক কাজ করতে বাধ্য করার সময় কোডের লাইনটি সত্যিই খুব দরকারী বলে সমস্ত কিছু বলা হয়েছিল। পিছনের দরজাটি ব্যবহার করা সাধারণত একটি কোড গন্ধ যা আপনাকে আরও ভাল লাইব্রেরি কোডে আপগ্রেড করতে হবে যেখানে আপনাকে পাপ করতে হবে না। কোডের সেই বিপজ্জনক লাইনের আর একটি সাধারণ ব্যবহার হ'ল "ভুডু ফ্রেমওয়ার্ক" (orm, ইঞ্জেকশন ধারক, ...) লিখুন। অনেক লোক এ জাতীয় কাঠামো সম্পর্কে ধার্মিক হন (উভয় পক্ষে এবং বিপক্ষে) তাই আমি বিশাল সংখ্যক প্রোগ্রামারকে সেখানে যেতে হবে না বলে কিছুই না বলে শিখা যুদ্ধকে আহ্বান করা এড়াতে পারব।


1

স্ট্রিংগুলি JVM হিপ মেমরির স্থায়ী অঞ্চলে তৈরি করা হয়। সুতরাং হ্যাঁ, এটি সত্যই অপরিবর্তনীয় এবং তৈরি হওয়ার পরে পরিবর্তন করা যায় না। কারণ জেভিএম-তে তিন ধরণের হিপ মেমরি রয়েছে: 1. তরুণ প্রজন্ম ২. পুরানো প্রজন্ম ৩. স্থায়ী প্রজন্ম।

যখন কোনও অবজেক্ট তৈরি করা হয়, এটি তরুণ প্রজন্মের হিপ এরিয়া এবং স্ট্রিং পুলিংয়ের জন্য সংরক্ষিত পারমজেন অঞ্চলে যায়।

এখানে আরও বিশদে আপনি যেতে পারেন এবং আরও তথ্য দখল করতে পারেন: জাভাতে কীভাবে আবর্জনা সংগ্রহ কাজ করে


আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.