একটি ডিফল্ট পদ্ধতি সহ একটি ইন্টারফেস কখন শুরু হয়?


94

জাভা ল্যাঙ্গুয়েজ স্পেসিফিকেশন মাধ্যমে অনুসন্ধান যখন উত্তর দিতে এই প্রশ্নের , আমি শিখেছি যে

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

আমার নিজের কৌতূহলের জন্য, আমি এটি চেষ্টা করেছিলাম এবং প্রত্যাশা অনুযায়ী, ইন্টারফেসটি InterfaceTypeআরম্ভ করা হয়নি।

public class Example {
    public static void main(String[] args) throws Exception {
        InterfaceType foo = new InterfaceTypeImpl();
        foo.method();
    }
}

class InterfaceTypeImpl implements InterfaceType {
    @Override
    public void method() {
        System.out.println("implemented method");
    }
}

class ClassInitializer {
    static {
        System.out.println("static initializer");
    }
}

interface InterfaceType {
    public static final ClassInitializer init = new ClassInitializer();

    public void method();
}

এই প্রোগ্রাম প্রিন্ট

implemented method

যাইহোক, যদি ইন্টারফেসটি কোনও defaultপদ্ধতি ঘোষণা করে , তবে আরম্ভটি ঘটে। InterfaceTypeহিসাবে দেওয়া ইন্টারফেস বিবেচনা করুন

interface InterfaceType {
    public static final ClassInitializer init = new ClassInitializer();

    public default void method() {
        System.out.println("default method");
    }
}

তারপরে উপরের একই প্রোগ্রামটি মুদ্রণ করবে

static initializer  
implemented method

অন্য কথায়, static ইন্টারফেসের ক্ষেত্রটি সূচনা করা হয় ( বিশদ ইনিশিয়ালাইজেশন পদ্ধতিতে পদক্ষেপ 9 ) এবং staticপ্রারম্ভিক হওয়া ধরণের প্রাথমিককরণটি কার্যকর করা হয় exec এর অর্থ হল ইন্টারফেসটি আরম্ভ করা হয়েছিল।

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


4
আমার অনুমানটি হ'ল - এই জাতীয় ইন্টারফেসগুলি আরম্ভের ক্রমের দিক থেকে বিমূর্ত শ্রেণি বিবেচনা করে। আমি এটি একটি মন্তব্য হিসাবে লিখেছিলাম কারণ আমি নিশ্চিত যে এটি সঠিক বক্তব্য কিনা :)
আলেক্সি মালাভ

এটি জেএলএসের 12.4 বিভাগে হওয়া উচিত, তবে সেখানে উপস্থিত হবে না। আমি বলছি এটি অনুপস্থিত।
ওয়ারেন শিশ

4
কিছু মনে করবেন না .... সময় যখন তারা বোঝেন না বা একটি ব্যাখ্যা তারা downvote হবে না অধিকাংশ :( .এই তাই সাধারণত ঘটে।
NeverGiveUp161

আমি ভেবেছিলাম যে interfaceজাভাতে কোনও কংক্রিট পদ্ধতি সংজ্ঞায়িত করা উচিত নয়। সুতরাং আমি বিস্মিত যে InterfaceTypeকোডটি সংকলিত হয়েছে।
ম্যাক্সজুম

উত্তর:


85

এটি একটি খুব আকর্ষণীয় ইস্যু!

দেখে মনে হচ্ছে জেএলএস বিভাগ 12.4.1 এর অবশ্যই এটি আবশ্যক। তবে ওরাকল জেডিকে এবং ওপেনজেডিকে (জাভাক এবং হটস্পট) এর আচরণ এখানে নির্দিষ্ট করা থেকে পৃথক। বিশেষত, এই বিভাগ থেকে 12.4.1.3 উদাহরণটি ইন্টারফেসের সূচনাটি অন্তর্ভুক্ত করে। উদাহরণস্বরূপ:

interface I {
    int i = 1, ii = Test.out("ii", 2);
}
interface J extends I {
    int j = Test.out("j", 3), jj = Test.out("jj", 4);
}
interface K extends J {
    int k = Test.out("k", 5);
}
class Test {
    public static void main(String[] args) {
        System.out.println(J.i);
        System.out.println(K.j);
    }
    static int out(String s, int i) {
        System.out.println(s + "=" + i);
        return i;
    }
}

এর প্রত্যাশিত আউটপুটটি হ'ল:

1
j=3
jj=4
3

এবং প্রকৃতপক্ষে আমি প্রত্যাশিত আউটপুট পেতে। তবে ইন্টারফেসে যদি কোনও ডিফল্ট পদ্ধতি যুক্ত হয় I,

interface I {
    int i = 1, ii = Test.out("ii", 2);
    default void method() { } // causes initialization!
}

আউটপুট এতে পরিবর্তিত হয়:

1
ii=2
j=3
jj=4
3

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

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

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

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


6
আমি সরকারী সূত্র চেয়েছি। আমি মনে করি না এটি এর চেয়ে বেশি অফিসিয়াল হয়। সমস্ত বিকাশ দেখতে দুটি দিন দিন।
সোটিরিওস ডেলিমনলিস

48
@ স্টার্টমার্কস " লোকেরা যদি মনে করে এটি আমাকে একটি অন্যায় সুবিধা দেয় ইত্যাদি " => আমরা প্রশ্নের উত্তর পেতে এখানে এসেছি এবং এটি একটি নিখুঁত উত্তর!
assylias

4
একটি পার্শ্ব নোট: জেভিএম স্পেসে এমন একটি বিবরণ রয়েছে যা জেএলএসের অনুরূপ: ডকস.অরাকল.com / javase / specs / jvms / se8 / html / jvms-5.html#jvms-5.5 এটিও আপডেট করা উচিত ।
মার্কো 13

4
@Asslias এবং Sotirios, আপনার মন্তব্যের জন্য ধন্যবাদ। অ্যাসিলিয়াসের মন্তব্যে ১৪ টি উপন্যাসের (এই লেখার পাশাপাশি) তারা কোনও সম্ভাব্য অন্যায়তা সম্পর্কে আমার উদ্বেগকে প্রশমিত করেছে।
স্টুয়ার্ট

4
@ সোরিরিওসডেলিমনোলিস এমন একটি দম্পতি বাগ রয়েছে যা প্রাসঙ্গিক বলে মনে হচ্ছে, জেডিকে -৩০৪৩7575৫ এবং জেডিকে -৩43৩৩১৯০ এবং সেগুলি 8u40-তে স্থির হিসাবে চিহ্নিত হয়েছে। তবে, আচরণটি একই রকম বলে মনে হচ্ছে। এর সাথে জড়িত কিছু জেভিএম স্পেক পরিবর্তনগুলিও ছিল, সুতরাং সম্ভবত ঠিক করা "পুরানো আরম্ভের ক্রমটি পুনরুদ্ধার করুন" ব্যতীত অন্য কিছু।
স্টুয়ার্ট

13

ইন্টারফেসটি আরম্ভ করা হয়নি কারণ ধ্রুবক ক্ষেত্র InterfaceType.init, যা অ ধ্রুবক মান (পদ্ধতি কল) দ্বারা আরম্ভ করা হচ্ছে, কোথাও ব্যবহৃত হয় না।

সংকলনের সময়ে এটি পরিচিত যে ধ্রুবক ইন্টারফেসের ক্ষেত্রটি কোথাও ব্যবহার করা হয় না, এবং ইন্টারফেসটিতে কোনও ডিফল্ট পদ্ধতি নেই (জাভা -8 এ) তাই ইন্টারফেসটি আরম্ভ বা লোড করার প্রয়োজন নেই।

ইন্টারফেস নিম্নলিখিত ক্ষেত্রে প্রাথমিক করা হবে,

  • ধ্রুব ক্ষেত্র আপনার কোড ব্যবহার করা হয়।
  • ইন্টারফেসে একটি ডিফল্ট পদ্ধতি রয়েছে (জাভা 8)

ডিফল্ট পদ্ধতিগুলির ক্ষেত্রে , আপনি প্রয়োগ করছেন InterfaceType। সুতরাং, যদি InterfaceTypeকোনও ডিফল্ট পদ্ধতি থাকে তবে তা প্রয়োগের শ্রেণিতে নিযুক্ত (ব্যবহৃত) হবে । আর ইনিশিয়ালেশন হবে ছবিতে।

তবে, আপনি যদি ইন্টারফেসের ধ্রুবক ক্ষেত্রটি অ্যাক্সেস করতে থাকেন (যা সাধারণ উপায়ে সূচনা হয়), ইন্টারফেসের আরম্ভ করার প্রয়োজন নেই।

নিম্নলিখিত কোড বিবেচনা করুন।

public class Example {
    public static void main(String[] args) throws Exception {
        InterfaceType foo = new InterfaceTypeImpl();
        System.out.println(InterfaceType.init);
        foo.method();
    }
}

class InterfaceTypeImpl implements InterfaceType {
    @Override
    public void method() {
        System.out.println("implemented method");
    }
}

class ClassInitializer {
    static {
        System.out.println("static initializer");
    }
}

interface InterfaceType {
    public static final ClassInitializer init = new ClassInitializer();

    public void method();
}

উপরের ক্ষেত্রে, ইন্টারফেসটি আরম্ভ হবে এবং লোড হবে কারণ আপনি ক্ষেত্রটি ব্যবহার করছেন InterfaceType.init

আপনি ইতিমধ্যে আপনার প্রশ্নে যেভাবে দিয়েছেন তা আমি ডিফল্ট পদ্ধতির উদাহরণ দিচ্ছি না।

জাভা ভাষার স্পেসিফিকেশন এবং উদাহরণ জেএলএস 12.4.1 এ দেওয়া হয়েছে ( উদাহরণটিতে ডিফল্ট পদ্ধতি নেই))


আমি ডিফল্ট পদ্ধতিগুলির জন্য জেএলএস খুঁজে পাই না, দুটি সম্ভাবনা থাকতে পারে

  • জাভা লোকেরা ডিফল্ট পদ্ধতির ক্ষেত্রে বিবেচনা করতে ভুলে গিয়েছিল। (স্পেসিফিকেশন ডক বাগ)
  • তারা কেবল ইন্টারফেসের অ-ধ্রুবক সদস্য হিসাবে ডিফল্ট পদ্ধতিগুলি উল্লেখ করে। (তবে কোথায় উল্লেখ করা হয়নি, আবার স্পেসিফিকেশন ডক বাগ)

আমি ডিফল্ট পদ্ধতির জন্য একটি রেফারেন্স খুঁজছি। ক্ষেত্রটি কেবল এটি দেখানোর জন্য ছিল যে ইন্টারফেসটি আরম্ভ হয়েছিল কিনা।
সোটিরিওস ডেলিমনোলিস

@ সোরিরিওসডেলিমনোলিস আমি ডিফল্ট পদ্ধতির উত্তরের কারণ উল্লেখ করেছি ... তবে দুর্ভাগ্যক্রমে কোনও জেএলএস এখনও ডিফল্ট পদ্ধতির জন্য খুঁজে পায়নি।
কোনও বাগটি

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

আমি মনে করি জাভা লোকেরা ডিফল্ট পদ্ধতির ক্ষেত্রে বিবেচনা করতে ভুলে গিয়েছিল, বা তারা কেবল ডিফল্ট পদ্ধতিগুলিকে ইন্টারফেসের অ-ধ্রুবক সদস্য হিসাবে উল্লেখ করে (আমার অনুমান, কোনও নথিতে সন্ধান করতে পারে না)।
কোনও বাগটি

4
@ কিশনসার্চা গজ্জার: ইন্টারফেসে ধ্রুবক ক্ষেত্র বলতে কী বোঝ? ইন্টারফেসের কোনও পরিবর্তনশীল / ক্ষেত্র ডিফল্টরূপে স্থির চূড়ান্ত।
লোকেশ

10

InstanceKlass.cpp OpenJDK থেকে ফাইল আরম্ভের পদ্ধতি রয়েছে InstanceKlass::initialize_implযে অনুরূপ বিস্তারিত সূচনা পদ্ধতি JLS মধ্যে, যা অনুরূপভাবে পাওয়া যায় সূচনা জেভিএম বৈশিষ্ট অধ্যায়।

এটিতে একটি নতুন পদক্ষেপ রয়েছে যা জেএলএসে উল্লেখ করা হয়নি এবং কোডে উল্লেখ করা জেভিএম বইতে নেই:

// refer to the JVM book page 47 for description of steps
...

if (this_oop->has_default_methods()) {
  // Step 7.5: initialize any interfaces which have default methods
  for (int i = 0; i < this_oop->local_interfaces()->length(); ++i) {
    Klass* iface = this_oop->local_interfaces()->at(i);
    InstanceKlass* ik = InstanceKlass::cast(iface);
    if (ik->has_default_methods() && ik->should_be_initialized()) {
      ik->initialize(THREAD);
    ....
    }
  }
}

সুতরাং এই সূচনাটি স্পষ্টভাবে একটি নতুন পদক্ষেপ 7.5 হিসাবে প্রয়োগ করা হয়েছে । এটি ইঙ্গিত করে যে এই বাস্তবায়ন কিছু নির্দিষ্টকরণ অনুসরণ করেছে, তবে মনে হয় ওয়েবসাইটে লিখিত বিবরণী সেই অনুযায়ী আপডেট করা হয়নি।

সম্পাদনা: একটি রেফারেন্স হিসাবে, প্রতিশ্রুতিবদ্ধ (অক্টোবর ২০১২ থেকে!) যেখানে সম্পর্কিত পদক্ষেপ বাস্তবায়নে অন্তর্ভুক্ত করা হয়েছে: http://hg.openjdk.java.net/jdk8/build/hotspot/rev/4735d2c84362

সম্পাদনা 2: কাকতালীয়ভাবে হটস্পটে ডিফল্ট পদ্ধতি সম্পর্কে এই নথিটি পেয়েছি যার শেষে একটি আকর্ষণীয় পার্শ্ব নোট রয়েছে:

৩.7 বিবিধ

ইন্টারফেসের এখন সেগুলিতে বাইকোড রয়েছে, তাই একটি বাস্তবায়নকারী ক্লাস আরম্ভ করার সময় আমাদের অবশ্যই সেগুলি শুরু করতে হবে।


4
এটি খনন করার জন্য ধন্যবাদ। (+1) এটি হতে পারে যে নতুন "পদক্ষেপ 7.5" অযৌক্তিকভাবে অনুমান থেকে বাদ দেওয়া হয়েছিল, বা এটি প্রস্তাবিত এবং প্রত্যাখ্যান করা হয়েছিল এবং এটি অপসারণের জন্য বাস্তবায়ন কখনও স্থির করা হয়নি।
স্টুয়ার্ট

1

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

এগুলির ক্ষেত্রে class, এটি ভালভাবে গৃহীত হয়েছে যে এটি উপ-শ্রেণীর উপর নির্ভর করে এমন পার্শ্ব প্রতিক্রিয়া সৃষ্টি করতে পারে। উদাহরণ স্বরূপ

class Foo{
    static{
        Bank.deposit($1000);
...

যে কোনও সাবক্লাস Fooআশা করবে যে তারা সাবক্লাস কোডের যে কোনও জায়গায় ব্যাঙ্কে 1000 ডলার দেখবে। অতএব সুপারক্লাস সাবক্লাসের আগে শুরু করা হয়েছিল।

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

সুতরাং আমরা ইন্টারফেস প্রারম্ভিককরণগুলিতে এই জাতীয় পার্শ্ব প্রতিক্রিয়াগুলি আরও ভালভাবে প্রতিষ্ঠিত করব না establish সর্বোপরি, interfaceএই বৈশিষ্ট্যগুলির জন্য নয় (স্ট্যাটিক ক্ষেত্রগুলি / পদ্ধতিগুলি) আমরা সুবিধার জন্য পাইল করি।

অতএব আমরা যদি সেই নীতিটি অনুসরণ করি তবে এটি আমাদের পক্ষে কোন উদ্বেগের বিষয় হবে না যাতে ক্রমের ইন্টারফেসগুলি আরম্ভ করা হয়।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.