constructor كلاس - كيف يمكنني استدعاء مُنشئ واحد من آخر في Java؟




جافا شرح (14)

هل من الممكن استدعاء مُنشئ من آخر (ضمن نفس الفئة ، وليس من فئة فرعية)؟ إذا نعم كيف؟ وماذا يمكن أن يكون أفضل طريقة لاستدعاء منشئ آخر (إذا كان هناك العديد من الطرق للقيام بذلك)؟


Answers

عندما أحتاج إلى استدعاء مُنشئ آخر من داخل التعليمة البرمجية (وليس في السطر الأول) ، عادةً ما استخدم طريقة مساعد مثل هذه:

class MyClass {
   int field;


   MyClass() {
      init(0);
   } 
   MyClass(int value) {
      if (value<0) {
          init(0);
      } 
      else { 
          init(value);
      }
   }
   void init(int x) {
      field = x;
   }
}

ولكن في معظم الأحيان أحاول القيام بذلك في الاتجاه الآخر عن طريق استدعاء الصانعين الأكثر تعقيدًا من الأبسطين في السطور الأولى ، إلى أقصى حد ممكن. على سبيل المثال أعلاه

class MyClass {
   int field;

   MyClass(int value) {
      if (value<0)
         field = 0;
      else
         field = value;
   }
   MyClass() {
      this(0);
   }
}

داخل مُنشئ ، يمكنك استخدام this الكلمة الأساسية لاستدعاء منشئ آخر في نفس الفئة. يسمى القيام بذلك استدعاء صريح منشئ .

فيما يلي فئة مستطيل أخرى ، مع تطبيق مختلف عن ذلك الموجود في قسم الكائنات.

public class Rectangle {
    private int x, y;
    private int width, height;

    public Rectangle() {
        this(1, 1);
    }
    public Rectangle(int width, int height) {
        this( 0,0,width, height);
    }
    public Rectangle(int x, int y, int width, int height) {
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
    }

}

يحتوي هذا الفصل على مجموعة من المنشئ. يقوم كل مُنشئ بتهيئة بعض أو كل المتغيرات الخاصة بالمستخدم المستطيل.


بسيط جدا

public class SomeClass{

    int number;
    String someString;

    public SomeClass(){
        number = 0;
    }

    public SomeClass(int number){
        this(); //set the class to 0
        this.setNumber(number); 
    }

    public SomeClass(int number, String someString){
        this(number); //call public SomeClass( int number )
    }

    public void setNumber(int number){
        this.number = number;
    }
    public void setString(String someString){
        this.someString = someString;
    }
    //.... add some accessors
}

الآن هنا بعض الائتمان الإضافي الصغير:

public SomeOtherClass extends SomeClass {
    public SomeOtherClass(int number, String someString){
         super(number, someString); //calls public SomeClass(int number, String someString)
    }
    //.... Some other code.
}

أتمنى أن يساعدك هذا.


نعم ، من الممكن الاتصال بمنشئ من آخر باستخدام this()

class Example{
   private int a = 1;
   Example(){
        this(5); //here another constructor called based on constructor argument
        System.out.println("number a is "+a);   
   }
   Example(int b){
        System.out.println("number b is "+b);
   }

يمكنك إنشاء منشئ آخر من نفس الفئة باستخدام الكلمة الأساسية "هذه". مثال -

class This1
{
    This1()
    {
        this("Hello");
        System.out.println("Default constructor..");
    }
    This1(int a)
    {
        this();
        System.out.println("int as arg constructor.."); 
    }
    This1(String s)
    {
        System.out.println("string as arg constructor..");  
    }

    public static void main(String args[])
    {
        new This1(100);
    }
}

الإخراج - سلسلة كما هو مُنشئ arg .. المُنشئ الافتراضي .. int كـ arg مُنشئ.


أعرف أن هناك الكثير من الأمثلة على هذا السؤال ولكن ما وجدته أضعه هنا لمشاركة الفكرة. هناك طريقتان لسلسلة منشئ. في نفس الفصل ، يمكنك استخدام هذه الكلمة. في الوراثة ، تحتاج إلى استخدام الكلمة الرئيسية الفائقة.

    import java.util.*;
    import java.lang.*;

    class Test
    {  
        public static void main(String args[])
        {
            Dog d = new Dog(); // Both Calling Same Constructor of Parent Class i.e. 0 args Constructor.
            Dog cs = new Dog("Bite"); // Both Calling Same Constructor of Parent Class i.e. 0 args Constructor.

            // You need to Explicitly tell the java compiler to use Argument constructor so you need to use "super" key word
            System.out.println("------------------------------");
            Cat c = new Cat();
            Cat caty = new Cat("10");

            System.out.println("------------------------------");
            // Self s = new Self();
            Self ss = new Self("self");
        }
    }

    class Animal
    {
        String i;

        public Animal()
        {
            i = "10";
            System.out.println("Animal Constructor :" +i);
        }
        public Animal(String h)
        {
            i = "20";
            System.out.println("Animal Constructor Habit :"+ i);
        }
    }

    class Dog extends Animal
    {
        public Dog()
        {
            System.out.println("Dog Constructor");
        }
        public Dog(String h)
        {
            System.out.println("Dog Constructor with habit");
        }
    }

    class Cat extends Animal
    {
        public Cat()
        {
            System.out.println("Cat Constructor");
        }
        public Cat(String i)
        {
            super(i); // Calling Super Class Paremetrize Constructor.
            System.out.println("Cat Constructor with habit");
        }
    }

    class Self
    {
        public Self()
        {
            System.out.println("Self Constructor");
        }
        public Self(String h)
        {
            this(); // Explicitly calling 0 args constructor. 
            System.out.println("Slef Constructor with value");
        }
    }

سأخبرك بطريقة سهلة

هناك نوعان من المنشئات:

  1. منشئ افتراضي
  2. منشئ معتبر

سأشرح في مثال واحد

class ConstructorDemo 
{
      ConstructorDemo()//Default Constructor
      {
         System.out.println("D.constructor ");
      }

      ConstructorDemo(int k)//Parameterized constructor
      {
         this();//-------------(1)
         System.out.println("P.Constructor ="+k);       
      }

      public static void main(String[] args) 
      {
         //this(); error because "must be first statement in constructor
         new ConstructorDemo();//-------(2)
         ConstructorDemo g=new ConstructorDemo(3);---(3)    
       }
   }                  

في المثال أعلاه عرضت 3 أنواع من الاتصال

  1. يجب أن يكون هذا استدعاء () إلى هذا أولاً العبارة في منشئ
  2. هذا هو اسم أقل كائن. هذا تلقائياً باستدعاء منشئ افتراضي. 3. هذا يستدعي المُنَظِر المُعْلَمي.

ملاحظة: يجب أن يكون هذا أول عبارة في المُنشئ.


كما قال الجميع بالفعل ، يمكنك استخدام this(…) ، والذي يسمى استدعاء صريح منشئ .

ومع ذلك ، ضع في اعتبارك أنه ضمن بيان الاستدعاء صريح منشئ قد لا تشير إلى

  • أي متغيرات الحالة أو
  • أي طرق سبيل المثال أو
  • أي فصول داخلية معلن عنها في هذه الفئة أو أي طبقة متميزة ، أو
  • this أو
  • super .

كما ورد في JLS (§8.8.7.1).


نعم ، يمكن أن يكون أي عدد من المنشئين موجودًا في فصل ويمكن أن يتم استدعاؤه بواسطة مُنشئ آخر باستخدام this() [الرجاء عدم الخلط بين this() الاتصال بالمنشئ باستخدام this الكلمة الأساسية]. يجب أن يكون this() أو this(args) السطر الأول في المُنشئ.

مثال:

Class Test {
    Test() {
        this(10); // calls the constructor with integer args, Test(int a)
    }
    Test(int a) {
        this(10.5); // call the constructor with double arg, Test(double a)
    }
    Test(double a) {
        System.out.println("I am a double arg constructor");
    }
}

هذا هو المعروف باسم الحمولة الزائدة منشئ.
يرجى ملاحظة أنه بالنسبة للمُنشئ ، لا ينطبق سوى مفهوم الحمولة الزائدة وليس الميراث أو تجاوزه.


استدعاء مُنشئ من مُنشئ آخر

class MyConstructorDemo extends ConstructorDemo
{
    MyConstructorDemo()
    {
        this("calling another constructor");
    }
    MyConstructorDemo(String arg)
    {
        System.out.print("This is passed String by another constructor :"+arg);
    }
}

كما يمكنك استدعاء منشئ الأهل باستخدام استدعاء super()


هناك أنماط تصميم تغطي الحاجة إلى البناء المعقد - إذا لم يكن بالإمكان القيام به بإيجاز ، أو إنشاء طريقة مصنع أو فصل مصنع.

مع أحدث java وإضافة lambdas ، من السهل إنشاء مُنشئ يمكنه قبول أي رمز تهيئة تريده.

class LambdaInitedClass {

   public LamdaInitedClass(Consumer<LambdaInitedClass> init) {
       init.accept(this);
   }
}

اتصل بها ...

 new LambdaInitedClass(l -> { // init l any way you want });

باستخدام this(args) . النمط المفضل هو العمل من أصغر مُنشئ إلى الأكبر.

public class Cons {

 public Cons() {
  // A no arguments constructor that sends default values to the largest
  this(madeUpArg1Value,madeUpArg2Value,madeUpArg3Value);
 }

 public Cons(int arg1, int arg2) {
  // An example of a partial constructor that uses the passed in arguments
  // and sends a hidden default value to the largest
  this(arg1,arg2, madeUpArg3Value);
 }

 // Largest constructor that does the work
 public Cons(int arg1, int arg2, int arg3) {
  this.arg1 = arg1;
  this.arg2 = arg2;
  this.arg3 = arg3;
 }
}

يمكنك أيضًا استخدام طريقة مؤيدة حديثًا للقيمة أو فقط "من":

public class Cons {
 public static Cons newCons(int arg1,...) {
  // This function is commonly called valueOf, like Integer.valueOf(..)
  // More recently called "of", like EnumSet.of(..)
  Cons c = new Cons(...);
  c.setArg1(....);
  return c;
 }
} 

للاتصال بفئة ممتازة ، استخدم super(asdf) . يجب أن تكون المكالمة إلى السوبر هي المكالمة الأولى في المُنشئ أو ستحصل على خطأ في التحويل البرمجي.


نعم من الممكن استدعاء منشئ من آخر. لكن هناك قاعدة لذلك. إذا تم إجراء مكالمة من مُنشئ إلى آخر ، فعندئذٍ

يجب أن يكون استدعاء منشئ جديد عبارة الأول في المنشئ الحالي

public class Product {
     private int productId;
     private String productName;
     private double productPrice;
     private String category;

    public Product(int id, String name) {
        this(id,name,1.0);
    }

    public Product(int id, String name, double price) {
        this(id,name,price,"DEFAULT");
    }

    public Product(int id,String name,double price, String category){
        this.productId=id;
        this.productName=name;
        this.productPrice=price;
        this.category=category;
    }
}

شيء من هذا القبيل أدناه لن ينجح.

public Product(int id, String name, double price) {
    System.out.println("Calling constructor with price");
    this(id,name,price,"DEFAULT");
}

في الأساس ، لا يؤثر إعادة تعيين معلمات الكائن على الحجة ، على سبيل المثال ،

private void foo(Object bar) {
    bar = null;
}

public static void main(String[] args) {
    String baz = "Hah!";
    foo(baz);
    System.out.println(baz);
}

ستطبع "Hah!"بدلا من null. السبب في أن هذا العمل هو barنسخة من قيمة baz، وهي مجرد إشارة إلى "Hah!". إذا كانت الإشارة الفعلية نفسها، ثم fooقد أعاد bazل null.





java constructor