JavaRush /Java blogi /Random-UZ /Java tilida konstruktorlar

Java tilida konstruktorlar

Guruhda nashr etilgan
Salom! Bugun biz ob'ektlarimizga tegishli bo'lgan juda muhim mavzuni ko'rib chiqamiz. Mana, mubolag'asiz aytishimiz mumkinki, siz ushbu bilimlarni har kuni haqiqiy ishda qo'llaysiz! Biz konstruktorlar haqida gaplashamiz. Siz bu atamani birinchi marta eshitayotgan bo'lishingiz mumkin, lekin aslida siz konstruktorlardan foydalangandirsiz, lekin o'zingiz buni sezmagansiz :) Buni keyinroq ko'ramiz.

Java-da konstruktor nima va u nima uchun kerak?

Keling, ikkita misolni ko'rib chiqaylik.
public class Car {

   String model;
   int maxSpeed;

   public static void main(String[] args) {

       Car bugatti = new Car();
       bugatti.model = "Bugatti Veyron";
       bugatti.maxSpeed = 407;

   }
}
Biz mashinamizni yaratdik va uning modelini va maksimal tezligini o'rnatdik. Biroq, haqiqiy loyihada Avtomobil ob'ekti aniq 2 dan ortiq maydonga ega bo'ladi. Va, masalan, 16 ta maydon!
public class Car {

   String model;//model
   int maxSpeed;//max speed
   int wheels;// disk width
   double engineVolume;//engine capacity
   String color;//color
   int yearOfIssue;//year of issue
   String ownerFirstName;//Owner's name
   String ownerLastName;//owner's last name
   long price;//price
   boolean isNew;//new or not
   int placesInTheSalon;//number of seats in the cabin
   String salonMaterial;// interior material
   boolean insurance;//is it insured
   String manufacturerCountry;//manufacturer country
   int trunkVolume;// trunk volume
   int accelerationTo100km;//acceleration to 100 km/h in seconds


   public static void main(String[] args) {
       Car bugatti = new Car();

       bugatti.color = "blue";
       bugatti.accelerationTo100km = 3;
       bugatti.engineVolume = 6.3;
       bugatti.manufacturerCountry = "Italy";
       bugatti.ownerFirstName = "Amigo";
       bugatti.yearOfIssue = 2016;
       bugatti.insurance = true;
       bugatti.price = 2000000;
       bugatti.isNew = false;
       bugatti.placesInTheSalon = 2;
       bugatti.maxSpeed = 407;
       bugatti.model = "Bugatti Veyron";

   }

}
Biz yangi Avtomobil ob'ektini yaratdik . Bitta muammo: bizda 16 ta maydon bor, lekin biz faqat 12 tasini ishga tushirdik ! Biz unutganlarni topish uchun koddan foydalanib ko'ring! Juda oson emas, to'g'rimi? Bunday vaziyatda dasturchi osongina xatoga yo'l qo'yishi va ba'zi maydonlarni ishga tushirishni o'tkazib yuborishi mumkin. Natijada, dastur harakati noto'g'ri bo'ladi:
public class Car {

   String model;//model
   int maxSpeed;//max speed
   int wheels;// disk width
   double engineVolume;//engine capacity
   String color;//color
   int yearOfIssue;//year of issue
   String ownerFirstName;//Owner's name
   String ownerLastName;//owner's last name
   long price;//price
   boolean isNew;//new or not
   int placesInTheSalon;//number of seats in the cabin
   String salonMaterial;// interior material
   boolean insurance;//is it insured
   String manufacturerCountry;//manufacturer country
   int trunkVolume;// trunk volume
   int accelerationTo100km;//acceleration to 100 km/h in seconds


   public static void main(String[] args) {
       Car bugatti = new Car();

       bugatti.color = "blue";
       bugatti.accelerationTo100km = 3;
       bugatti.engineVolume = 6.3;
       bugatti.manufacturerCountry = "Italy";
       bugatti.ownerFirstName = "Amigo";
       bugatti.yearOfIssue = 2016;
       bugatti.insurance = true;
       bugatti.price = 2000000;
       bugatti.isNew = false;
       bugatti.placesInTheSalon = 2;
       bugatti.maxSpeed = 407;
       bugatti.model = "Bugatti Veyron";

       System.out.println("Model Bugatti Veyron. Engine size - " + bugatti.engineVolume + ", trunk - " + bugatti.trunkVolume + ", salon is made of" + bugatti.salonMaterial +
       ", disc width - " + bugatti.wheels + ". Was acquired in 2018 by Mr. " + bugatti.ownerLastName);

   }

}
Konsol chiqishi:
Bugatti Veyron modeli. Dvigatel hajmi - 6,3, magistral - 0, ichki qismi null, jant kengligi - 0. 2018 yilda janob null tomonidan sotib olingan
Mashina uchun 2 million dollar to'lagan xaridoringiz "janob Null" deb nomlanishni yoqtirmasligi aniq! Ammo jiddiy tarzda, oxir-oqibat, dasturimiz noto'g'ri yaratilgan ob'ekt bilan yakunlandi - rom kengligi 0 bo'lgan avtomobil (ya'ni, umuman jantlar yo'q), yo'qolgan yukxona, noma'lum materialdan yasalgan salon va hatto noma'lum kimgadir tegishli. . Dastur ishlayotganda qanday qilib bunday xatolik yuz berishi mumkinligini faqat tasavvur qilish mumkin! Biz qandaydir tarzda bunday vaziyatlardan qochishimiz kerak. Bizning dasturimiz cheklovga ega bo'lishi kerak: yangi avtomobil ob'ektini yaratishda, masalan, uning modeli va maksimal tezligi har doim ko'rsatilishi kerak. Aks holda, ob'ekt yaratishga ruxsat bermang. Konstruktor funktsiyalari bu vazifani osonlikcha engishadi. Ular biron sababga ko'ra o'z nomlarini oldilar. Konstruktor sinfning har bir yangi ob'ekti mos kelishi kerak bo'lgan sinfning o'ziga xos "skeleti" ni yaratadi. Qulaylik uchun, keling, ikkita maydonli Car sinfining oddiyroq versiyasiga qaytaylik . Bizning talablarimizni hisobga olgan holda, Car sinfi uchun konstruktor quyidagicha ko'rinadi:
public Car(String model, int maxSpeed) {
   this.model = model;
   this.maxSpeed = maxSpeed;
}
Va endi ob'ekt yaratish quyidagicha ko'rinadi:
public static void main(String[] args) {
   Car bugatti = new Car("Bugatti Veyron", 407);
}
Diqqat qilishkonstruktor qanday yaratilgan. Bu oddiy usulga o'xshaydi, lekin uning qaytish turi yo'q. Bunday holda, sinf nomi konstruktorda bosh harf bilan ham ko'rsatiladi. Bizning holatda - Avtomobil . Bundan tashqari, konstruktor new-to-you kalit so'zidan foydalanadi this . “This” ingliz tilida “bu, bu” degan ma’noni anglatadi. Bu so'z ma'lum bir ob'ektni anglatadi. Konstruktordagi kod:
public Car(String model, int maxSpeed) {
   this.model = model;
   this.maxSpeed = maxSpeed;
}
deyarli so'zma-so'z tarjima qilish mumkin: " bu mashina uchun model (biz hozir yaratmoqdamiz) = konstruktorda ko'rsatilgan model argumenti . Ushbu mashina uchun maxSpeed ​​(biz yaratayotgan) = maxSpeed ​​argumenti konstruktorda ko'rsatilgan." Bu shunday bo'ldi:
public class Car {

   String model;
   int maxSpeed;

   public Car(String model, int maxSpeed) {
       this.model = model;
       this.maxSpeed = maxSpeed;
   }

   public static void main(String[] args) {
       Car bugatti = new Car("Bugatti Veyron", 407);
       System.out.println(bugatti.model);
       System.out.println(bugatti.maxSpeed);
   }

}
Konsol chiqishi:
Bugatti Veyron 407
Konstruktor kerakli qiymatlarni muvaffaqiyatli tayinladi. Konstruktor oddiy usulga juda o'xshashligini payqagandirsiz! Bu shunday: konstruktor - bu usul, faqat bir oz o'ziga xos :) Xuddi usulda bo'lgani kabi, biz konstruktorimizga parametrlarni uzatdik. Va xuddi usulni chaqirish kabi, agar siz ularni ko'rsatmasangiz, konstruktorni chaqirish ishlamaydi:
public class Car {

   String model;
   int maxSpeed;

   public Car(String model, int maxSpeed) {
       this.model = model;
       this.maxSpeed = maxSpeed;
   }

   public static void main(String[] args) {
       Car bugatti = new Car(); //error!
   }

}
Ko'ryapsizmi, dizayner biz erishmoqchi bo'lgan narsani qildi. Endi siz tezliksiz yoki modelsiz mashina yaratolmaysiz! Konstruktorlar va usullar o'rtasidagi o'xshashliklar shu bilan tugamaydi. Usullar singari, konstruktorlar ham haddan tashqari yuklanishi mumkin. Tasavvur qiling-a, sizning uyingizda 2 ta mushuk bor. Siz ulardan birini mushukcha sifatida olib borgansiz, ikkinchisini esa kattalardek ko'chadan uyga olib kelgansiz va uning necha yoshda ekanligini aniq bilmaysiz. Bu shuni anglatadiki, bizning dasturimiz ikkita turdagi mushuklarni yaratishi kerak - birinchi mushuk uchun ism va yosh bilan va faqat ism bilan - ikkinchi mushuk uchun. Buning uchun biz konstruktorni ortiqcha yuklaymiz:
public class Cat {

   String name;
   int age;

   //for the first cat
   public Cat(String name, int age) {
       this.name = name;
       this.age = age;
   }

   //for the second cat
   public Cat(String name) {
       this.name = name;
   }

   public static void main(String[] args) {

       Cat barsik = new Cat("Barsik", 5);
       Cat streetCatNamedBob = new Cat("Bob");
   }

}
Asl konstruktorga "ism" va "yosh" parametrlari bilan biz boshqasini qo'shdik, faqat ism bilan. Biz avvalgi darslarda xuddi shunday usullarni ortiqcha yuklaganmiz. Endi biz mushuklarning ikkala versiyasini ham muvaffaqiyatli yaratishimiz mumkin :) Konstruktorlar nima uchun kerak?  - 2Ma'ruza boshida siz allaqachon konstruktorlardan foydalanganingizni aytganimizni eslaysizmi, lekin siz buni sezmadingizmi? Ha shunaqa. Gap shundaki, Java-dagi har bir sinf standart konstruktor deb ataladi. Unda hech qanday argument yo'q, lekin har qanday sinfning istalgan ob'ekti yaratilganda u ishga tushadi.
public class Cat {

   public static void main(String[] args) {

       Cat barsik = new Cat(); //this is where the default constructor worked
   }
}
Bir qarashda bu sezilmaydi. Xo'sh, biz ob'ektni yaratdik va uni yaratdik, dizaynerning ishi qayerda? Buni ko'rish uchun keling, o'z qo'llarimiz bilan Cat sinfi uchun bo'sh konstruktor yozamiz va uning ichida biz konsolga ba'zi iboralarni chop etamiz. Agar u ko'rsatilsa, demak konstruktor ishlagan.
public class Cat {

   public Cat() {
       System.out.println("Created a cat!");
   }

   public static void main(String[] args) {

       Cat barsik = new Cat(); //this is where the default constructor worked
   }
}
Konsol chiqishi:
Ular mushuk yaratdilar!
Mana tasdiq! Standart konstruktor har doim sizning sinflaringizda ko'rinmas holda mavjud. Ammo siz uning yana bir xususiyatini bilishingiz kerak. Argumentlar bilan ba'zi konstruktor yaratganingizda standart konstruktor sinfdan yo'qoladi. Buning isboti, aslida, biz yuqorida ko'rdik. Mana bu kodda:
public class Cat {

   String name;
   int age;

   public Cat(String name, int age) {
       this.name = name;
       this.age = age;
   }

   public static void main(String[] args) {

       Cat barsik = new Cat(); //error!
   }
}
Biz mushukni ism va yoshisiz yarata olmadik, chunki biz Cat : string + number uchun konstruktorni aniqladik. Standart konstruktor shundan so'ng darhol sinfdan g'oyib bo'ldi. Shuning uchun, esda tuting: agar sizning sinfingizda bir nechta konstruktorlar kerak bo'lsa, shu jumladan bo'sh bo'lsa, uni alohida yaratishingiz kerak. Masalan, veterinariya klinikasi uchun dastur tuzyapmiz. Klinikamiz xayrli ishlar qilishni va biz ismini ham, yoshini ham bilmaydigan uysiz mushuklarga yordam berishni xohlaydi. Keyin bizning kodimiz quyidagicha ko'rinishi kerak:
public class Cat {

   String name;
   int age;

   //for domestic cats
   public Cat(String name, int age) {
       this.name = name;
       this.age = age;
   }

   //for street cats
   public Cat() {
   }

   public static void main(String[] args) {

       Cat barsik = new Cat("Barsik", 5);
       Cat streetCat = new Cat();
   }
}
Endi biz standart konstruktorni aniq yozdik, biz ikkala turdagi mushuklarni yaratishimiz mumkin :) Konstruktor uchun (har qanday usulda bo'lgani kabi) argumentlar tartibi juda muhim. Keling, konstruktorimizdagi ism va yosh argumentlarini almashtiramiz.
public class Cat {

   String name;
   int age;

   public Cat(int age, String name) {
       this.name = name;
       this.age = age;
   }

   public static void main(String[] args) {

       Cat barsik = new Cat("Barsik", 10); //error!
   }
}
Xato! Konstruktor aniq ta'kidlaydiki, Cat ob'ekti yaratilganda, unga raqam va satr shu tartibda o'tkazilishi kerak. Shuning uchun bizning kodimiz ishlamaydi. Buni unutmang va o'z sinflaringizni yaratishda buni yodda tuting:
public Cat(String name, int age) {
   this.name = name;
   this.age = age;
}

public Cat(int age, String name) {
   this.age = age;
   this.name = name;
}
Bu ikkita butunlay boshqa dizaynerlar! “Bizga konstruktor nima uchun kerak?” degan savolga javobni bir jumla bilan ifodalasak, shuni aytishimiz mumkin: ob'ektlar doimo to'g'ri holatda bo'lsin. Konstruktorlardan foydalanganda, barcha o'zgaruvchilaringiz to'g'ri ishga tushiriladi va dasturda tezlik 0 bo'lgan mashinalar yoki boshqa "noto'g'ri" ob'ektlar bo'lmaydi. Ulardan foydalanish, birinchi navbatda, dasturchining o'zi uchun juda foydali. Agar siz maydonlarni o'zingiz ishga tushirsangiz, biror narsani o'tkazib yuborish va xato qilish xavfi yuqori. Ammo konstruktor bilan bu sodir bo'lmaydi: agar siz unga barcha kerakli argumentlarni o'tkazmagan bo'lsangiz yoki ularning turlarini aralashtirsangiz, kompilyator darhol xatoga yo'l qo'yadi. Alohida ta'kidlab o'tish joizki, dasturingiz mantiqini konstruktor ichiga qo'ymaslik kerak. Buni amalga oshirish uchun sizning ixtiyoringizda barcha kerakli funktsiyalarni tavsiflash mumkin bo'lgan usullar mavjud. Keling, konstruktor mantig'i nima uchun yomon fikr ekanligini ko'rib chiqaylik:
public class CarFactory {

   String name;
   int age;
   int carsCount;

   public CarFactory(String name, int age, int carsCount) {
   this.name = name;
   this.age = age;
   this.carsCount = carsCount;

   System.out.println("Our car factory is called" + this.name);
   System.out.println("She was founded" + this.age + " years ago" );
   System.out.println("During this time it was produced" + this.carsCount +  "cars");
   System.out.println("On average she produces" + (this.carsCount/this.age) + "cars per year");
}

   public static void main(String[] args) {

       CarFactory ford = new CarFactory("Ford", 115 , 50000000);
   }
}
Bizda avtomobillar ishlab chiqaradigan zavodni tavsiflovchi CarFactory klassi mavjud. Konstruktor ichida biz barcha maydonlarni ishga tushiramiz va mantiqni bu yerga joylashtiramiz: zavod haqidagi ba'zi ma'lumotlarni konsolga ko'rsatamiz. Buning hech qanday yomon joyi yo'qdek tuyuladi, dastur mukammal ishladi. Konsol chiqishi:
Bizning avtozavodimiz Ford deb nomlanadi.Bunga 115 yil avval asos solingan.Bu vaqt ichida u 50000000 avtomobil ishlab chiqargan.Yiliga o'rtacha 434782 dona avtomobil ishlab chiqaradi.
Lekin, aslida, biz soatli bomba joylashtirdik. Va bunday kod juda oson xatolarga olib kelishi mumkin. Tasavvur qilaylik, hozir biz Ford haqida emas, balki bir yildan kamroq vaqt davomida mavjud bo'lgan va 1000 ta mashina ishlab chiqargan yangi "Amigo Motors" zavodi haqida ketyapmiz:
public class CarFactory {

   String name;
   int age;
   int carsCount;

   public CarFactory(String name, int age, int carsCount) {
   this.name = name;
   this.age = age;
   this.carsCount = carsCount;

   System.out.println("Our car factory is called" + this.name);
   System.out.println("She was founded" + this.age + " years ago" );
   System.out.println("During this time it was produced" + this.carsCount +  "cars");
   System.out.println("On average she produces" + (this.carsCount/this.age) + "cars per year");
}


   public static void main(String[] args) {

       CarFactory ford = new CarFactory("Amigo Motors", 0 , 1000);
   }
}
Konsol chiqishi:
Bizning avtomobil zavodimiz "main" java.lang.ArithmeticException: / nol bo'yicha Amigo Motors Exception deb ataladi. CarFactory.main(CarFactory.java:23) Chiqish kodi 1</init> bilan jarayon tugallandi
Biz yetib keldik! Dastur g'alati xato bilan yakunlandi. Buning sababi nima ekanligini taxmin qilishga harakat qilasizmi? Sababi biz konstruktorga joylashtirgan mantiqdir. Xususan, ushbu qatorda:
System.out.println("On average she produces" + (this.carsCount/this.age) + "cars per year");
Bu erda biz hisob-kitob qilamiz va ishlab chiqarilgan avtomobillar sonini zavod yoshiga ajratamiz. Bizning fabrikamiz yangi bo'lgani uchun (ya'ni 0 yoshda), natijada matematikada taqiqlangan 0 ga bo'linadi. Natijada dastur xato bilan tugaydi. Nima qilishimiz kerak edi? Barcha mantiqni alohida usulga o'tkazing va uni chaqiring, masalan, printFactoryInfo() . Siz uni parametr sifatida CarFactory ob'ektini o'tkazishingiz mumkin . Shuningdek, siz barcha mantiqni u erga qo'yishingiz mumkin va shu bilan birga - bizniki kabi nol yil bilan mumkin bo'lgan xatolarni qayta ishlashingiz mumkin. Har kimga o'zi. Ob'ekt holatini to'g'ri o'rnatish uchun konstruktorlar kerak. Biznes mantig'i uchun bizda usullar mavjud. Birini boshqasiga aralashtirmaslik kerak.
Izohlar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION