জাভা এবং .NET এ স্ট্রিংগুলি কেন পরিবর্তনযোগ্য হতে পারে না?


190

কেন তারা Stringজাভা এবং। নেট (এবং কিছু অন্যান্য ভাষায়) পরিবর্তনযোগ্য করার সিদ্ধান্ত নিয়েছে ? কেন তারা এটিকে পরিবর্তনযোগ্য করে তুলল না?


13
আমারও একই ধারণা ছিল, তবে মূল পোস্টারগুলির অবস্থানটি পরীক্ষা করে দেখেছি যে তারা বেলজিয়ামের। প্রদত্ত যে এর অর্থ তারা সম্ভবত স্থানীয় নেটিভ স্পিকার হওয়ার সম্ভাবনা নেই। বেশিরভাগ স্থানীয় নাগরিকের ভাষার ofিলেspালা উপলব্ধি রয়েছে এর সাথে মিলিত হয়ে আমি তাকে কিছুটা herিল কাটানোর সিদ্ধান্ত নিয়েছি।
বেলুগাবোব

8
ধন্যবাদ বেলুগাবোব, তবে আমি সে নই আমি সে একজন। স্পষ্টতই লোকেরা সাংস্কৃতিক পার্থক্য বিবেচনা করে না।
chrissie1

7
আমার ক্ষমা - ক্রিসি হ'ল (সাধারণত) যুক্তরাজ্যের একটি মেয়ের নাম - আমাকে অন্য সংস্কৃতির পার্থক্যের শিকার করে
তোলে

NET Stringএ কেবল একটি নোট আসলে অভ্যন্তরীণভাবে পরিবর্তিত। StringBuilder.NET 2.0 এ একটি স্ট্রিং পরিবর্তন করে । আমি শুধু এটি এখানে ছেড়ে দেব।
আলভিন ওং

আসলে .NET স্ট্রিং হয় চপল। এবং এটি এমনকি একটি হ্যাকের হেকও নয়।
বিটারব্লু

উত্তর:


204

কার্যকর জাভা অনুসারে , অধ্যায় 4, পৃষ্ঠা 73, 2 য় সংস্করণ:

"এর অনেকগুলি ভাল কারণ রয়েছে: অপরিবর্তনীয় ক্লাসগুলি পরিবর্তনীয় ক্লাসগুলির চেয়ে নকশা করা, প্রয়োগ করা এবং ব্যবহার করা সহজ They এগুলি ত্রুটির ঝুঁকির ঝুঁকি কম এবং আরও সুরক্ষিত।

[...]

" অপরিবর্তনীয় অবজেক্টগুলি সহজ An আপনার পক্ষ থেকে কোন প্রচেষ্টা।

[...]

অপরিবর্তনীয় বস্তুগুলি সহজাতভাবে থ্রেড-নিরাপদ; তাদের কোনও সিঙ্ক্রোনাইজেশন প্রয়োজন। একযোগে একাধিক থ্রেড অ্যাক্সেস করে তাদের দূষিত করা যায় না। এটি থ্রেড সুরক্ষা অর্জনের সবচেয়ে সহজ পদ্ধতির and প্রকৃতপক্ষে, কোনও থ্রেড কখনও অপরিবর্তনীয় কোনও জিনিসে অন্য থ্রেডের কোনও প্রভাব পর্যবেক্ষণ করতে পারে না। অতএব, অপরিবর্তনীয় জিনিসগুলি অবাধে ভাগ করা যায়

[...]

একই অধ্যায় থেকে অন্যান্য ছোট পয়েন্ট:

আপনি কেবল অপরিবর্তনীয় বস্তুগুলিই ভাগ করতে পারবেন না, তবে আপনি তাদের অভ্যন্তর ভাগ করতে পারেন share

[...]

অপরিবর্তনীয় অবজেক্টগুলি অপরিবর্তনীয় বা অপরিবর্তনীয়, অন্য বস্তুর জন্য দুর্দান্ত বিল্ডিং ব্লক তৈরি করে।

[...]

অপরিবর্তনীয় শ্রেণির একমাত্র আসল অসুবিধা হ'ল প্রতিটি স্বতন্ত্র মানের জন্য তাদের পৃথক বস্তুর প্রয়োজন।


22
আমার উত্তরের দ্বিতীয় বাক্যটি পড়ুন: অপরিবর্তনীয় ক্লাসগুলি পরিবর্তনীয় ক্লাসগুলির চেয়ে নকশা করা, বাস্তবায়ন এবং ব্যবহার করা সহজ। এগুলি ত্রুটির প্রবণতা কম এবং আরও সুরক্ষিত।
PRINCESS FLUFF

5
@ PRINCESSFLUFF আমি যুক্ত করব যে একত্রে থ্রেটেড পারস্পরিক পরিবর্তনগুলি ভাগ করাও বিপজ্জনক। উদাহরণস্বরূপ, একটি প্রতিবেদন কপি: report2.Text = report1.Text;। এর পরে, অন্য কোথাও, টেক্সট সংশোধন করা হচ্ছে: report2.Text.Replace(someWord, someOtherWord);। এটি প্রথম রিপোর্টের পাশাপাশি দ্বিতীয়টিরও পরিবর্তন করবে।
ফুগ

10
@ সাম তিনি "কেন তারা পরিবর্তনীয় হতে পারে না" জিজ্ঞাসা করেননি, তিনি জিজ্ঞাসা করলেন "তারা কেন স্থাবর করার সিদ্ধান্ত নিয়েছে" যা এর উত্তরে উত্তর দেয়।
জেমস

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

@ হাউইইচ্যাম্প আমি মনে করি যে এটির উত্তরের দ্বারা অন্তর্নিহিত যে স্ট্রিংগুলি পরিবর্তনযোগ্য হতে পারে (কোনও হাইপোথটিকাল মিউটেবল স্ট্রিং ক্লাস বিদ্যমান থেকে বাধা দেয় না)। তারা কেবল সরলতার জন্য সেভাবে এটি না করার সিদ্ধান্ত নিয়েছে এবং কারণ এটি ব্যবহারের 99% কেসকে কভার করে। তারা এখনও অন্য 1% মামলার জন্য স্ট্রিংবিল্ডার সরবরাহ করেছে।
ড্যানিয়েল গার্সিয়া রুবিও

102

কমপক্ষে দুটি কারণ রয়েছে।

প্রথম - সুরক্ষা http://www.javphaq.nu/java-article1060.html

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

দ্বিতীয়ত - মেমরি দক্ষতা http://hikrish.blogspot.com/2006/07/why-string-class-is-immutable.html

জেভিএম অভ্যন্তরীণভাবে "স্ট্রিং পুল" বজায় রাখে। মেমরির দক্ষতা অর্জন করতে, JVM পুল থেকে স্ট্রিং অবজেক্টটি উল্লেখ করবে। এটি নতুন স্ট্রিং অবজেক্ট তৈরি করবে না। সুতরাং, যখনই আপনি একটি নতুন স্ট্রিং আক্ষরিক তৈরি করবেন, জেভিএম পুলটি ইতিমধ্যে বিদ্যমান কিনা তা পরীক্ষা করে দেখবে। যদি ইতিমধ্যে পুলটিতে উপস্থিত থাকে তবে কেবল একই বস্তুর রেফারেন্স দিন বা পুলটিতে নতুন বস্তু তৈরি করুন। একই স্ট্রিং অবজেক্টগুলিতে অনেক রেফারেন্স পয়েন্ট থাকবে, যদি কেউ মান পরিবর্তন করে তবে এটি সমস্ত রেফারেন্সকে প্রভাবিত করবে। সুতরাং, সূর্য এটিকে স্থাবর করার সিদ্ধান্ত নিয়েছে।


এটি পুনঃব্যবহার সম্পর্কে একটি ভাল পয়েন্ট এবং বিশেষত সত্য যদি আপনি স্ট্রিং.ইনটার্ন () ব্যবহার করেন। সমস্ত স্ট্রিংকে অনিবার্য না করে পুনরায় ব্যবহার করা সম্ভব হত, তবে জীবন সেই মুহূর্তে জটিল হয়ে পড়ে।
জেসাইট

3
এগুলির মধ্যে একটিও আমার কাছে এই দিন এবং যুগে মারাত্মকভাবে বৈধ কারণ বলে মনে হচ্ছে না।
ব্রায়ান নোব্লাচ

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

7
সুরক্ষা সত্যই অপরিবর্তনীয় স্ট্রিংয়ের জন্য রাইসন ডি'ট্রে অংশ নয় - আপনার ওএস কার্নেল-মোড বাফারগুলিতে স্ট্রিংগুলি অনুলিপি করবে এবং সময়োচিত আক্রমণগুলি এড়াতে সেখানে অ্যাক্সেস-চেক করবে। এটি থ্রেড সুরক্ষা এবং পারফরম্যান্স সম্পর্কে সত্যই :)
স্নেমার্চ

1
মেমরি দক্ষতার যুক্তি কার্যকর হয় না। সি এর মতো নেটিভ ভাষায় স্ট্রিং কনস্ট্যান্টগুলি প্রাথমিকভাবে ডেটা বিভাগে কেবলমাত্র পয়েন্টার হয় - এগুলি যেভাবেই পঠনযোগ্য / অপরিবর্তনীয়। "যদি কেউ মান পরিবর্তন করে" - আবার, পুলের স্ট্রিংগুলি যেভাবেই পঠনযোগ্য।
wj32

57

প্রকৃতপক্ষে, জাভাগুলিতে স্ট্রিং অপরিবর্তনীয় কারণগুলির সাথে সুরক্ষার সাথে খুব বেশি কিছু করার নেই। দুটি প্রধান কারণ নিম্নলিখিত:

থিয়েড সুরক্ষা:

স্ট্রিংগুলি চূড়ান্তভাবে ব্যবহৃত ধরণের অবজেক্ট। একাধিক-থ্রেড পরিবেশে এটি কম-বেশি গ্যারান্টিযুক্ত। স্ট্রিংগুলি থ্রেডগুলির মধ্যে স্ট্রিংগুলি ভাগ করে নেওয়া নিরাপদ কিনা তা নিশ্চিত করার জন্য তা পরিবর্তনযোগ্য। অপরিবর্তনীয় স্ট্রিং থাকা নিশ্চিত করে যে থ্রেড এ থেকে অন্য থ্রেড বিতে স্ট্রিংগুলি যাওয়ার সময়, থ্রেড বি অপ্রত্যাশিতভাবে থ্রেড এ এর ​​স্ট্রিং সংশোধন করতে পারে না।

এটি কেবল বহু-থ্রেড প্রোগ্রামিংয়ের ইতিমধ্যে জটিল জটিল কাজটিকে সহজতর করতে সহায়তা করে না, তবে এটি মাল্টি-থ্রেডযুক্ত অ্যাপ্লিকেশনগুলির কার্য সম্পাদনে সহায়তা করে। পরিবর্তনীয় অবজেক্টগুলিতে অ্যাক্সেস অবশ্যই একরকম সিঙ্ক্রোনাইজ করা উচিত যখন একাধিক থ্রেড থেকে সেগুলি অ্যাক্সেস করা যায়, তা নিশ্চিত করার জন্য যে কোনও থ্রেড অন্য থ্রেডের মাধ্যমে সংশোধন করার সময় আপনার অবজেক্টের মান পড়ার চেষ্টা করে না। যথাযথ সিঙ্ক্রোনাইজেশন উভয়ই প্রোগ্রামারটির জন্য সঠিকভাবে করা শক্ত এবং রানটাইম ব্যয়বহুল। অপরিবর্তনীয় বস্তুগুলি সংশোধন করা যায় না এবং তাই সিঙ্ক্রোনাইজেশন প্রয়োজন হয় না।

কর্মক্ষমতা:

স্ট্রিং ইন্টার্নিংয়ের কথা উল্লেখ করা হলেও এটি জাভা প্রোগ্রামগুলির জন্য মেমরির দক্ষতায় সামান্য লাভের প্রতিনিধিত্ব করে। কেবল স্ট্রিং লিটারেলগুলি ইন্টার্ন করা হয়। এর অর্থ হ'ল কেবলমাত্র আপনার উত্স কোডে যে স্ট্রিংগুলি একই স্ট্রিং অবজেক্টটি ভাগ করবে। যদি আপনার প্রোগ্রামটি গতিশীলভাবে স্ট্রিংগুলি একই রকম তৈরি করে, তবে সেগুলিকে বিভিন্ন বস্তুতে উপস্থাপন করা হবে।

আরও গুরুত্বপূর্ণ, অপরিবর্তনীয় স্ট্রিংগুলি তাদের অভ্যন্তরীণ ডেটা ভাগ করার অনুমতি দেয়। অনেকগুলি স্ট্রিং অপারেশনের জন্য, এর অর্থ হ'ল অক্ষরের অন্তর্নিহিত অ্যারেটি অনুলিপি করার দরকার নেই। উদাহরণস্বরূপ, বলুন আপনি স্ট্রিংয়ের পাঁচটি প্রথম অক্ষর নিতে চান। জাভাতে, আপনি myString.substring (0,5) কল করবেন। এই ক্ষেত্রে, স্ট্রাস্টিং () পদ্ধতিটি কেবল একটি নতুন স্ট্রিং অবজেক্ট তৈরি করে যা মাইস্ট্রিংয়ের অন্তর্নিহিত চরটি ভাগ করে [] তবে কে জানে যে এটি সূচক 0 থেকে শুরু হয় এবং সেই চরের সূচক 5 এ শেষ হয় [] এটি গ্রাফিকাল আকারে রাখার জন্য, আপনি নিম্নলিখিতটি দিয়ে শেষ করবেন:

 |               myString                  |
 v                                         v
"The quick brown fox jumps over the lazy dog"   <-- shared char[]
 ^   ^
 |   |  myString.substring(0,5)

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


6
অন্তর্নিহিত ভাগ করে রেফারেন্স হিসাবে সাবস্ট্রিংগুলি প্রয়োগ char[]করা একটি বরং প্রশ্নবিদ্ধ ডিজাইনের সিদ্ধান্ত। আপনি যদি একটি সম্পূর্ণ স্ট্রালে একটি একক স্ট্রিংয়ে পড়ে থাকেন এবং মাত্র 1-বর্ণের সাবস্ট্রিংয়ের একটি রেফারেন্স বজায় রাখেন তবে পুরো ফাইলটি মেমরিতে রাখতে হবে।
গ্যাবে

5
ঠিক একইভাবে, আমি একটি ওয়েবসাইট ক্রলার তৈরি করার সময় আমি সেই নির্দিষ্ট গোচাতে পৌঁছেছিলাম যেখানে পুরো পৃষ্ঠা থেকে কেবল কয়েকটি শব্দ বের করা দরকার। পুরো পৃষ্ঠার এইচটিএমএল কোডটি মেমোরিতে ছিল এবং চরটি ভাগ করে নেওয়ার কারণে [] আমার কেবল কয়েকটি বাইটের প্রয়োজন হলেও আমি পুরো এইচটিএমএল কোডটি রেখেছি kept এর জন্য একটি কার্যপ্রণালী হ'ল নতুন স্ট্রিং (আসল.সুবস্ট্রিং (.., ..)) ব্যবহার করা, স্ট্রিং (স্ট্রিং) কনস্ট্রাক্টর অন্তর্নিহিত অ্যারের সম্পর্কিত পরিসীমাটির একটি অনুলিপি তৈরি করে।
লর্ডঅফ দ্য পিপস

1
পরবর্তী পরিবর্তনগুলি কভার করার একটি সংযোজন: String.substring()উপরের মন্তব্যে উল্লিখিত সমস্যাগুলি প্রতিরোধ করার জন্য জাভ 7 যেহেতু একটি সম্পূর্ণ অনুলিপি সম্পাদন করে। জাভা 8-এ, char[]ভাগ করে নেওয়া সক্ষম করে এমন দুটি ক্ষেত্র , যথা countএবং offset, মুছে ফেলা হয়, এভাবে স্ট্রিংয়ের উদাহরণগুলির মেমরির পদচিহ্ন হ্রাস করে।
খ্রিস্টান সেমরাউ

আমি থিয়েড সুরক্ষা অংশের সাথে একমত, তবে সন্দেহের সাবস্ট্রিংয়ের ক্ষেত্রে।
Gqqnbig

@ লাভরাইট: তারপরে জাভা.লং.স্ট্রিংয়ের সোর্স কোডটি পরীক্ষা করুন ( গ্রেপকোড / ফাইল / রিপোসিটরি.grepcode.com/java/root/jdk/openjdk/… ), জাভা until অবধি এটি সমস্তরকমই ছিল (যেটি যখন এই উত্তরটি লেখা হয়েছিল তখন বর্তমান ছিল)। আমি স্পষ্টত জাভা 7.
তে

28

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


11

একজনকে সত্যই জিজ্ঞাসা করা উচিত, "এক্স কেন পরিবর্তনযোগ্য হতে হবে?" অপরিবর্তনযোগ্যতায় ডিফল্ট করা ভাল, কারণ ইতিমধ্যে উল্লিখিত সুবিধাগুলির কারণেপ্রিন্সেস ফ্লাফের । এটি ব্যতিক্রম হওয়া উচিত যে কিছু পরিবর্তনযোগ্য।

দুর্ভাগ্যক্রমে বর্তমান প্রোগ্রামিং ভাষার বেশিরভাগ ভাষা পরিবর্তনের জন্য ডিফল্ট, তবে আশা করি ভবিষ্যতে ডিফল্টটি অপরিবর্তনশীলতার উপর বেশি থাকে ( পরবর্তী মূলধারার প্রোগ্রামিং ভাষার জন্য একটি বিশদ তালিকা দেখুন )।


7

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

এটি বেশ অভিনব ধারণা যে এর অপরিবর্তনীয়তা Stringথ্রেডিংয়ের সমস্যাগুলিকে সম্বোধন করছে। হুমম ... আমার একটি অবজেক্ট আছে যা দুটি ভিন্ন থ্রেড দ্বারা পরিবর্তিত হচ্ছে। আমি কীভাবে এটি সমাধান করব? অবজেক্টে অ্যাক্সেস সিঙ্ক্রোনাইজ করবেন? নাউউউইউ ... আসুন কাউকে কিছুতেই এটাকে পরিবর্তন করতে দেওয়া যাক না - যা আমাদের সমস্ত অগোছালো বিষয়গুলির সমাধান করবে! প্রকৃতপক্ষে, আসুন সমস্ত বস্তুকে অপরিবর্তনীয় করে তুলুন এবং তারপরে আমরা জাভা ভাষা থেকে সিঙ্ক্রোনাইজড কন্ট্রাক্টটি সরিয়ে ফেলতে পারি।

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

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


3
অপরিবর্তনীয়তা এবং থ্রেডিং মন্তব্য সম্পর্কে আমি দৃ strongly়ভাবে একমত নই, আমার কাছে মনে হয় আপনি সেখানে তেমন পয়েন্টটি পাচ্ছেন না। আর যদি জাভা ব্লচ, জাভা প্রয়োগকারীদের মধ্যে একজন, যদি বলেন যে এটিই ছিল নকশা সংক্রান্ত একটি সমস্যা, তবে কীভাবে এটি ভুল তথ্য হতে পারে?
জাভাসলুক 21

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

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

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

7

String কোনও আদিম ধরণের নয়, তবুও আপনি সাধারণত এটি মান ভঙ্গুর সাথে ব্যবহার করতে চান, যেমন একটি মানের মতো।

একটি মান এমন একটি জিনিস যা আপনি বিশ্বাস করতে পারেন আপনার পিছনে পিছনে পরিবর্তন হবে না। যদি আপনি লিখেন: String str = someExpr(); আপনি কিছু না করে আপনি এটি পরিবর্তন করতে চান না str

Stringযেমন একটি Objectপ্রাকৃতিকভাবে পয়েন্টার শব্দার্থক আছে, মান শব্দার্থবিজ্ঞান পেতে পাশাপাশি এটি অপরিবর্তনীয় হওয়া প্রয়োজন।


7

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


6

আমি জানি এটি একটি গলদ, কিন্তু ... এগুলি কি সত্যিই অপরিবর্তনীয়? নিম্নোক্ত বিবেচনা কর.

public static unsafe void MutableReplaceIndex(string s, char c, int i)
{
    fixed (char* ptr = s)
    {
        *((char*)(ptr + i)) = c;
    }
}

...

string s = "abc";
MutableReplaceIndex(s, '1', 0);
MutableReplaceIndex(s, '2', 1);
MutableReplaceIndex(s, '3', 2);
Console.WriteLine(s); // Prints 1 2 3

এমনকি আপনি এটিকে একটি এক্সটেনশন পদ্ধতিও করতে পারেন।

public static class Extensions
{
    public static unsafe void MutableReplaceIndex(this string s, char c, int i)
    {
        fixed (char* ptr = s)
        {
            *((char*)(ptr + i)) = c;
        }
    }
}

যা নিম্নলিখিত কাজ করে

s.MutableReplaceIndex('1', 0);
s.MutableReplaceIndex('2', 1);
s.MutableReplaceIndex('3', 2);

উপসংহার: তারা একটি অপরিবর্তনীয় অবস্থায় রয়েছে যা সংকলক দ্বারা পরিচিত। জাভাটির উপরেরটি কেবল জা। পয়েন্টার না থাকায় .NET স্ট্রিংগুলিতে প্রযোজ্য। তবে একটি স্ট্রিং সি # তে পয়েন্টার ব্যবহার করে পুরোপুরি পরিবর্তনযোগ্য হতে পারে। পয়েন্টারগুলি কীভাবে ব্যবহারের উদ্দেশ্যে ব্যবহার করা হয়, ব্যবহারিক ব্যবহার আছে বা নিরাপদে ব্যবহার করা হয় তা নয়; এটি তবে সম্ভব, এভাবে পুরো "পরিবর্তনীয়" বিধি মোড়ক। আপনি সাধারণত কোনও স্ট্রিংয়ের সরাসরি সূচকটি পরিবর্তন করতে পারবেন না এবং এটিই একমাত্র উপায়। এটির একটি উপায় রয়েছে যে স্ট্রিংয়ের পয়েন্টার দৃষ্টান্তগুলি অস্বীকার করা বা একটি স্ট্রিংকে নির্দেশিত করার সময় একটি অনুলিপি তৈরির মাধ্যমে এটি প্রতিরোধ করা যেতে পারে, তবে দুটি করা হয় না, যা সি # তে স্ট্রিংগুলি সম্পূর্ণরূপে স্থায়ী নয়।


1
+1 টি। .NET স্ট্রিংগুলি প্রকৃতপক্ষে পরিবর্তনযোগ্য নয়; প্রকৃতপক্ষে, স্ট্রিং এবং স্ট্রিংবিল্ডার ক্লাসে পারফেক্ট কারণে এই পুরো সময়টি করা হয়।
জেমস কো

3

সবচেয়ে উদ্দেশ্যে, একটি "STRING" (ব্যবহৃত / চিকিত্সা হিসাবে / / চিন্তা গণ্য করা) একটি অর্থপূর্ণ , পারমাণবিক ইউনিট মাত্র একটি সংখ্যা মত

স্ট্রিংয়ের স্বতন্ত্র অক্ষরগুলি কেন পারস্পরিক পরিবর্তনযোগ্য নয় তা জিজ্ঞাসা করার কারণ একটি পূর্ণসংখ্যার পৃথক বিট কেন পরিবর্তনীয় নয়।

আপনার জানা উচিত কেন। এটা আমার মনে হয়.

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

আমরা সংখ্যার সাথে কীভাবে করি তার অনুরূপ "স্ট্রিং" এর সাথে গণনা এবং তুলনা করি। স্ট্রিংগুলি (বা পূর্ণসংখ্যার) যদি পারস্পরিক পরিবর্তনযোগ্য হয় তবে কোনও ধরণের গণনা নির্ভরযোগ্যতার সাথে সম্পাদন করার জন্য আমাদের তাদের মানগুলি পরিবর্তনযোগ্য স্থানীয় ফর্মগুলিতে লক করতে বিশেষ কোড লিখতে হবে। সুতরাং, সংখ্যার শনাক্তকারীর মতো স্ট্রিংয়ের কথা ভাবা ভাল তবে 16, 32 বা 64 বিট দীর্ঘ না হয়ে এটি কয়েকশ বিট দীর্ঘ হতে পারে।

যখন কেউ "স্ট্রিং" বলে, আমরা সবাই আলাদা আলাদা জিনিস নিয়ে ভাবি। যারা এটিকে কেবল কোনও চরিত্রের একটি সেট হিসাবে মনে করেন, যার কোনও বিশেষ উদ্দেশ্য মাথায় রাখেনি, অবশ্যই তারা হতাশ হয়ে যাবে যে কেউ ঠিক করেছিলেন যে তারা এই চরিত্রগুলি পরিচালনা করতে সক্ষম হবে না। তবে "স্ট্রিং" শ্রেণিটি কেবল একটি অক্ষরের অ্যারে নয়। এটি একটি STRING, একটি না char[]। ধারণাটিকে আমরা "স্ট্রিং" হিসাবে উল্লেখ করি সম্পর্কে কিছু প্রাথমিক অনুমান রয়েছে এবং এটি সাধারণত সংখ্যার মতো কোডড ডেটার অর্থবোধক, পারমাণবিক ইউনিট হিসাবে বর্ণনা করা যায়। লোকেরা যখন "স্ট্রিংগুলি ম্যানিপুলেটিং" সম্পর্কে কথা বলেন, সম্ভবত তারা স্ট্রিং তৈরির জন্য অক্ষরগুলি ব্যবহার করার বিষয়ে সত্যই কথা বলছিলেন এবং তার জন্য একটি স্ট্রিংবিল্ডার দুর্দান্ত।

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

string GetPersonalInfo( string username, string password )
{
    string stored_password = DBQuery.GetPasswordFor( username );
    if (password == stored_password)
    {
        //another thread modifies the mutable 'username' string
        return DBQuery.GetPersonalInfoFor( username );
    }
}

সুরক্ষা কেবল 'অ্যাক্সেস নিয়ন্ত্রণ' সম্পর্কে নয়, এটি 'সুরক্ষা' এবং 'নির্ভুলতার গ্যারান্টি' সম্পর্কেও। কোনও পদ্ধতি যদি সহজেই গণনা করা যায় বা নির্ভরযোগ্যভাবে একটি সাধারণ গণনা বা তুলনা করা যায় তার উপর নির্ভর করা যায় না, তবে এটি কল করা নিরাপদ নয়, তবে প্রোগ্রামিং ভাষাতেই প্রশ্নটি নেওয়া নিরাপদ হবে।


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

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

2
এবং কেবল স্পষ্ট করে বলতে গেলে, অবজেক্ট-ওরিয়েন্টেড কোডের পয়েন্টারগুলি অন্তর্নিহিতভাবে অনিরাপদ, ঠিক কারণ তারা একটি শ্রেণীর জন্য সংজ্ঞায়িত পাবলিক ইন্টারফেসকে বিঘ্নিত করে। আমি যা বলছিলাম তা হ'ল কোনও স্ট্রিংয়ের জন্য পাবলিক ইন্টারফেসটিকে অন্য থ্রেড দ্বারা সংশোধন করার অনুমতি দিলে কোনও ফাংশন সহজেই ট্রিক করা যায়। অবশ্যই, এটি সর্বদা পয়েন্টারগুলির সাহায্যে সরাসরি ডেটা অ্যাক্সেস করে ঠকানো যায় তবে সহজে বা অজান্তেই নয় not
ট্রায়ঙ্কো

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

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

3

অপরিচ্ছন্নতা সুরক্ষার সাথে এত ঘনিষ্ঠভাবে আবদ্ধ হয় না। তার জন্য, কমপক্ষে। নেট এ, আপনি SecureStringক্লাস পাবেন।

পরে সম্পাদনা করুন: জাভাতে আপনি পাবেন GuardedString, অনুরূপ বাস্তবায়ন।


2

সি ++ তে স্ট্রিং মিউটেবল হওয়ার সিদ্ধান্তটি প্রচুর সমস্যার সৃষ্টি করে, ম্যাড সিওডাব্লিউ ডিজিজ সম্পর্কে ক্যালভিন হেনির এই দুর্দান্ত নিবন্ধটি দেখুন

COW = অনুলিপি করুন


2

এটি একটি বাণিজ্য বন্ধ। Stringগুলি ঢোকা Stringপুল এবং আপনি একাধিক অভিন্ন তৈরি করেনString গুলি তারা একই মেমরির শেয়ার করুন। ডিজাইনাররা মেমরির সংরক্ষণের এই কৌশলটি সাধারণ ক্ষেত্রে খুব ভাল কাজ করবে বলে প্রোগ্রামগুলি একই স্ট্রিংগুলিতে প্রচুর পরিমাণে পিষে থাকে।

ক্ষয়ক্ষতিটি হ'ল সংক্ষেপণগুলি অতিরিক্ত Stringক্রিয়াকলাপ তৈরি করে যা কেবলমাত্র ট্রানজিশিয়াল এবং কেবল আবর্জনায় পরিণত হয়, যা আসলে স্মৃতির কর্মক্ষমতা ক্ষতি করে। আপনার কাছে StringBufferএবং StringBuilder(জাভা, StringBuilderএই ক্ষেত্রে মেমরি সংরক্ষণ করতে ব্যবহার করতে .NET রয়েছেন)।


1
মনে রাখবেন যে "স্ট্রিং পুল" স্বয়ংক্রিয়ভাবে সমস্ত স্ট্রিংয়ের জন্য ব্যবহার করা হয় না যদি না আপনি স্পষ্টভাবে "আন্ত ()" এর এড স্ট্রিং ব্যবহার করেন।
জাজাইট

2

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


1
আমি বিশ্বাস করি যে আপনার কোডটি যদি পুরো বিশ্বস্ততার সাথে চলতে থাকে তবে আপনি কোনও ধরণের কৌশল করতে সক্ষম হবেন, সুতরাং কোনও সুরক্ষার ক্ষতি নেই। আপনি স্ট্রিংগুলি সঞ্চয় করা আছে সেখানে মেমরির অবস্থানটিতে সরাসরি লিখতে JNI ব্যবহার করতে পারেন।
এন্টোইন অব্রি

প্রকৃতপক্ষে আমি বিশ্বাস করি আপনি প্রতিবিম্ব দ্বারা কোনও অপরিবর্তনীয় বস্তু পরিবর্তন করতে পারেন।
Gqqnbig

0

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


0

প্রায় প্রতিটি নিয়মের ব্যতিক্রম রয়েছে:

using System;
using System.Runtime.InteropServices;

namespace Guess
{
    class Program
    {
        static void Main(string[] args)
        {
            const string str = "ABC";

            Console.WriteLine(str);
            Console.WriteLine(str.GetHashCode());

            var handle = GCHandle.Alloc(str, GCHandleType.Pinned);

            try
            {
                Marshal.WriteInt16(handle.AddrOfPinnedObject(), 4, 'Z');

                Console.WriteLine(str);
                Console.WriteLine(str.GetHashCode());
            }
            finally
            {
                handle.Free();
            }
        }
    }
}

-1

এটি মূলত সুরক্ষার কারণে। কোনও সিস্টেম সুরক্ষিত করা অনেক বেশি শক্তিশালী যদি আপনি বিশ্বাস করতে না পারেন যে আপনার Stringসারণী প্রতিরোধী।


1
"টেম্পারপ্রুফ" বলতে কী বোঝাতে চেয়েছেন তার উদাহরণ দিতে পারেন? এই উত্তরগুলি সত্যই প্রসঙ্গের বাইরে রয়েছে।
জারগলি ওরোজ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.