আমি কীভাবে কোনও ক্লাসে একটি ব্যক্তিগত ক্ষেত্রের পরিবর্তন রোধ করব?


165

ভাবুন যে এই ক্লাসটি আমার রয়েছে:

public class Test
{
  private String[] arr = new String[]{"1","2"};    

  public String[] getArr() 
  {
    return arr;
  }
}

এখন, আমার আরও একটি ক্লাস রয়েছে যা উপরের ক্লাসটি ব্যবহার করে:

Test test = new Test();
test.getArr()[0] ="some value!"; //!!!

সুতরাং এই সমস্যাটি: আমি বাইরে থেকে কোনও শ্রেণির একটি ব্যক্তিগত ক্ষেত্র অ্যাক্সেস করেছি! আমি কীভাবে এটি প্রতিরোধ করতে পারি? মানে আমি কীভাবে এই অ্যারেটিকে অপরিবর্তনীয় করতে পারি? এর অর্থ কি এই যে প্রতিটি গেটর পদ্ধতিতে আপনি ব্যক্তিগত ক্ষেত্রটি অ্যাক্সেস করতে নিজের পথে কাজ করতে পারেন? (আমি পেয়ারা হিসাবে কোনও গ্রন্থাগার চাই না। এটি করার সঠিক উপায়টি আমার জানা উচিত)।


10
আসলে, এটিকে finalকরে মাঠের পরিমার্জন প্রতিরোধ । তবে Objectকোনও ক্ষেত্র দ্বারা বর্ণিত সংশোধন প্রতিরোধ করা আরও জটিল।
ওল্ডরুকমুডিজিয়ন

22
আপনার মানসিক মডেলটিতে সমস্যা আছে যদি আপনি মনে করেন যে কোনও অ্যারে যাতে আপনার একটি ব্যক্তিগত ক্ষেত্রে সঞ্চিত রেফারেন্সটি সংশোধন করতে সক্ষম হবেন তবে এটি একটি ব্যক্তিগত ক্ষেত্র পরিবর্তন করতে সক্ষম হওয়ার মতোই।
জোরেেন

45
যদি এটি ব্যক্তিগত হয় তবে কেন এটি প্রথম স্থানে প্রকাশ করবেন?
এরিক রিপেন

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

8
এই প্রশ্নটি এত মনোযোগ কেন কেন অন্য কেউ অবাক হয়?
রোমান

উত্তর:


163

আপনাকে অবশ্যই আপনার অ্যারের একটি অনুলিপি ফেরত পাঠাতে হবে।

public String[] getArr() {
  return arr == null ? null : Arrays.copyOf(arr, arr.length);
}

121
আমি লোকদের মনে করিয়ে দিতে চাই যে যদিও এই প্রশ্নের সঠিক উত্তরটি ভোট দেওয়া হয়েছে, তবে সমস্যার সেরা সমাধানটি আসলে এসপি 300 মি যেমন বলেছেন - একটি ফেরত দেওয়া Unmodifiable List
ওল্ড কার্মিউডজিয়ন

48
আপনার যদি আসলে একটি অ্যারে ফেরত দেওয়ার দরকার হয় তা নয়।
Svish

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

20
তবে নিশ্চিত করুন যে এটি একটি গভীর অনুলিপি, ডেটার অগভীর অনুলিপি নয়। স্ট্রিংসের ক্ষেত্রে এটি কোনও পার্থক্য রাখে না, যেমন তারিখের মতো অন্যান্য শ্রেণীর জন্য যেখানে উদাহরণের বিষয়বস্তুটি পরিবর্তন করা যায় এটি একটি পার্থক্য আনতে পারে।
11:43

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

377

আপনি যদি অ্যারের পরিবর্তে একটি তালিকা ব্যবহার করতে পারেন তবে সংগ্রহগুলি একটি অবিচ্ছেদ্য তালিকা সরবরাহ করে :

public List<String> getList() {
    return Collections.unmodifiableList(list);
}

Collections.unmodifiableList(list)ক্ষেত্রের জন্য অ্যাসাইনমেন্ট হিসাবে ব্যবহার করে এমন একটি উত্তর যুক্ত করেছে , যাতে ক্লাসটি নিজেই তালিকাটি পরিবর্তন করে না।
মার্টেন বোদেউয়েস

কেবল ভাবছি, আপনি যদি এই পদ্ধতিটি ছিন্ন করেন তবে আপনি প্রচুর নতুন কীওয়ার্ড পাবেন। GetList () অনেক বেশি অ্যাক্সেস পেলে এই কার্য সম্পাদনকে ক্ষতি করে না। উদাহরণস্বরূপ রেন্ডার কোডে।
থমাস 15v

2
মনে রাখবেন যে অ্যারেগুলির উপাদানগুলি Stringযেমন নিজের মধ্যে যেমন পরিবর্তনযোগ্য তেমনি এটি কাজ করে তবে তারা যদি পরিবর্তনীয় হয় তবে কলকারীকে তাদের পরিবর্তন থেকে রোধ করতে কিছু করার প্রয়োজন হতে পারে।
লিই

45

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

public String [] getArr ()
{
    return arr;
}

প্রতি:

public String [] getArr ()
{
    return arr.clone ();
}

অথবা

public int getArrLength ()
{
    return arr.length;
}

public String getArrElementAt (int index)
{
    return arr [index];
}

5
এই নিবন্ধটি অ্যারেতে ক্লোন ব্যবহার করার বিরুদ্ধে তর্ক করে না, কেবলমাত্র অবজেক্ট করা যায় এমন বস্তুগুলিতে।
লিন হেডলি

28

Collections.unmodifiableListইতিমধ্যে উল্লেখ করা হয়েছে - Arrays.asList()অদ্ভুত না! আমার সমাধানটি হ'ল বাইরে থেকে তালিকাটি ব্যবহার করা এবং অ্যারেটি নিম্নরূপে মোড়ানো হবে:

String[] arr = new String[]{"1", "2"}; 
public List<String> getList() {
    return Collections.unmodifiableList(Arrays.asList(arr));
}

অ্যারে অনুলিপি করার সমস্যাটি হ'ল: আপনি যদি কোডটি অ্যাক্সেস করেন এবং অ্যারেটি যত বড় হয় প্রতিবার আপনি এটি করেন তবে আপনি অবশ্যই আবর্জনা সংগ্রাহকের জন্য প্রচুর কাজ তৈরি করবেন। সুতরাং অনুলিপিটি একটি সহজ তবে সত্যই খারাপ দৃষ্টিভঙ্গি - আমি "সস্তা" বলব, তবে মেমরিটি ব্যয়বহুল! বিশেষত যখন আপনি কেবলমাত্র 2 টিরও বেশি উপাদান রয়েছেন।

আপনি যদি উত্সের কোডটি দেখুন Arrays.asListএবং Collections.unmodifiableListসেখানে আসলে খুব বেশি কিছু তৈরি হয় নি। প্রথমটি কেবল অনুলিপি ছাড়াই অ্যারেটিকে আবৃত করে, দ্বিতীয়টি কেবল তালিকাটি মোড়ানো, এতে পরিবর্তনগুলি উপলভ্য নয়।


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

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

6

আপনি এটি ব্যবহার করতে পারেন ImmutableListযা মানের চেয়ে ভাল হওয়া উচিত unmodifiableList। ক্লাসটি গুয়ারা লাইব্রেরির অংশ যা গুগল তৈরি করেছিল।

বর্ণনাটি এখানে:

কালেকশনস.অনমোডিফাইয়েবললিস্ট (java.util.List) এর বিপরীতে, যা পৃথক সংগ্রহের দৃশ্য যা এখনও পরিবর্তন করতে পারে, ইমট্যুয়েবললিস্টের একটি উদাহরণটিতে তার নিজস্ব ব্যক্তিগত ডেটা রয়েছে এবং এটি কখনই পরিবর্তিত হবে না will

এটি কীভাবে ব্যবহার করবেন তার একটি সাধারণ উদাহরণ এখানে:

public class Test
{
  private String[] arr = new String[]{"1","2"};    

  public ImmutableList<String> getArr() 
  {
    return ImmutableList.copyOf(arr);
  }
}

এই তালিকাটি ব্যবহার করুন যদি আপনি ক্লাসকে বিশ্বাস নাTest করতে পারেন তবে ফিরে আসা তালিকাটি আনল্যাটার্টড ছেড়ে যেতে পারেন । আপনাকে নিশ্চিত করা দরকার যে ImmutableListএটি ফিরে এসেছে এবং তালিকার উপাদানগুলিও অপরিবর্তনীয়। অন্যথায় আমার সমাধানটিও নিরাপদ হওয়া উচিত।
মার্টেন বোদেউয়েস

3

এই দৃষ্টিতে আপনার সিস্টেম অ্যারে অনুলিপি ব্যবহার করা উচিত:

public String[] getArr() {
   if (arr != null) {
      String[] arrcpy = new String[arr.length];
      System.arraycopy(arr, 0, arrcpy, 0, arr.length);
      return arrcpy;
   } else
      return null;
   }
}

-1 এটি কল করার ফলে কিছুই করে না cloneএবং এটি সংক্ষিপ্ত নয়।
মার্টেন বোদেউয়েস

2

আপনি তথ্য একটি অনুলিপি ফিরে আসতে পারে। যে কলার ডেটা পরিবর্তন করতে চান কেবল তার অনুলিপি পরিবর্তন করা হবে

public class Test {
    private static String[] arr = new String[] { "1", "2" };

    public String[] getArr() {

        String[] b = new String[arr.length];

        System.arraycopy(arr, 0, b, 0, arr.length);

        return b;
    }
}

2

সমস্যার কেন্দ্রবিন্দুটি হ'ল আপনি কোনও পরিবর্তনকারী স্থানে কোনও পয়েন্টার ফিরিয়ে দিচ্ছেন। উফ। হয় আপনি অবজেক্টটি অব্যবহারযোগ্য (অবিস্মরণীয় তালিকা সমাধান) রেন্ডার করুন বা আপনি বস্তুর অনুলিপি ফিরিয়ে দেন।

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


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

1

অবিশ্বাস্য তালিকা ফিরিয়ে দেওয়া ভাল ধারণা। কিন্তু গিটার পদ্ধতিতে কল করার সময় অকেজোযোগ্যযোগ্য একটি তালিকা এখনও শ্রেণি বা ক্লাস থেকে প্রাপ্ত ক্লাস দ্বারা পরিবর্তন করা যেতে পারে।

পরিবর্তে আপনার ক্লাস প্রসারিত যে কারও কাছে এটি পরিষ্কার করা উচিত যে তালিকাটি পরিবর্তন করা উচিত নয়।

সুতরাং আপনার উদাহরণে এটি নিম্নলিখিত কোডের দিকে নিয়ে যেতে পারে:

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class Test {
    public static final List<String> STRINGS =
        Collections.unmodifiableList(
            Arrays.asList("1", "2"));

    public final List<String> getStrings() {
        return STRINGS;
    }
}

উপরের উদাহরণে আমি STRINGSক্ষেত্রটি সর্বজনীন করে দিয়েছি , নীতিগতভাবে আপনি পদ্ধতি কলটি সরিয়ে ফেলতে পারেন, মানগুলি ইতিমধ্যে জানা রয়েছে বলে।

private final List<String>ক্লাস ইনস্ট্যান্স নির্মাণের সময় আপনি অক্ষরবিহীন তৈরি ক্ষেত্রের জন্য স্ট্রিংগুলিও বরাদ্দ করতে পারেন । ধ্রুবক বা তাত্ক্ষণিক যুক্তি (নির্মাণকারীর) ব্যবহার শ্রেণীর নকশার উপর নির্ভর করে।

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class Test {
    private final List<String> strings;

    public Test(final String ... strings) {
        this.strings = Collections.unmodifiableList(Arrays
                .asList(strings));
    }

    public final List<String> getStrings() {
        return strings;
    }
}

0

হ্যাঁ, আপনার অ্যারের অনুলিপি ফিরে আসা উচিত:

 public String[] getArr()
 {
    return Arrays.copyOf(arr);
 }
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.