CodeGym /وبلاگ جاوا /Random-FA /توالی اعمال در حین ایجاد شی
John Squirrels
مرحله
San Francisco

توالی اعمال در حین ایجاد شی

در گروه منتشر شد
سلام! درس امروز کاملاً... اوه... چند وجهی خواهد بود :) به این معنا که ما طیف گسترده ای از موضوعات را پوشش خواهیم داد، اما همه آنها به فرآیند ایجاد شی مربوط می شوند . توالی اقدامات در حین ایجاد شی - 1ما آن را از ابتدا تا انتها تجزیه و تحلیل می‌کنیم: سازنده‌ها چگونه فراخوانی می‌شوند، چگونه و به چه ترتیبی فیلدها (از جمله فیلدهای استاتیک) مقداردهی اولیه می‌شوند و غیره. ما قبلاً برخی از نکات مورد بحث در مقاله را لمس کرده‌ایم، بنابراین می‌توانید به آن نگاه کنید. مواد بر روی سازنده های کلاس پایه ابتدا بیایید به یاد بیاوریم که یک شی چگونه ایجاد می شود. شما به خوبی به یاد دارید که این فرآیند از دیدگاه یک توسعه دهنده چگونه به نظر می رسد: او یک کلاس ایجاد می کند، می نویسد newو همه چیز آماده است :) در اینجا ما در مورد آنچه که در داخل کامپیوتر و ماشین جاوا هنگام نوشتن اتفاق می افتد صحبت خواهیم کرد، به عنوان مثال:

Cat cat = new Cat();
قبلاً در این مورد صحبت کرده‌ایم، اما اگر به شما یادآوری کنیم:
  • ابتدا حافظه برای ذخیره شی اختصاص داده می شود.
  • سپس، ماشین جاوا یک مرجع به شی ایجاد می کند (در مورد ما مرجع Cat cat است).
  • در نهایت، متغیرها مقداردهی اولیه می شوند و سازنده فراخوانی می شود (ما این فرآیند را با جزئیات بیشتری بررسی می کنیم).
علاوه بر این، از درس چرخه زندگی شیء ، احتمالاً به یاد دارید که یک شی تا زمانی که حداقل یک مرجع به آن وجود داشته باشد، دوام می آورد. اگر چیزی باقی نماند، آن شیء طعمه زباله گرد می شود. توالی اعمال در حین ایجاد شی - 2این دو نکته اول نباید سؤال خاصی ایجاد کند. تخصیص حافظه یک فرآیند ساده است و تنها دو نتیجه ممکن وجود دارد: یا حافظه وجود دارد یا وجود ندارد :) و ایجاد یک پیوند غیرعادی نیست. اما نکته سوم مجموعه کاملی از عملیات را نشان می دهد که به ترتیب دقیق اجرا شده اند. من طرفدار انباشته کردن تست ها نیستم، اما شما باید این فرآیند را به خوبی درک کنید و باید این توالی از عملیات را به خاطر بسپارید . وقتی در درس های قبلی در مورد فرآیند ایجاد شی صحبت کردیم، شما واقعاً هنوز چیزی در مورد وراثت نمی دانستید، بنابراین توضیح برخی چیزها مشکل ساز بود. حالا شما خیلی چیزها را می دانید و در نهایت می توانیم این سوال را به طور کامل در نظر بگیریم :) بنابراین نکته سوم می گوید "در نهایت متغیرها مقداردهی اولیه می شوند و سازنده فراخوانی می شود. " اما همه اینها به چه ترتیبی اتفاق می افتد؟ برای درک بهتر، بیایید دو کلاس فوق العاده ساده ایجاد کنیم - یک والدین و یک فرزند:

public class Vehicle { 

   public static int vehicleCounter = 0; 

   private String description = "Vehicle"; 
   public Vehicle() { 
   } 

   public String getDescription() { 
       return description; 
   } 
} 

public class Truck extends Vehicle { 

   private static int truckCounter = 0; 

   private int yearOfManufacture; 
   private String model; 
   private int maxSpeed; 

   public Truck(int yearOfManufacture, String model, int maxSpeed) { 
       this.yearOfManufacture = yearOfManufacture; 
       this.model = model; 
       this.maxSpeed = maxSpeed; 

       Vehicle.vehicleCounter++; 
       truckCounter++; 
   } 
}
کلاس Truckپیاده سازی یک کامیون با فیلدهایی است که سال، مدل و حداکثر سرعت آن را نشان می دهد. اکنون می خواهیم یکی از این شی را ایجاد کنیم:

public class Main { 

   public static void main(String[] args) throws IOException { 

       Truck truck = new Truck(2017, "Scania S 500 4x2", 220); 
   } 
}
برای ماشین جاوا، فرآیند به صورت زیر خواهد بود:
  1. اولین چیزی که اتفاق می افتد این است که متغیرهای استاتیک کلاس Vehicleمقداردهی اولیه می شوند . بله گفتم Vehicleکلاس نه Truck. متغیرهای استاتیک قبل از فراخوانی سازنده ها مقداردهی اولیه می شوند و این کار در کلاس والد شروع می شود. بیایید سعی کنیم این را تأیید کنیم. vehicleCounterفیلد Vehicleکلاس را برابر با 10 قرار می دهیم و سعی می کنیم آن را در هر دو سازنده Vehicleو نمایش دهیم Truck.

    
    public class Vehicle { 
    
       public static int vehicleCounter = 10; 
       private String description = "Vehicle"; 
    
       public Vehicle() { 
           System.out.println(vehicleCounter); 
       } 
    
       public String getDescription() { 
           return description; 
       } 
    } 
    
    public class Truck extends Vehicle { 
    
       private static int truckCount = 0;
    
       private int yearOfManufacture; 
       private String model; 
       private int maxSpeed; 
    
       public Truck(int yearOfManufacture, String model, int maxSpeed) { 
           System.out.println(vehicleCounter); 
           this.yearOfManufacture = yearOfManufacture; 
           this.model = model; 
           this.maxSpeed = maxSpeed; 
    
           Vehicle.vehicleCounter++; 
           truckCount++; 
       } 
    }

    ما عمداً عبارت println را در همان ابتدای سازنده قرار دادیم Truckتا مطمئن شویم که فیلدهای کامیون هنگام vehicleCounterنمایش هنوز مقدار دهی اولیه نشده اند.

    و این هم نتیجه:

    
    10 
    10
  2. بعد از اینکه متغیرهای استاتیک کلاس والد مقداردهی اولیه شد، متغیرهای استاتیک کلاس فرزند مقداردهی اولیه می شوند. در مورد ما، این truckCounterزمینه کلاس است Truck.

    بیایید آزمایش دیگری انجام دهیم که در آن سعی می کنیم قبل از مقداردهی اولیه فیلدهای دیگر، مقدار truckCounterداخل سازنده را نمایش دهیم:Truck

    
    public class Truck extends Vehicle { 
    
       private static int truckCounter = 10; 
    
       private int yearOfManufacture; 
       private String model; 
       private int maxSpeed; 
    
       public Truck(int yearOfManufacture, String model, int maxSpeed) { 
           System.out.println(truckCounter); 
           this.yearOfManufacture = yearOfManufacture; 
           this.model = model; 
           this.maxSpeed = maxSpeed; 
    
           Vehicle.vehicleCounter++; 
           truckCounter++; 
       } 
    }

    همانطور که می بینید، مقدار 10 قبلاً با شروع سازنده به متغیر استاتیک ما اختصاص داده شده استTruck .

  3. هنوز وقت سازندگان نرسیده است! مقداردهی اولیه متغیر ادامه دارد. متغیرهای غیراستاتیک کلاس والد در مرحله سوم مقداردهی اولیه می شوند. همانطور که می بینید، وراثت به طور قابل توجهی فرآیند ایجاد یک شی را پیچیده می کند، اما هیچ کاری نمی توانید در مورد آن انجام دهید: فقط باید برخی چیزها را در برنامه نویسی به خاطر بسپارید :)

    به عنوان یک آزمایش، می‌توانیم مقداری اولیه را به descriptionمتغیر Vehicleکلاس اختصاص دهیم و سپس آن را در سازنده تغییر دهیم.

    
    public class Vehicle { 
    
       public static int vehicleCounter = 10; 
    
       private String description = "Initial value of the description field"; 
    
       public Vehicle() { 
           System.out.println(description); 
           description = "Vehicle"; 
           System.out.println(description); 
       } 
    
       public String getDescription() { 
           return description; 
       } 
    }

    بیایید main()روش خود را برای ایجاد یک کامیون اجرا کنیم:

    
    public class Main { 
    
       public static void main(String[] args) throws IOException { 
    
           Truck truck = new Truck(2017, "Scania S 500 4x2", 220); 
       } 
    }

    نتیجه زیر را می گیریم:

    
    Initial value of the description field 
    Vehicle

    این ثابت می کند که وقتی Vehicleسازنده شروع می شود به descriptionفیلد قبلاً یک مقدار اختصاص داده شده است.

  4. بالاخره نوبت سازندگان می رسد! به طور دقیق تر، زمان سازنده کلاس پایه فرا رسیده است. در مرحله چهارم فرآیند ایجاد شیء فراخوانی می شود.

    تأیید این موضوع نیز نسبتاً آسان است. بیایید خروجی دو خط را به کنسول امتحان کنیم: یکی در Vehicleسازنده کلاس پایه و دومی در Truckسازنده. Vehicleما باید متقاعد شویم که ابتدا خط داخل نمایش داده می شود:

    
    public Vehicle() { 
    
       System.out.println("Hello from the Vehicle constructor!"); 
    } 
    
    public Truck(int yearOfManufacture, String model, int maxSpeed) { 
    
       System.out.println("Hello from the Truck constructor!"); 
       this.yearOfManufacture = yearOfManufacture; 
       this.model = model; 
       this.maxSpeed = maxSpeed; 
    
       Vehicle.vehicleCounter++; 
       truckCounter++; 
    }

    ما main()روش خود را اجرا می کنیم و به نتیجه نگاه می کنیم:

    
    Hello from the Vehicle constructor! 
    Hello from the Truck constructor!

    عالی یعنی ما اشتباه نمیکنیم :) بریم جلو.

  5. حالا نوبت مقداردهی اولیه فیلدهای غیراستاتیک کلاس فرزند یعنی Truckکلاس ماست. فیلدهای بلافاصله داخل کلاس در حال نمونه سازی تا مرحله پنجم مقداردهی اولیه نمی شوند! شگفت‌آور است، اما درست است :) باز هم، ما یک بررسی ساده انجام می‌دهیم - درست مانند کلاس والد: مقداری اولیه برای متغیر تعیین می‌کنیم maxSpeedو در Truckسازنده بررسی می‌کنیم که مقدار قبل از شروع سازنده اختصاص داده شده باشد:

    
    public class Truck extends Vehicle { 
    
       private static int truckCounter = 10; 
    
       private int yearOfManufacture; 
       private String model; 
       private int maxSpeed = 150; 
    
       public Truck(int yearOfManufacture, String model, int maxSpeed) { 
    
           System.out.println("Initial value of maxSpeed = " + this.maxSpeed); 
           this.yearOfManufacture = yearOfManufacture; 
           this.model = model; 
           this.maxSpeed = maxSpeed; 
    
           Vehicle.vehicleCounter++; 
           truckCounter++; 
       } 
    }

    خروجی کنسول:

    
    Initial value of maxSpeed = 150

    همانطور که می بینید،  زمانی که Truck سازنده شروع می شود، maxSpeed در حال حاضر برابر با 150 است!

  6. سازنده Truckکلاس فرزند فراخوانی می شود.

    و تنها در این مرحله، آخر از همه، سازنده کلاسی که ما نمونه سازی می کنیم فراخوانی می شود!

    فقط در مرحله ششم مقادیری که به عنوان آرگومان به کامیون خود ارسال می کنیم به فیلدها اختصاص داده می شود.

    همانطور که می بینید، "ساخت" یک کامیون، یعنی فرآیند ایجاد شی، ساده نیست. اما به نظر می رسد که ما آن را به کوچکترین قسمت ها تقسیم کرده ایم :)

توالی اعمال در حین ایجاد شی - 3 چرا درک این فرآیند بسیار مهم است؟ تصور کنید که اگر دقیقاً نمی دانستید "زیر کاپوت" چه اتفاقی می افتد، نتایج ایجاد یک شی معمولی چقدر غیرمنتظره می تواند باشد :) حالا زمان بازگشت به دوره و انجام برخی کارها است! موفق باشید و به زودی شما را می بینم! :)
نظرات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION