জাভা 8: জাভা.লাং.অবজেক্ট থেকে কোনও পদ্ধতির জন্য ডিফল্ট পদ্ধতিটি নির্ধারণ করা কেন নিষিদ্ধ?


130

ডিফল্ট পদ্ধতিগুলি আমাদের জাভা টুলবক্সে একটি দুর্দান্ত নতুন সরঞ্জাম। তবে, আমি একটি ইন্টারফেস লেখার চেষ্টা করেছি defaultযা toStringপদ্ধতির একটি সংস্করণ সংজ্ঞায়িত করে । জাভা আমাকে জানায় যে এটি নিষিদ্ধ, যেহেতু ঘোষিত পদ্ধতিগুলি সম্পাদনা java.lang.Objectনাও করা যেতে পারে default। কেন এই ক্ষেত্রে?

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

সুতরাং, জাভা ডিজাইনাররা defaultপদ্ধতিগুলি ওভাররাইডিং পদ্ধতিগুলিকে অনুমতি না দেওয়ার সিদ্ধান্ত নিয়েছিলেন কেন Object?


1
আমি এখন নিজের সম্পর্কে খুব ভাল বোধ করছি, এটি 100 বারের জন্য উত্সাহিত করে এবং এইভাবে সোনার ব্যাজ। ভাল প্রশ্ন!
ইউজিন

উত্তর:


186

এটি এখনও সেই ভাষা নকশাগুলির আর একটি বিষয় যা আপনি খনন শুরু না করা এবং আপনি বুঝতে না পারছেন যে এটি আসলে একটি খারাপ ধারণা।

এই মেলটিতে এই বিষয়ে অনেক কিছুই রয়েছে (এবং অন্যান্য বিষয়েও।) বেশ কয়েকটি ডিজাইন ফোর্স ছিল যা আমাদের বর্তমান নকশায় নিয়ে এসেছিল:

  • উত্তরাধিকারের মডেলটি সহজ রাখার ইচ্ছা;
  • সত্য যে একবার আপনি স্পষ্ট উদাহরণগুলি (যেমন, AbstractListএকটি ইন্টারফেসে রূপান্তরিত ) অতীতের দিকে তাকান , আপনি বুঝতে পারবেন যে উত্তরাধিকার সমান / হ্যাশকোড / টুস্ট্রিং একক উত্তরাধিকার এবং রাষ্ট্রের সাথে দৃ strongly়ভাবে আবদ্ধ এবং ইন্টারফেসগুলি বহুগুণ উত্তরাধিকারসূত্রে এবং রাষ্ট্রহীন;
  • এটি সম্ভবত কিছু আশ্চর্যজনক আচরণের দরজা খুলে দিয়েছে।

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

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

AbstractListউদাহরণটি বের করা সহজ ; এটি সুন্দর হবে যদি আমরা AbstractListআচরণ থেকে মুক্তি পেয়ে Listইন্টারফেসে রাখতে পারি। তবে একবার আপনি এই সুস্পষ্ট উদাহরণের বাইরে চলে গেলে আর অনেক ভাল উদাহরণ পাওয়া যায় না। মূলটি, AbstractListএকক উত্তরাধিকারের জন্য ডিজাইন করা হয়েছে। তবে ইন্টারফেসগুলি একাধিক উত্তরাধিকারের জন্য ডিজাইন করা আবশ্যক।

আরও, আপনি এই ক্লাসটি লিখছেন তা কল্পনা করুন:

class Foo implements com.libraryA.Bar, com.libraryB.Moo { 
    // Implementation of Foo, that does NOT override equals
}

FooSupertypes এ লেখক সৌন্দর্য, সমান কোন বাস্তবায়ন দেখেন, এবং যে রেফারেন্স সমতা পেতে উপসংহারে, সমস্ত তিনি প্রয়োজন থেকে উত্তরাধিকারী সমান হয় Object। তারপরে, পরের সপ্তাহে, বারের জন্য লাইব্রেরি রক্ষণাবেক্ষণকারী "সহায়কভাবে" একটি ডিফল্ট equalsবাস্তবায়ন যুক্ত করে। ওপস! এখন এর অর্থশাস্ত্রগুলি Fooঅন্য একটি রক্ষণাবেক্ষণ ডোমেনের "ইন্টারফেসলি" একটি সাধারণ পদ্ধতির জন্য একটি ডিফল্ট যোগ করে একটি ইন্টারফেস দ্বারা ভেঙে গেছে।

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

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


13
আমি আনন্দিত যে আপনি এটি ব্যাখ্যা করতে সময় নিয়েছিলেন এবং আমি বিবেচনা করা সমস্ত কারণগুলির প্রশংসা করি। আমি সম্মত হই যে এটি বিপজ্জনক হবে hashCodeএবং এর জন্য equals, তবে আমি মনে করি এটি এর জন্য খুব কার্যকর হবে toString। উদাহরণস্বরূপ, কিছু Displayableইন্টারফেস একটি String display()পদ্ধতি সংজ্ঞায়িত করতে পারে এবং এটি একটি টোন বয়লারপ্লেট বাছাই করতে সক্ষম হবে যা সংজ্ঞায়িত করতে সক্ষম হবে , পরিবর্তে প্রতিটি একককে বেস ক্লাস প্রয়োগ বা প্রসারিত করার প্রয়োজন হবে default String toString() { return display(); }না । DisplayableDisplayabletoString()DisplayableToString
ব্র্যান্ডন

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

5
@ জ্যাক্সিকাইড যদি toString()কেবল ইন্টারফেসের পদ্ধতির উপর ভিত্তি করে থাকে তবে আপনি কেবল default String toStringImpl()ইন্টারফেসের মতো কিছু যুক্ত করতে পারেন এবং toString()ইন্টারফেস বাস্তবায়নের জন্য প্রতিটি সাবক্লাসে ওভাররাইড করতে পারেন - কিছুটা কুৎসিত, তবে কাজ করে, আর কিছুই না থেকে ভাল। আরেকটি উপায় এটা ভালো কিছু করা হয় না :) Objects.hash(), Arrays.deepEquals()এবং Arrays.deepToString()। @ ব্রায়ানগোয়েজের উত্তরটির জন্য +1 করেছেন!
সিউ চিং পং-আসুকা কেনজি-

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

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

30

ক্ষেত্রে পদ্ধতিগুলির জন্য ইন্টারফেসে ডিফল্ট পদ্ধতিগুলি নির্ধারণ করা নিষিদ্ধ java.lang.Object, যেহেতু ডিফল্ট পদ্ধতিগুলি কখনই "পৌঁছনীয়" হতে পারে না।

ইন্টারফেস প্রয়োগকারী ক্লাসগুলিতে ডিফল্ট ইন্টারফেস পদ্ধতিগুলি ওভাররাইট করা যেতে পারে এবং পদ্ধতিটি একটি সুপারক্লাসে প্রয়োগ করা হলেও, পদ্ধতির শ্রেণিকরণ ইন্টারফেস প্রয়োগের চেয়ে উচ্চতর প্রাধান্য পায়। যেহেতু সমস্ত শ্রেণি উত্তরাধিকার সূত্রে প্রাপ্ত java.lang.Object, তাই পদ্ধতিগুলি java.lang.Objectইন্টারফেসে ডিফল্ট পদ্ধতির চেয়ে প্রাধান্য পাবে এবং পরিবর্তে ডাকা হবে।

ওরাকল থেকে আসা ব্রায়ান গোয়েট এই মেইলিং তালিকা পোস্টে নকশার সিদ্ধান্ত সম্পর্কে আরও কয়েকটি বিশদ সরবরাহ করে ।


3

আমি জাভা ভাষার লেখকদের মাথাতে দেখি না, তাই আমরা কেবল অনুমান করতে পারি। তবে আমি অনেকগুলি কারণ দেখছি এবং এই ইস্যুতে তাদের সাথে একমত আছি।

ডিফল্ট পদ্ধতিগুলি প্রবর্তনের মূল কারণ হ'ল পুরানো প্রয়োগগুলির পশ্চাদপদ সামঞ্জস্যতা না ভেঙে ইন্টারফেসগুলিতে নতুন পদ্ধতি যুক্ত করতে সক্ষম হওয়া। ডিফল্ট পদ্ধতিগুলি প্রয়োগকারী প্রতিটি ক্লাসে তাদের সংজ্ঞায়িত করার প্রয়োজন ছাড়াই "সুবিধা" পদ্ধতিগুলি সরবরাহ করতে ব্যবহৃত হতে পারে।

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

"বেস ক্লাস সর্বদা জিতে যায়" নিয়মেরও এর শক্ত কারণ রয়েছে। ধারণা করা হয় যে ক্লাসগুলি বাস্তব বাস্তবায়নগুলি সংজ্ঞায়িত করে , যখন ইন্টারফেসগুলি ডিফল্ট বাস্তবায়নগুলি সংজ্ঞায়িত করে , যা কিছুটা দুর্বল।

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

সর্বোপরি, আপনি যে সমাধানটি প্রস্তাব করবেন এটি সম্ভবত পেশাদারদের চেয়ে বেশি বিপর্যয় আনবে।


আমার পোস্ট করার সময় আমি জেক্সিকাইডের উত্তরের দ্বিতীয় অনুচ্ছেদটি লক্ষ্য করিনি। এটিতে একটি লিঙ্ক রয়েছে যা আরও বিস্তারিতভাবে বিষয়টি ব্যাখ্যা করে।
মারউইন

1

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


1

খুব পেডেন্টিক উত্তর দিতে, কেবলমাত্র defaultকোনও জনসাধারণের পদ্ধতির জন্য কোনও পদ্ধতির সংজ্ঞা দেওয়া নিষিদ্ধ java.lang.Object। এখানে 11 টি পদ্ধতি বিবেচনা করতে হবে, যা এই প্রশ্নের উত্তর দেওয়ার জন্য তিনটি উপায়ে শ্রেণিবদ্ধ করা যেতে পারে।

  1. ছয় Objectপদ্ধতি থাকতে পারে না defaultপদ্ধতি কারণ তারা finalএবং এ সব উপেক্ষিত হতে পারে না: getClass(), notify(), notifyAll(), wait(), wait(long), এবং wait(long, int)
  2. তিন Objectপদ্ধতি থাকতে পারে না defaultব্রায়ান Goetz দ্বারা দেওয়া উপরোক্ত কারণে পদ্ধতি: equals(Object), hashCode(), এবং toString()
  3. দুটি Objectপদ্ধতিতে পদ্ধতি থাকতে পারে default, যদিও এই জাতীয় খেলাপির মান সর্বোত্তমভাবে প্রশ্নবিদ্ধ: clone()এবং finalize()

    public class Main {
        public static void main(String... args) {
            new FOO().clone();
            new FOO().finalize();
        }
    
        interface ClonerFinalizer {
            default Object clone() {System.out.println("default clone"); return this;}
            default void finalize() {System.out.println("default finalize");}
        }
    
        static class FOO implements ClonerFinalizer {
            @Override
            public Object clone() {
                return ClonerFinalizer.super.clone();
            }
            @Override
            public void finalize() {
                ClonerFinalizer.super.finalize();
            }
        }
    }

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