উত্তর:
এটি মূলত যেভাবে জেনারিকগুলি জাভাতে সংকলক ট্রিকের মাধ্যমে প্রয়োগ করা হয়। সংকলিত জেনেরিক কোড আসলে শুধু ব্যবহার java.lang.Object
যেখানেই থাকুন না কেন আপনার সম্পর্কে কথা T
(অথবা অন্য কোনো প্রকারকে প্যারামিটার) - এবং কিছু মেটাডাটা কম্পাইলার এটি সত্যিই একটি জেনেরিক ধরনের জানাতে হবে।
আপনি যখন জেনেরিক টাইপ বা পদ্ধতির বিপরীতে কিছু কোড কম্পাইল করেন, তখন সংকলকটি আপনার আসলে কী বোঝায় তা নির্ধারণ করে (অর্থাত্ টাইপ আর্গুমেন্টটি T
কী) এবং সংকলনের সময় যাচাই করে যে আপনি সঠিক জিনিসটি করছেন তবে নির্গত কোডটি আবার কেবল কথা বলে শর্তাবলী java.lang.Object
- সংকলক যেখানে প্রয়োজন সেখানে অতিরিক্ত কাস্ট তৈরি করে। কার্যকর করার সময়, এ List<String>
এবং এ List<Date>
হুবহু এক; সংকলক দ্বারা অতিরিক্ত ধরণের তথ্য মুছে ফেলা হয়েছে ।
এর সাথে তুলনা করুন, বলুন, সি #, যেখানে মৃত্যুদন্ড কার্যকর করার সময় তথ্যটি ধরে রাখা হয়, কোডের সাথে এক্সপ্রেশন থাকা যেমন typeof(T)
কোনটির সমতুল্য হয় T.class
- বাদে এটি অবৈধ is (। নেট জেনেরিকস এবং জাভা জেনেরিকগুলির মধ্যে আরও পার্থক্য রয়েছে, মনে রাখবেন)) জাভা জেনেরিকগুলি নিয়ে কাজ করার সময় টাইপ ইরেজর হ'ল "বিজোড়" সতর্কতা / ত্রুটি বার্তাগুলির উত্স।
অন্যান্য উৎস:
Object
(দুর্বলভাবে টাইপ করা দৃশ্যে) সরবরাহ করা এমন কিছু আছে কিনা তা কার্যকর করার সময় এটি নির্ণয় করা খুব সহজ List<String>
। জাভাতে এটি কেবল সম্ভব নয় - আপনি জানতে পারেন যে এটি একটি ArrayList
, তবে মূল জেনেরিকের ধরনটি কী তা নয়। উদাহরণস্বরূপ, এই ধরণের জিনিসটি সিরিয়ালাইজেশন / ডেসারিয়ালাইজেশন পরিস্থিতিতে উপস্থিত হতে পারে। আর একটি উদাহরণ যেখানে একটি ধারককে তার জেনেরিক ধরণের উদাহরণগুলি তৈরি করতে সক্ষম হতে হবে - আপনাকে জাভাতে (যেমন Class<T>
) আলাদাভাবে এই ধরণের পাস করতে হবে ।
Class<T>
কোনও কনস্ট্রাক্টরের (বা জেনেরিক পদ্ধতি) একটি প্যারামিটার যুক্ত করতে বাধ্য করেছি কারণ জাভা সেই তথ্যটি ধরে রাখে না। তাকান EnumSet.allOf
- উদাহরণস্বরূপ পদ্ধতি জেনেরিক টাইপ যুক্তি যথেষ্ট হওয়া উচিত; আমাকে কেন "সাধারণ" যুক্তিটি নির্দিষ্ট করতে হবে? উত্তর: মুছে ফেলা টাইপ। এই ধরণের জিনিস কোনও এপিআইকে দূষিত করে। আগ্রহের বাইরে, আপনি। নেট জেনারিকগুলি বেশি ব্যবহার করেছেন? (অবিরত)
পার্শ্ব-নোটের মতোই, এটি মুছে ফেলার সময় সংকলকটি আসলে কী করছে তা দেখার জন্য একটি আকর্ষণীয় অনুশীলন - পুরো ধারণাটি উপলব্ধি করতে কিছুটা সহজ করে তোলে। জেনারিকগুলি মুছে ফেলা এবং ক্যাসেটগুলি inোকানো হয়েছে এমন জাভা ফাইলগুলি আউটপুট দেওয়ার জন্য আপনি একটি বিশেষ পতাকা পাঠাতে পারেন। একটি উদাহরণ:
javac -XD-printflat -d output_dir SomeFile.java
এই -printflat
পতাকাটিই ফাইলগুলি উত্পন্ন করে এমন সংকলকটির কাছে হস্তান্তরিত হয়। ( -XD
অংশটি javac
এটিকে এক্সিকিউটেবল জারের কাছে হস্তান্তর করতে বলে যা প্রকৃতপক্ষে কেবল পরিবর্তে সংকলন করে না javac
, তবে আমি খনন করি ...) -d output_dir
প্রয়োজনীয় কারণ নতুন সংস্থার জাভা ফাইলগুলি সংকলনের জন্য কিছু জায়গা প্রয়োজন some
এটি অবশ্যই ক্ষয়ক্ষতির চেয়ে আরও বেশি কিছু করে; সংকলক যে সমস্ত স্বয়ংক্রিয় স্টাফ দেয় সেগুলি এখানে হয়ে যায়। উদাহরণস্বরূপ, ডিফল্ট কনস্ট্রাক্টরগুলিও inোকানো হয়, নতুন ফোরচ-স্টাইলের for
লুপগুলি নিয়মিত for
লুপগুলিতে প্রসারিত করা হয় auto ইত্যাদি auto
ক্ষয়, আক্ষরিক অর্থে হ'ল উত্স কোডে উপস্থিত টাইপ তথ্য সংকলিত বাইকোড থেকে মুছে ফেলা হয়। আসুন কিছু কোড সহ এটি বুঝতে পারি।
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class GenericsErasure {
public static void main(String args[]) {
List<String> list = new ArrayList<String>();
list.add("Hello");
Iterator<String> iter = list.iterator();
while(iter.hasNext()) {
String s = iter.next();
System.out.println(s);
}
}
}
আপনি যদি এই কোডটি সংকলন করেন এবং তার পরে এটি জাভা ডিকম্পিলার দিয়ে ডিকম্পাইল করেন তবে আপনি এর মতো কিছু পাবেন। লক্ষ্য করুন যে পচনশীল কোডটিতে মূল উত্স কোডে উপস্থিত ধরণের তথ্যের কোনও চিহ্ন নেই।
import java.io.PrintStream;
import java.util.*;
public class GenericsErasure
{
public GenericsErasure()
{
}
public static void main(String args[])
{
List list = new ArrayList();
list.add("Hello");
String s;
for(Iterator iter = list.iterator(); iter.hasNext(); System.out.println(s))
s = (String)iter.next();
}
}
jigawot
, এটি কাজ করে।
ইতিমধ্যে খুব সম্পূর্ণ জন স্কিটির উত্তরটি সম্পূর্ণ করতে, আপনাকে জাভাটির পূর্ববর্তী সংস্করণগুলির সাথে সামঞ্জস্যতার প্রয়োজন থেকে টাইপ ইরেজরের ধারণাটি উপলব্ধি করতে হবে ।
প্রাথমিকভাবে EclipseCon 2007 এ উপস্থাপন করা হয়েছে (আর উপলভ্য নয়), সামঞ্জস্যতার মধ্যে এই পয়েন্টগুলি অন্তর্ভুক্ত রয়েছে:
আসল উত্তর:
অত: পর:
new ArrayList<String>() => new ArrayList()
আরও বৃহত্তর সংশোধনের প্রস্তাব রয়েছে । "বিমূর্ত ধারণাটিকে আসল হিসাবে সম্মান করুন" হিসাবে সংশোধন করুন, যেখানে ভাষার গঠনগুলি কেবল সিনট্যাকটিক চিনি নয়, ধারণাগুলি হওয়া উচিত।
আমার checkCollection
জাভা the এর পদ্ধতিটিও উল্লেখ করা উচিত , যা নির্দিষ্ট সংকলনের গতিশীল টাইপসেফ ভিউ দেয়। ভুল ধরণের একটি উপাদান inোকানোর যে কোনও প্রয়াস তত্ক্ষণাত্ ফলপ্রসূ হবে ClassCastException
।
ভাষায় জেনেরিক্স মেকানিজম সংকলন-সময় (স্ট্যাটিক) প্রকারের পরীক্ষা করে থাকে তবে চেক না করা ক্যাসেটের সাহায্যে এই ব্যবস্থাকে পরাস্ত করা সম্ভব ।
সাধারণত এটি কোনও সমস্যা হয় না, কারণ সংকলক এই জাতীয় সমস্ত চেক না করা ক্রিয়াকলাপ সম্পর্কে সতর্কতা জারি করে।
তবে অনেক সময় আছে যখন একা স্থির ধরণের চেকিং পর্যাপ্ত নয়, যেমন:
ClassCastException
, এটি নির্দেশ করে যে একটি ভুলভাবে টাইপ করা উপাদান একটি প্যারামিটারাইজড সংগ্রহে রাখা হয়েছিল। দুর্ভাগ্যক্রমে, ভুল উপাদানটি সন্নিবেশ করার পরে ব্যতিক্রম যে কোনও সময় ঘটতে পারে, সুতরাং এটি সমস্যার প্রকৃত উত্স হিসাবে সাধারণত খুব কম বা কোনও তথ্য সরবরাহ করে না।জুলাই ২০১২ আপডেট করুন, প্রায় চার বছর পরে:
এটি এখন (২০১২) " এপিআই মাইগ্রেশন সামঞ্জস্য বিধি (স্বাক্ষর পরীক্ষা) " এ বিশদে রয়েছে
জাভা প্রোগ্রামিং ল্যাঙ্গুয়েজ মুছে ফেলা ব্যবহার করে জেনেরিক প্রয়োগ করে, যা নিশ্চিত করে যে লিগ্যাসি এবং জেনেরিক সংস্করণগুলি প্রকারগুলি সম্পর্কে কিছু সহায়ক তথ্য ব্যতীত সাধারণত অভিন্ন শ্রেণি ফাইল তৈরি করে। বাইনারি সামঞ্জস্যতা ভাঙা হয়নি কারণ কোনও ক্লায়েন্ট কোড পরিবর্তন বা পুনরায় সংশোধন না করে জেনেরিক ক্লাস ফাইলের সাথে উত্তরাধিকার শ্রেণির ফাইলটি প্রতিস্থাপন করা সম্ভব।
নন-জেনেরিক লেগ্যাসি কোডের সাথে হস্তক্ষেপের সুবিধার্থে, প্যারামিটারাইজড টাইপের ক্ষয়টি একটি প্রকার হিসাবে ব্যবহার করাও সম্ভব। এই জাতীয় প্রকারকে কাঁচা টাইপ ( জাভা ভাষার স্পেসিফিকেশন 3 / 4.8 ) বলা হয়। কাঁচা ধরণের অনুমতি দেওয়া উত্স কোডের জন্য পশ্চাদপটে সামঞ্জস্যতাও নিশ্চিত করে।
এই অনুসারে,
java.util.Iterator
শ্রেণীর নিম্নলিখিত সংস্করণগুলি বাইনারি এবং উত্স কোড উভয় পশ্চাদপটে সামঞ্জস্যপূর্ণ:
Class java.util.Iterator as it is defined in Java SE version 1.4:
public interface Iterator {
boolean hasNext();
Object next();
void remove();
}
Class java.util.Iterator as it is defined in Java SE version 5.0:
public interface Iterator<E> {
boolean hasNext();
E next();
void remove();
}
ইতিমধ্যে পরিপূরক জন স্কিট উত্তরটি পরিপূরক করছে ...
এটি উল্লেখ করা হয়েছে যে মুছে ফেলার মাধ্যমে জেনেরিকগুলি প্রয়োগ করা কিছু বিরক্তিকর সীমাবদ্ধতার দিকে নিয়ে যায় (উদাঃ না new T[42]
)। এটি আরও উল্লেখ করা হয়েছে যে এভাবে কাজগুলি করার প্রাথমিক কারণটি বাইটকোডের পিছনে সামঞ্জস্য ছিল। এটিও (বেশিরভাগ ক্ষেত্রে) সত্য। বাইটকোড উত্পাদিত -আমার্জাম 1.5 কেবল ডি-সুগার্ড কাস্টিং -রেটেজ 1.4 থেকে কিছুটা আলাদা। প্রযুক্তিগতভাবে, রানটাইমে জেনেরিক ধরণের ইনস্ট্যান্টেশনগুলিতে অ্যাক্সেস অর্জন (এমনকি প্রচুর ট্র্যাকারির মাধ্যমে) এমনকি সম্ভব , প্রমাণ করে যে বাইটকোডে আসলেই কিছু আছে।
আরও আকর্ষণীয় বিষয় (যা উত্থাপিত হয়নি) হ'ল ইরেজারের সাহায্যে জেনেরিকগুলি প্রয়োগ করা উচ্চ-স্তরের টাইপ সিস্টেমটি কী সম্পাদন করতে পারে তাতে কিছুটা আরও নমনীয়তা সরবরাহ করে। এর একটি ভাল উদাহরণ স্কেলার জেভিএম বাস্তবায়ন বনাম সিএলআর হবে। জেভিএম-তে, উচ্চতর প্রকারগুলি সরাসরি বাস্তবায়িত করা সম্ভব যে জেভিএম নিজে জেনেরিক ধরণের উপর কোনও বিধিনিষেধ আরোপ করে না (যেহেতু এই "প্রকারগুলি" কার্যকরভাবে অনুপস্থিত)। এটি সিএলআরের সাথে বিপরীতে রয়েছে, যার প্যারামিটার ইনস্ট্যান্টেশনের রানটাইম জ্ঞান রয়েছে। এ কারণে, জেনেরিকগুলি কীভাবে ব্যবহার করা উচিত সে সম্পর্কে সিএলআর নিজেই কিছু ধারণা থাকতে হবে, অপ্রত্যাশিত নিয়ম সহ সিস্টেমকে প্রসারিত করার প্রচেষ্টা বাতিল করে দেয়। ফলস্বরূপ, সিএলআর-এ স্কালার উচ্চতর ধরণেরগুলি সঙ্কলনের মধ্যেই ইমুলেটেড একটি অদ্ভুত রূপ ব্যবহার করে প্রয়োগ করা হয়,
আপনি রানটাইমের সময় দুষ্টু কাজ করতে চাইলে ক্ষয়ের অসুবিধা হতে পারে তবে সংকলক লেখকদের কাছে এটি সবচেয়ে নমনীয়তা দেয়। আমি অনুমান করছি যে কেন এটি খুব শীঘ্রই কোনও সময় চলে যাচ্ছে না of
যেহেতু আমি এটি বুঝতে পারি (। নেট লোক হিসাবে) জেভিএম জেনেরিকের কোনও ধারণা নেই, তাই সংকলকটি বস্তুর সাথে টাইপ পরামিতিগুলি প্রতিস্থাপন করে এবং আপনার জন্য সমস্ত কাস্টিং সম্পাদন করে।
এর অর্থ জাভা জেনেরিকগুলি সিনট্যাক্স চিনির ব্যতীত আর কিছুই নয় এবং রেফারেন্সের মাধ্যমে পাস করার সময় বক্সিং / আনবক্সিংয়ের প্রয়োজনীয় মানগুলির জন্য কোনও পারফরম্যান্স উন্নতি সরবরাহ করে না।
ভাল ব্যাখ্যা আছে। আমি কেবল উদাহরণটি যুক্ত করে দেখি কীভাবে ডেস্পপাইলার দিয়ে মুছে ফেলা যায়।
আসল ক্লাস,
import java.util.ArrayList;
import java.util.List;
public class S<T> {
T obj;
S(T o) {
obj = o;
}
T getob() {
return obj;
}
public static void main(String args[]) {
List<String> list = new ArrayList<>();
list.add("Hello");
// for-each
for(String s : list) {
String temp = s;
System.out.println(temp);
}
// stream
list.forEach(System.out::println);
}
}
এর বাইটোকোড থেকে কোড বিভক্ত করা,
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Objects;
import java.util.function.Consumer;
public class S {
Object obj;
S(Object var1) {
this.obj = var1;
}
Object getob() {
return this.obj;
}
public static void main(String[] var0) {
ArrayList var1 = new ArrayList();
var1.add("Hello");
// for-each
Iterator iterator = var1.iterator();
while (iterator.hasNext()) {
String string;
String string2 = string = (String)iterator.next();
System.out.println(string2);
}
// stream
PrintStream printStream = System.out;
Objects.requireNonNull(printStream);
var1.forEach(printStream::println);
}
}
জেনারিস কেন ব্যবহার করুন
সংক্ষেপে, জেনেরিক্স ক্লাস, ইন্টারফেস এবং পদ্ধতিগুলি সংজ্ঞায়িত করার সময় প্রকারগুলি (শ্রেণি এবং ইন্টারফেস) প্যারামিটার হিসাবে সক্ষম করে। পদ্ধতি ঘোষণাতে ব্যবহৃত আরও পরিচিত ফর্মাল প্যারামিটারগুলির মতো, টাইপ প্যারামিটারগুলি আপনাকে বিভিন্ন ইনপুট সহ একই কোডটি পুনরায় ব্যবহার করার একটি উপায় সরবরাহ করে। পার্থক্যটি হ'ল আনুষ্ঠানিক পরামিতিগুলির ইনপুটগুলি মান হয়, যখন পরামিতিগুলি টাইপ করার ইনপুটগুলি হয়। জেনেরিকগুলি ব্যবহার করে এমন অড জেনেরিক কোডের চেয়ে অনেকগুলি সুবিধা রয়েছে:
টাইপ ইরেজোর কী
সংকলন সময়ে শক্ততর প্রকারের চেক সরবরাহ এবং জেনেরিক প্রোগ্রামিং সমর্থন করার জন্য জেনারিকসটি জাভা ভাষার সাথে প্রবর্তিত হয়েছিল। জেনেরিকগুলি প্রয়োগ করতে, জাভা সংকলক প্রকারটি মুছে ফেলার জন্য প্রযোজ্য:
[এনবি] - সেতু পদ্ধতি কী? শীঘ্রই, প্যারামিটারাইজড ইন্টারফেসের ক্ষেত্রে যেমন Comparable<T>
, এটি সংকলক দ্বারা অতিরিক্ত পদ্ধতি methodsোকাতে পারে; এই অতিরিক্ত পদ্ধতিগুলিকে সেতু বলা হয়।
কিভাবে ক্ষয় কাজ করে
কোনও প্রকারের ক্ষয়টি নিম্নরূপে সংজ্ঞায়িত করা হয়: পরামিতিযুক্ত ধরণের থেকে সমস্ত প্রকারের প্যারামিটারগুলি ফেলে দিন এবং যেকোন প্রকারের ভেরিয়েবলটিকে তার বাউন্ডের ক্ষয়ের সাথে প্রতিস্থাপন করুন বা অবজেক্টের সাথে যদি তার কোনও আবদ্ধ না হয়, বা বামদিকের আবদ্ধতার মুছে ফেলুন একাধিক সীমা এখানে কিছু উদাহরন:
List<Integer>
, List<String>
এবং List<List<String>>
হয় List
।List<Integer>[]
হয় List[]
।List
নিজেই, একইভাবে কোনও কাঁচা ধরণের জন্য।Integer
নিজেই হয়, একইভাবে কোনও ধরণের পরামিতি ছাড়াই।T
সংজ্ঞা এর মুছে ফেলা asList
হয় Object
, কারণ T
কোন আবদ্ধ আছে।T
সংজ্ঞা এর মুছে ফেলা max
হয় Comparable
, কারণ T
আবদ্ধ Comparable<? super T>
।T
এর চূড়ান্ত সংজ্ঞায়নের ক্ষয়টি max
হ'ল Object
, কারণ
T
এটি আবদ্ধ হয়েছে Object
এবং Comparable<T>
এবং আমরা বাম দিকের আবদ্ধতার ক্ষয়টি গ্রহণ করি।জেনেরিকগুলি ব্যবহার করার সময় সাবধান হওয়া দরকার
জাভাতে দুটি স্বতন্ত্র পদ্ধতিতে একই স্বাক্ষর থাকতে পারে না। যেহেতু জেনেরিকগুলি মুছে ফেলার মাধ্যমে প্রয়োগ করা হয়, এটি আরও অনুসরণ করে যে দুটি স্বতন্ত্র পদ্ধতিতে একই ক্ষয়ের সাথে স্বাক্ষর থাকতে পারে না। একটি শ্রেণি দুটি পদ্ধতির ওভারলোড করতে পারে না যার স্বাক্ষরগুলির একই ক্ষয় হয় এবং একটি শ্রেণি দুটি মুছা একই ইন্টাররেস প্রয়োগ করতে পারে না।
class Overloaded2 {
// compile-time error, cannot overload two methods with same erasure
public static boolean allZero(List<Integer> ints) {
for (int i : ints) if (i != 0) return false;
return true;
}
public static boolean allZero(List<String> strings) {
for (String s : strings) if (s.length() != 0) return false;
return true;
}
}
আমরা এই কোডটি নিম্নরূপে কাজ করার ইচ্ছা করি:
assert allZero(Arrays.asList(0,0,0));
assert allZero(Arrays.asList("","",""));
তবে, এক্ষেত্রে উভয় পদ্ধতির স্বাক্ষরের ক্ষয়গুলি অভিন্ন:
boolean allZero(List)
সুতরাং, সংকলনের সময় একটি নাম সংঘর্ষের খবর পাওয়া গেছে। উভয় পদ্ধতির একই নাম দেওয়া এবং ওভারলোডিংয়ের মাধ্যমে তাদের মধ্যে পার্থক্য করার চেষ্টা করা সম্ভব নয়, কারণ ক্ষয়ের পরে একটি পদ্ধতির কলকে অন্যের থেকে আলাদা করা অসম্ভব।
আশা করি, পাঠক উপভোগ করবেন :)