এর কারণগুলি জাভা কীভাবে জেনেরিক প্রয়োগ করে তার উপর ভিত্তি করে।
একটি অ্যারে উদাহরণ
অ্যারেগুলির সাহায্যে আপনি এটি করতে পারেন (অ্যারেগুলি সমকামী)
Integer[] myInts = {1,2,3,4};
Number[] myNumber = myInts;
তবে, আপনি যদি এটি করার চেষ্টা করেন তবে কী হবে?
myNumber[0] = 3.14; //attempt of heap pollution
এই শেষ লাইনটি ঠিক জরিমানা সংকলন করবে, তবে আপনি যদি এই কোডটি চালান, আপনি একটি পেতে পারেন ArrayStoreException
। কারণ আপনি একটি সংখ্যার অ্যারেতে একটি ডাবল রাখার চেষ্টা করছেন (কোনও সংখ্যার রেফারেন্সের মাধ্যমে অ্যাক্সেস হওয়া নির্বিশেষে)।
এর অর্থ হ'ল আপনি সংকলককে বোকা বানাতে পারবেন তবে রানটাইম টাইপ সিস্টেমটিকে বোকা বানাতে পারবেন না। এবং এটি তাই কারণ অ্যারে আমরা যা পুনরায় সংশোধনযোগ্য প্রকারগুলি বলি । এর অর্থ রানটটাইম জাভা জানে যে এই অ্যারেটি আসলে পূর্ণসংখ্যার অ্যারে হিসাবে ইনস্ট্যান্ট করা হয়েছিল যা কেবল প্রকারের একটি রেফারেন্সের মাধ্যমে অ্যাক্সেস করা যায় Number[]
।
সুতরাং, যেমন আপনি দেখতে পাচ্ছেন, একটি জিনিস হ'ল অবজেক্টের প্রকৃত ধরণ এবং অন্য জিনিসটি আপনি এটি অ্যাক্সেস করতে ব্যবহার করেন এমন রেফারেন্সের ধরণটি, তাই না?
জাভা জেনারিক্সের সাথে সমস্যা
এখন, জাভা জেনেরিক ধরণের সমস্যা হ'ল টাইপ তথ্যটি সংকলক দ্বারা বাতিল করা হয় এবং এটি রান সময় পাওয়া যায় না। এই প্রক্রিয়াটিকে টাইপ ইরেজোর বলা হয় । জাভাতে এর মতো জেনেরিকগুলি প্রয়োগ করার উপযুক্ত কারণ রয়েছে তবে এটি একটি দীর্ঘ গল্প এবং এটি অন্যান্য বিষয়গুলির মধ্যে পূর্ব-বিদ্যমান কোডের সাথে বাইনারি সামঞ্জস্যের সাথে করতে হবে (দেখুন কীভাবে আমরা জেনেরিক পেয়েছি )।
তবে এখানে গুরুত্বপূর্ণ বিষয়টি হ'ল যেহেতু রানটাইমের সময় কোনও ধরণের তথ্য নেই, তাই আমরা নিশ্চিত হচ্ছি যে আমরা গাদা দূষণ করছি না।
এই ক্ষেত্রে,
List<Integer> myInts = new ArrayList<Integer>();
myInts.add(1);
myInts.add(2);
List<Number> myNums = myInts; //compiler error
myNums.add(3.14); //heap pollution
যদি জাভা সংকলক আপনাকে এটি করতে বাধা দেয় না, রানটাইম টাইপ সিস্টেমটি আপনাকে বাধা দিতে পারে না, কারণ রানটাইমের সময় কোনও উপায় নেই, এটি নির্ধারণ করার জন্য যে এই তালিকাটি কেবলমাত্র পূর্ণসংখ্যার একটি তালিকা হতে পারে determine জাভা রানটাইম আপনাকে যা যা করতে চান এই তালিকায় রাখবে, যখন এটিতে কেবল পূর্ণসংখ্যার উপস্থিতি থাকতে হবে, কারণ এটি তৈরি হওয়ার পরে এটি পূর্ণসংখ্যার তালিকা হিসাবে ঘোষণা করা হয়েছিল।
যেমন, জাভা ডিজাইনারগণ নিশ্চিত করেছেন যে আপনি সংকলককে বোকা বানাতে পারবেন না। আপনি যদি সংকলককে বোকা বানাতে না পারেন (যেমন আমরা অ্যারে দিয়ে করতে পারি) আপনি রানটাইম টাইপ সিস্টেমটিকেও বোকা বানাতে পারবেন না।
যেমনটি, আমরা বলি যে জেনেরিক প্রকারগুলি অ-সংশোধনযোগ্য ।
স্পষ্টতই, এটি বহুবর্ষকে বাধাগ্রস্ত করবে। নিম্নলিখিত উদাহরণ বিবেচনা করুন:
static long sum(Number[] numbers) {
long summation = 0;
for(Number number : numbers) {
summation += number.longValue();
}
return summation;
}
এখন আপনি এটি এর মতো ব্যবহার করতে পারেন:
Integer[] myInts = {1,2,3,4,5};
Long[] myLongs = {1L, 2L, 3L, 4L, 5L};
Double[] myDoubles = {1.0, 2.0, 3.0, 4.0, 5.0};
System.out.println(sum(myInts));
System.out.println(sum(myLongs));
System.out.println(sum(myDoubles));
আপনি যদি জেনেরিক সংগ্রহ সহ একই কোডটি প্রয়োগ করার চেষ্টা করেন তবে আপনি সফল হতে পারবেন না:
static long sum(List<Number> numbers) {
long summation = 0;
for(Number number : numbers) {
summation += number.longValue();
}
return summation;
}
আপনি যদি চেষ্টা করেন তবে আপনি সংকলক এরোগুলি পেয়ে যাবেন ...
List<Integer> myInts = asList(1,2,3,4,5);
List<Long> myLongs = asList(1L, 2L, 3L, 4L, 5L);
List<Double> myDoubles = asList(1.0, 2.0, 3.0, 4.0, 5.0);
System.out.println(sum(myInts)); //compiler error
System.out.println(sum(myLongs)); //compiler error
System.out.println(sum(myDoubles)); //compiler error
সমাধানটি হল জাভা জেনেরিকের দুটি শক্তিশালী বৈশিষ্ট্য যা covariance এবং বিপরীতমুখী হিসাবে পরিচিত হিসাবে ব্যবহার করা শিখতে হয়।
সহভেদাংক
প্রচলিত সাহায্যে আপনি কোনও কাঠামো থেকে আইটেমগুলি পড়তে পারেন, তবে আপনি এতে কিছুই লিখতে পারবেন না। এই সমস্ত বৈধ ঘোষণা।
List<? extends Number> myNums = new ArrayList<Integer>();
List<? extends Number> myNums = new ArrayList<Float>();
List<? extends Number> myNums = new ArrayList<Double>();
এবং আপনি থেকে পড়তে পারেন myNums
:
Number n = myNums.get(0);
কারণ আপনি নিশ্চিত হতে পারেন যে প্রকৃত তালিকায় যা কিছু আছে, এটি একটি সংখ্যায় আপস করা যেতে পারে (সংখ্যার প্রসারিত সমস্ত কিছুর পরে একটি সংখ্যা, তাই না?)
তবে আপনাকে কোনও সমবায় কাঠামোতে কিছু দেওয়ার অনুমতি নেই।
myNumst.add(45L); //compiler error
এটি অনুমোদিত হবে না, কারণ জাভা জেনেরিক কাঠামোর মধ্যে বস্তুর আসল প্রকারের গ্যারান্টি দিতে পারে না। এটি সংখ্যাকে প্রসারিত এমন কোনও কিছু হতে পারে, তবে সংকলকটি নিশ্চিত হতে পারে না। সুতরাং আপনি পড়তে পারেন, কিন্তু লিখতে পারেন না।
Contravariance
বিপরীতে আপনি বিপরীতে করতে পারেন। আপনি জিনিসগুলিকে জেনেরিক কাঠামোর মধ্যে রাখতে পারেন তবে আপনি এটি থেকে পড়তে পারবেন না।
List<Object> myObjs = new List<Object>();
myObjs.add("Luke");
myObjs.add("Obi-wan");
List<? super Number> myNums = myObjs;
myNums.add(10);
myNums.add(3.14);
এই ক্ষেত্রে, অবজেক্টের প্রকৃত প্রকৃতি হ'ল অবজেক্টগুলির একটি তালিকা, এবং বৈপরীত্যের মাধ্যমে আপনি সংখ্যাগুলিকে এতে স্থাপন করতে পারেন, মূলত কারণ সমস্ত সংখ্যারই তাদের পূর্বপুরুষ হিসাবে অবজেক্ট থাকে। যেমন, সমস্ত নম্বর বস্তু এবং তাই এটি বৈধ।
যাইহোক, আপনি এই সংকীর্ণ কাঠামোটি থেকে কোনও নম্বর পাবেন বলে ধরে নিয়ে নিরাপদে কিছু পড়তে পারবেন না।
Number myNum = myNums.get(0); //compiler-error
আপনি দেখতে পাচ্ছেন, যদি সংকলক আপনাকে এই লাইনটি লেখার অনুমতি দেয় তবে আপনি রানটাইমটিতে একটি ক্লাসকাস্ট এক্সেকশন পাবেন।
নীতি পান / রাখুন
যেমন, যখন আপনি কেবল কোনও কাঠামোর বাইরে জেনেরিক মান নেওয়ার ইচ্ছা করেন তখন কোভারিয়েন্স ব্যবহার করুন, যখন আপনি কেবল জেনেরিক মানগুলিকে কোনও কাঠামোর মধ্যে রাখবেন এবং যখন আপনি উভয়ই করার ইচ্ছা করেন তখন সঠিক জেনেরিক প্রকারটি ব্যবহার করুন cont
আমার কাছে সর্বোত্তম উদাহরণটি হ'ল নিম্নলিখিতটি যা কোনও তালিকা থেকে অন্য তালিকায় অনুলিপি করে। এটি কেবল উত্স থেকে আইটেম পায় এবং এটি কেবলমাত্র লক্ষ্যগুলিতে আইটেম রাখে ।
public static void copy(List<? extends Number> source, List<? super Number> target) {
for(Number number : source) {
target(number);
}
}
সমাজতন্ত্র এবং বৈপরীত্যের শক্তিগুলিকে ধন্যবাদ এটি এরকম একটি মামলার জন্য কাজ করে:
List<Integer> myInts = asList(1,2,3,4);
List<Double> myDoubles = asList(3.14, 6.28);
List<Object> myObjs = new ArrayList<Object>();
copy(myInts, myObjs);
copy(myDoubles, myObjs);