তালিকার তালিকায় কাস্ট করার সর্বাধিক দক্ষ উপায় <সাবস্ক্লাস> <BaseClass>


134

আমি একটি List<SubClass>হিসাবে আমি চিকিত্সা করতে চান List<BaseClass>। এটি দেখে মনে হচ্ছে এটা ঢালাই একটি যেহেতু একটি সমস্যা হওয়ার কথা নয় SubClassএকটি থেকে BaseClassএকটি স্ন্যাপ, কিন্তু আমার কম্পাইলার অভিযোগ যে ঢালাই অসম্ভব।

সুতরাং, একই হিসাবে একই জিনিসগুলির রেফারেন্স পাওয়ার সর্বোত্তম উপায় List<BaseClass>কী?

এই মুহূর্তে আমি কেবল একটি নতুন তালিকা তৈরি করছি এবং পুরাতন তালিকাটি অনুলিপি করছি:

List<BaseClass> convertedList = new ArrayList<BaseClass>(listOfSubClass)

আমি যেমন বুঝতে পেরেছি তবে এটি সম্পূর্ণ নতুন তালিকা তৈরি করতে হবে। আমি সম্ভব হলে মূল তালিকার একটি রেফারেন্স চাই!


3
উত্তর এখানে আছে: stackoverflow.com/questions/662508/...
lukastymo

উত্তর:


175

এই ধরণের অ্যাসাইনমেন্টের বাক্য গঠনটি একটি ওয়াইল্ডকার্ড ব্যবহার করে:

List<SubClass> subs = ...;
List<? extends BaseClass> bases = subs;

এটা উপলব্ধি করা যে একটি গুরুত্বপূর্ণ List<SubClass>হয় না একটি সঙ্গে বিনিমেয় List<BaseClass>। কোড যা একটি রেফারেন্স ধরে রেখেছে List<SubClass>তালিকার প্রতিটি আইটেম একটি হতে পারে বলে আশা করবে SubClass। কোডের অন্য একটি অংশ যদি তালিকা হিসাবে উল্লেখ করা হয় List<BaseClass>, সংকলক কোনও BaseClassবা inোকানো হবে না তখন অভিযোগ করবে না AnotherSubClass। তবে এটি ClassCastExceptionকোডের প্রথম টুকরোটির জন্য একটি কারণ তৈরি করবে , যা ধরে নেবে যে তালিকার সমস্ত কিছুই একটি SubClass

জেনেরিক সংগ্রহগুলি জাভাতে অ্যারের মতো আচরণ করে না। অ্যারেগুলি সমবায়; অর্থাৎ এটি করার অনুমতি দেওয়া হয়েছে:

SubClass[] subs = ...;
BaseClass[] bases = subs;

এটি অনুমোদিত, কারণ অ্যারে তার উপাদানগুলির প্রকারটি "জানে"। যদি কেউ এমন কোনও কিছু সঞ্চয় করতে চেষ্টা করে SubClassযা অ্যারের উদাহরণ হিসাবে না হয় ( basesরেফারেন্সের মাধ্যমে ), একটি রানটাইম ব্যতিক্রম নিক্ষেপ করা হবে।

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


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

বিশেষত দুটি তালিকা কেন একই বিবেচনা করা যায় না তার ব্যাখ্যার জন্য ধন্যবাদ।
রিলে লার্ক

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

38

আপনি কেন এটি করতে পারবেন না তা এরিকন ইতিমধ্যে ব্যাখ্যা করেছেন, তবে এখানে কিছু সমাধান:

যদি আপনি কেবলমাত্র আপনার বেস তালিকা থেকে উপাদানগুলি নিতে চান, নীতিগতভাবে আপনার গ্রহণ পদ্ধতিটি গ্রহণ করার হিসাবে ঘোষণা করা উচিত List<? extends BaseClass>

তবে যদি তা না হয় এবং আপনি এটি পরিবর্তন করতে না পারেন তবে আপনি তালিকাটি মোড়াতে পারেন Collections.unmodifiableList(...)যা আর্গুমেন্টের প্যারামিটারের একটি সুপারটাইপের একটি তালিকা ফেরত দেওয়ার অনুমতি দেয়। (এটি সন্নিবেশনের চেষ্টাগুলিতে অসমর্থিত অপারেশন এক্সেক্সশন নিক্ষেপ করে টাইপসফটি সমস্যাটি এড়ায়))


গ্রেট! ওটা জানতাম না।
কেউলেজে

আপনাকে অনেক ধন্যবাদ!
ওোল্যান্ড

14

@ এরিকসন যেমন ব্যাখ্যা করেছেন, আপনি যদি সত্যিই মূল তালিকার কোনও রেফারেন্স চান তবে নিশ্চিত হন যে কোনও কোডই যদি সেই তালিকাটিতে আবার কোনওরকম তার মূল ঘোষণার অধীনে ব্যবহার করতে না চান তবে নিশ্চিত করুন। এটির সর্বাধিক সহজ উপায় হ'ল এটি কেবল একটি সরল পুরানো অজেনারিক তালিকায় কাস্ট করা:

List<BaseClass> baseList = (List)new ArrayList<SubClass>();

তালিকার কী হয় তা আপনি যদি না জানেন এবং আমি আপনাকে প্রস্তাব দিচ্ছি যে তালিকাটি যা আপনার প্রয়োজন সেই তালিকাটি মেনে নেওয়ার জন্য তালিকা পরিবর্তন করুন suggest


3

নীচে একটি দরকারী স্নিপেট যা কাজ করে। এটি একটি নতুন অ্যারে তালিকা তৈরি করে তবে JVM অবজেক্টের মাথার উপরের গঠন তাৎপর্যপূর্ণ।

আমি দেখেছি অন্যান্য উত্তরগুলি অগত্যা জটিল।

List<BaseClass> baselist = new ArrayList<>(sublist);

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

ওভারহেড তুচ্ছ নয়, কারণ এটি প্রতিটি রেফারেন্সটি (অগভীর) অনুলিপি করতে হয়। যেমন এটি তালিকার আকারের সাথে স্কেল করে, সুতরাং এটি একটি ও (এন) অপারেশন।
john16384

2

ডাবল কাস্ট ব্যবহার করে আপনি যেখানে সবেমাত্র মূল তালিকাটি কাস্ট করেছেন সে উত্তরটি আমি মিস করেছি। সুতরাং এখানে এটি সম্পূর্ণতার জন্য:

List<BaseClass> baseList = (List<BaseClass>)(List<?>)subList;

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


1

List<BaseClass> convertedList = Collections.checkedList(listOfSubClass, BaseClass.class)


5
এটি কাজ করা উচিত নয়, কারণ এই পদ্ধতির জন্য সমস্ত যুক্তি এবং ফলাফল একই ধরণের পরামিতি নেয়।
পাওলো ইবারম্যান

অদ্ভুত, আপনি ঠিক বলেছেন। কোনও কারণে, আমি ছাপের মধ্যে ছিলাম এই পদ্ধতিটি জেনেরিক সংগ্রহের উপক্রমের জন্য কার্যকর। তবুও এইভাবে ব্যবহার করা যেতে পারে এবং আপনি দমনের ব্যবহারগুলি ব্যবহার করতে চাইলে এটি একটি "নিরাপদ" সংগ্রহ সরবরাহ করবে।
jtahlorn

1

আপনি যা করার চেষ্টা করছেন তা খুব দরকারী এবং আমি খুঁজে পেয়েছি যে আমি যে কোডটি লিখছি তা আমার প্রায়শই এটি করা দরকার। উদাহরণ ব্যবহারের ক্ষেত্রে:

বলুন আমাদের একটি ইন্টারফেস রয়েছে Fooএবং আমাদের একটি zorkingপ্যাকেজ রয়েছে যা একটি ZorkingFooManagerপ্যাকেজ-প্রাইভেটের উদাহরণ তৈরি করে এবং পরিচালনা করে ZorkingFoo implements Foo। (একটি খুব সাধারণ দৃশ্য।)

সুতরাং, ZorkingFooManagerএকটি ধারণ করা দরকার private Collection<ZorkingFoo> zorkingFoosতবে এটি একটি প্রকাশ করা প্রয়োজন public Collection<Foo> getAllFoos()

বেশিরভাগ জাভা প্রোগ্রামাররা getAllFoos()নতুন বরাদ্দ হিসাবে প্রয়োগের আগে দুবার ভাবেন না ArrayList<Foo>, এটিকে সমস্ত উপাদান দিয়ে এটিকে জনবহুল করে zorkingFoosফিরে আসে returning আমি এই ভাবনাটি উপভোগ করতে পেরেছি যে সমগ্র গ্রহের লক্ষ লক্ষ মেশিনে চলমান জাভা কোড দ্বারা গ্রাহিত সমস্ত ঘড়ির চক্রের প্রায় 30% আরেলিস্টগুলির অনর্থক অনুলিপি তৈরি করা ছাড়া কিছুই করছে না যা তাদের সৃষ্টির পরে আবর্জনা-সংগৃহীত মাইক্রোসেকেন্ড রয়েছে।

এই সমস্যার সমাধান অবশ্যই সংগ্রহটি ডাউন কাস্টিং is এটি করার সর্বোত্তম উপায় এখানে:

static <T,U extends T> List<T> downCastList( List<U> list )
{
    return castList( list );
}

যা আমাদের castList()ফাংশনে নিয়ে আসে :

static <T,E> List<T> castList( List<E> list )
{
    @SuppressWarnings( "unchecked" )
    List<T> result = (List<T>)list;
    return result;
}

মধ্যবর্তী result পরিবর্তনশীল জাভা ভাষার একটি বিকৃতি কারণে প্রয়োজনীয়:

  • return (List<T>)list;একটি "চেক না করা castালাই" ব্যতিক্রম উত্পাদন করে; এ পর্যন্ত সব ঠিকই; কিন্তু তারপর:

  • @SuppressWarnings( "unchecked" ) return (List<T>)list; দমন-সতর্কতা টীকাটির অবৈধ ব্যবহার।

সুতরাং, যদিও @SuppressWarningsকোনও returnবিবৃতিতে কোশার ব্যবহার করা ঠিক নয় , এটি একটি অ্যাসাইনমেন্টে এটি ব্যবহার করা স্পষ্টতই ভাল, সুতরাং অতিরিক্ত "ফলাফল" পরিবর্তনশীল এই সমস্যাটি সমাধান করে। (এটি যেকোনওভাবে সংকলক বা জেআইটি দ্বারা অপ্টিমাইজ করা উচিত))


0

এর মতো কিছুতেও কাজ করা উচিত:

public static <T> List<T> convertListWithExtendableClasses(
    final List< ? extends T> originalList,
    final Class<T> clazz )
{
    final List<T> newList = new ArrayList<>();
    for ( final T item : originalList )
    {
        newList.add( item );
    }// for
    return newList;
}

বাস্তবে জানেন না যে গ্রহণে কেন ঝাঁকুনির প্রয়োজন ..


0

কিভাবে সমস্ত উপাদান castালাই সম্পর্কে। এটি একটি নতুন তালিকা তৈরি করবে, তবে পুরানো তালিকা থেকে মূল বিষয়গুলি উল্লেখ করবে।

List<BaseClass> convertedList = listOfSubClass.map(x -> (BaseClass)x).collect(Collectors.toList());

এটি কোডের সম্পূর্ণ অংশ যা উপ শ্রেণীর তালিকাকে সুপার ক্লাসে কাস্ট করতে কাজ করে।
কানাপার্থিকিরন

0

জেনারিক্স ব্যবহার করে সাব ক্লাসের তালিকাটি সুপার ক্লাসে কাস্ট করতে এটি কোডের সম্পূর্ণ কার্যকারী অংশ।

কলার পদ্ধতি যা সাবক্লাসের ধরণের পাস করে

List<SubClass> subClassParam = new ArrayList<>();    
getElementDefinitionStatuses(subClassParam);

কলি পদ্ধতি যা বেস শ্রেণীর যে কোনও উপ-টাইপ গ্রহণ করে

private static List<String> getElementDefinitionStatuses(List<? extends 
    BaseClass> baseClassVariableName) {
     return allElementStatuses;
    }
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.