`SomeObject.new` জাভাতে কি করে?


100

জাভাতে, আমি সন্ধান করেছি যে নিম্নলিখিত কোডটি আইনী:

KnockKnockServer newServer = new KnockKnockServer();                    
KnockKnockServer.receiver receive = newServer.new receiver(clientSocket);

এফওয়াইআই, রিসিভার হ'ল নিম্নলিখিত স্বাক্ষর সহ একটি সহায়ক শ্রেণি:

public class receiver extends Thread {  /* code_inside */  }

আমি XYZ.newস্বরলিপিটি এর আগে কখনও দেখিনি । ওটা কিভাবে কাজ করে? প্রচলিতভাবে কোড করার কোনও উপায় আছে কি?


7
আপনার রেফারেন্সের জন্য, অভ্যন্তর শ্রেণি
অ্যালভিন ওয়াং

1
এছাড়াও, আমি বিশ্বাস করেছি যে newপ্রচুর ভাষায় অপারেটর। (আমি ভেবেছিলাম আপনি newসি ++ এও ওভারলোড করতে পারেন ?) জাভাটির অভ্যন্তরীণ ক্লাসটি আমার জন্য কিছুটা অদ্ভুত।
অ্যালভিন ওয়াং

5
স্ট্যাকওভারফ্লোতে কোনও নির্বোধ প্রশ্ন নেই!
আইজাক রবিনোভিচ

2
@ আইসাকআরবিনোভিচ - কোনও বোকা প্রশ্ন নেই। তবে অনেকগুলি নির্বোধ রয়েছে। (এবং পাশাপাশি মাঝে মধ্যে নির্বোধ উত্তর।)
হট লিকস

2
@ হটলিক্স এবং একটি নির্বোধ প্রশ্নের আপনার সংজ্ঞা কি? আপনি যে জিজ্ঞাসা করা খুব স্মার্ট, আমি মনে করি। ভালো যে আপনার এতটা আত্মমর্যাদাবোধ রয়েছে।
আইজাক রবিনোভিচ

উত্তর:


120

ওরাকল ডক্সে বর্ণিত ধরণের দেহের বাইরে থেকে কোনও অ স্থিতিশীল অভ্যন্তর শ্রেণিকে ইনস্ট্যান্ট করার উপায় এটি ।

প্রতিটি অভ্যন্তর শ্রেণীর উদাহরণটি এর সমন্বিত শ্রেণীর উদাহরণের সাথে যুক্ত। যখন আপনি তার অন্তর্ভুক্ত newশ্রেণীর মধ্যে থেকে কোনও অভ্যন্তর শ্রেণি thisডিফল্টরূপে ধারকটির উদাহরণটি ব্যবহার করে :

public class Foo {
  int val;
  public Foo(int v) { val = v; }

  class Bar {
    public void printVal() {
      // this is the val belonging to our containing instance
      System.out.println(val);
    }
  }

  public Bar createBar() {
    return new Bar(); // equivalent of this.new Bar()
  }
}

তবে আপনি যদি ফু এর বাইরে বারের কোনও উদাহরণ তৈরি করতে চান বা একটি নতুন দৃষ্টান্তের সাথে একটি নতুন উদাহরণ সংযুক্ত করতে চান thisতবে আপনাকে উপসর্গ চিহ্নটি ব্যবহার করতে হবে।

Foo f = new Foo(5);
Foo.Bar b = f.new Bar();
b.printVal(); // prints 5

18
এবং, আপনি বলতে পারেন যে এটি অবিশ্বাস্যরকম বিভ্রান্তিকর হতে পারে। আদর্শভাবে, অভ্যন্তরীণ ক্লাসগুলি বাইরের শ্রেণীর প্রয়োগের বিবরণ হওয়া উচিত এবং বাইরের বিশ্বের কাছে প্রকাশ করা উচিত নয়।
এরিক জাবলো 23

10
@ এরিকজাব্লো প্রকৃতপক্ষে, এটি সিনট্যাক্সের সেই বিটগুলির মধ্যে একটি যা অনুপস্থিতিকে সামঞ্জস্য রাখতে অব্যাহত থাকতে পারে তবে আপনি আসলে এটি ব্যবহারের প্রয়োজন নেই এমন 99,9999% সময় রয়েছে। যদি বাইরের লোকদের সত্যই বার দৃষ্টান্ত তৈরি করতে হয় তবে আমি ফুগুলিতে তাদের ব্যবহারের চেয়ে কারখানার পদ্ধতি সরবরাহ করব f.new
ইয়ান রবার্টস

আমি ভুল হলে আমাকে সংশোধন করুন তবে যদি publicঅ্যাক্সেসের স্তরটি KnockKnockServer.receiverতৈরি করা হত privateতবে এইভাবে ইনস্ট্যান্ট করা অসম্ভব, তাই না? @ এরিকজাব্লো'র মন্তব্য বাড়ানোর জন্য, অভ্যন্তরীণ ক্লাসগুলি সাধারণত privateঅ্যাক্সেস স্তরে সর্বদা ডিফল্ট থাকে ।
অ্যান্ড্রু বিসেল 0

1
@ অ্যান্ড্রুবিসেল হ্যাঁ, তবে receiverবাইরে থেকে ক্লাসটি উল্লেখ করাও অসম্ভব । যদি আমি এটি ডিজাইন করতাম তবে আমি সম্ভবত বর্গ জনসাধারণের কাছে থাকতাম তবে এর নির্মাতা সুরক্ষিত বা প্যাকেজ-প্রাইভেট থাকতেন এবং KnockKnockServerরিসিভারের উদাহরণগুলি তৈরি করার পদ্ধতি ছিল ।
ইয়ান রবার্টস

1
@ এমরি আমি এটি বলছি না, আমি জানি যে কোনও অভ্যন্তরীণ শ্রেণিকে জনসাধারণের মধ্যে গড়ে তোলার উপযুক্ত বৈধ কারণ থাকতে পারে এবং বাইরের পদ্ধতি থেকে অভ্যন্তরীণ শ্রেণীর উদাহরণগুলি ফিরে আসতে পারে তবে আমি আমার কোডটি এমনভাবে ডিজাইন করতে চাই " বহিরাগতদের "সরাসরি ব্যবহার করে অভ্যন্তরীণ শ্রেণীর উদাহরণ তৈরি করার দরকার নেই x.new
ইয়ান রবার্টস

18

এই উদাহরণটি দেখুন:

public class Test {

    class TestInner{

    }

    public TestInner method(){
        return new TestInner();
    }

    public static void main(String[] args) throws Exception{
        Test t = new Test();
        Test.TestInner ti = t.new TestInner();
    }
}

জাভাপ ব্যবহার করে আমরা এই কোডটির জন্য উত্পন্ন নির্দেশাবলী দেখতে পারি

প্রধান পদ্ধতি:

public static void main(java.lang.String[])   throws java.lang.Exception;
  Code:
   0:   new     #2; //class Test
   3:   dup
   4:   invokespecial   #3; //Method "<init>":()V
   7:   astore_1
   8:   new     #4; //class Test$TestInner
   11:  dup
   12:  aload_1
   13:  dup
   14:  invokevirtual   #5; //Method java/lang/Object.getClass:()Ljava/lang/Class;
   17:  pop
   18:  invokespecial   #6; //Method Test$TestInner."<init>":(LTest;)V
   21:  astore_2
   22:  return
}

ইনার ক্লাস কনস্ট্রাক্টর:

Test$TestInner(Test);
  Code:
   0:   aload_0
   1:   aload_1
   2:   putfield        #1; //Field this$0:LTest;
   5:   aload_0
   6:   invokespecial   #2; //Method java/lang/Object."<init>":()V
   9:   return

}

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

t.new TestInner(); - কেবলমাত্র টেস্টইনার কনস্ট্রাক্টরের কাছে প্রথম লুকানো যুক্তি নির্দিষ্ট করার উপায়, কোনও প্রকার নয়

পদ্ধতি () সমান:

public TestInner method(){
    return this.new TestInner();
}

টেস্টইনারের সমান:

class TestInner{
    private Test this$0;

    TestInner(Test parent){
        this.this$0 = parent;
    }
}

7

জাভাতে যখন ভাষার 1.1 সংস্করণে অভ্যন্তরীণ ক্লাসগুলি যুক্ত করা হয়েছিল তখন সেগুলি মূলত 1.0 এর সামঞ্জস্যপূর্ণ কোডে রূপান্তর হিসাবে সংজ্ঞায়িত হয়েছিল। আপনি যদি এই রূপান্তরটির উদাহরণের দিকে লক্ষ্য করেন তবে আমি মনে করি এটি একটি অভ্যন্তর শ্রেণি আসলে কীভাবে কাজ করে তা এটি আরও পরিষ্কার করে দেবে।

আয়ান রবার্টসের উত্তরের কোডটি বিবেচনা করুন:

public class Foo {
  int val;
  public Foo(int v) { val = v; }

  class Bar {
    public void printVal() {
      System.out.println(val);
    }
  }

  public Bar createBar() {
    return new Bar();
  }
}

১.০ সামঞ্জস্যপূর্ণ কোডে রূপান্তরিত হলে, সেই অভ্যন্তর শ্রেণিটি Barএমন কিছুতে পরিণত হবে:

class Foo$Bar {
  private Foo this$0;

  Foo$Bar(Foo outerThis) {
    this.this$0 = outerThis;
  }

  public void printVal() {
    System.out.println(this$0.val);
  }
}

অভ্যন্তরীণ শ্রেণীর নামটি বহিরাগত শ্রেণীর নামের সাথে পূর্ববর্তী করা যাতে এটি অনন্য করা যায়। একটি লুকানো ব্যক্তিগত this$0সদস্য যুক্ত করা হয়েছে যা বাইরের একটি অনুলিপি রাখে this। এবং সেই সদস্যকে আরম্ভ করার জন্য একটি লুকানো কনস্ট্রাক্টর তৈরি করা হয়।

এবং যদি আপনি createBarপদ্ধতিটি দেখেন তবে এটি এমন কিছুতে রূপান্তরিত হবে:

public Foo$Bar createBar() {
  return new Foo$Bar(this);
}

সুতরাং আসুন দেখুন যখন আপনি নিম্নলিখিত কোডটি কার্যকর করেন তখন কি হয়।

Foo f = new Foo(5);
Foo.Bar b = f.createBar();                               
b.printVal();

প্রথমে আমরা একটি উদাহরণ ইনস্ট্যান্ট করি Fooএবং সদস্যটিকে val5 (অর্থাৎ f.val = 5) তে অন্তর্নিহিত করি ।

এরপরে আমরা কল করব f.createBar(), যা একটি দৃষ্টান্ত ইনস্ট্যান্ট করে Foo$Barএবং সদস্যটিকে (যেমন ) থেকে উত্তীর্ণের this$0মান থেকে আরম্ভ করে ।thiscreateBarb.this$0 = f

অবশেষে আমরা কল b.printVal()যা প্রিন্ট করার চেষ্টা করে b.this$0.valযা f.valযা 5।

এখন এটি একটি অভ্যন্তর শ্রেণীর নিয়মিত ইনস্ট্যান্টেশন ছিল। সেখানে কি ঘটছে যখন শুরু করতে গিয়ে এ আসুন বর্ণন Barবাইরে থেকে Foo

Foo f = new Foo(5);
Foo.Bar b = f.new Bar();
b.printVal();

আমাদের ১.০ রূপান্তরটি আবার প্রয়োগ করা, সেই দ্বিতীয় লাইনটি এরকম কিছু হয়ে উঠবে:

Foo$Bar b = new Foo$Bar(f);

এটি f.createBar()কলটির সাথে প্রায় অভিন্ন । আবার আমরা একটি দৃষ্টান্ত ইনস্ট্যান্ট করছি Foo$Barএবং this$0সদস্যকে চ-তে শুরু করি। আবার b.this$0 = f,।

এবং আবার যখন আপনি কল করবেন b.printVal(), আপনি মুদ্রণ করছেন b.thi$0.valযা f.val5 হয়।

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


4

new receiverএকক টোকেন হিসাবে চিন্তা করুন । কোনও স্থানের মতো কোনও ফাংশনের নামের মতো এটি।

অবশ্যই, ক্লাসে KnockKnockServerআক্ষরিক অর্থে কোনও ফাংশন নেই new receiver, তবে আমি অনুমান করছি সিনট্যাক্সটি বোঝাতে চাইছে এটি suggest এটি দেখে মনে হচ্ছে বোঝানো হচ্ছে আপনি কোনও ফাংশনকে কল করছেন যা ঘেরের ক্লাসে কোনও অ্যাক্সেসের জন্য KnockKnockServer.receiverএকটি নির্দিষ্ট উদাহরণ ব্যবহার করে একটি নতুন উদাহরণ তৈরি করে KnockKnockServer


ধন্যবাদ, হ্যাঁ - এটি এখন আমাকে new receiverটোকেন হিসাবে ভাবতে সহায়তা করে ! অনেক ধন্যবাদ!
কফি

1

ছায়াকরণ

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

public class ShadowTest {

    public int x = 0;

    class FirstLevel {

        public int x = 1;

        void methodInFirstLevel(int x) {
            System.out.println("x = " + x);
            System.out.println("this.x = " + this.x);
            System.out.println("ShadowTest.this.x = " + ShadowTest.this.x);
        }
    }

    public static void main(String... args) {
        ShadowTest st = new ShadowTest();
        ShadowTest.FirstLevel fl = st.new FirstLevel();
        fl.methodInFirstLevel(23);
    }
}

নিম্নলিখিতটি এই উদাহরণটির ফলাফল:

x = 23
this.x = 1
ShadowTest.this.x = 0

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

System.out.println("this.x = " + this.x);

সদস্য ভেরিয়েবলগুলি দেখুন যা তারা শ্রেণীর নামের সাথে বৃহত স্কোপগুলি আবদ্ধ করে। উদাহরণস্বরূপ, নীচের বিবৃতিটি মেথড মেথডআইন ফার্স্টলাইভেল থেকে শ্যাডো টেস্টের ক্লাসের সদস্য ভেরিয়েবল অ্যাক্সেস করে:

System.out.println("ShadowTest.this.x = " + ShadowTest.this.x);

দস্তাবেজগুলি পড়ুন

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