CodeGym /Java Blogu /Rastgele /Java Yapıcıları
John Squirrels
Seviye
San Francisco

Java Yapıcıları

grupta yayınlandı
MERHABA! Bugün nesnelerimizi ilgilendiren çok önemli bir konuyu ele alacağız. Abartmadan bu konuyu gerçek hayatta her gün kullanacağınızı söyleyebiliriz! Java Yapıcılarından bahsediyoruz. Bu terimi ilk kez duyuyor olabilirsiniz, ancak aslında kurucuları zaten kullanmışsınızdır. Farkına varmadın :) Kendimizi buna sonra ikna ederiz.

Yapıcılar dünyada neler var ve onlara neden ihtiyaç duyuluyor?

İki örneği ele alalım.

public class Car {

   String model;
   int maxSpeed;

   public static void main(String[] args) {

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

   }
}
Arabamızı yarattık, modelini ve maksimum hızını belirledik. Ancak Car nesnesinin gerçek bir projede 2 alanı olmayacağı açıktır. Örneğin, 16 alanı olabilir!

public class Car {

   String model;// model
   int maxSpeed;// maximum speed
   int wheels;// wheel width
   double engineVolume;// engine volume
   String color;// color
   int productionYear;// production year
   String ownerFirstName;// first name of owner
   String ownerLastName;// last name of owner
   long price;// price
   boolean isNew;// flag indicating whether car is new
   int seatsInTheCar;// number of seats in the car
   String cabinMaterial;// interior material
   boolean insurance;// flag indicating whether car is insured
   String manufacturerCountry;// manufacturer country
   int trunkVolume;// size of the trunk
   int accelerationTo100km;// how long it takes to accelerate 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.productionYear = 2016;
       bugatti.insurance = true;
       bugatti.price = 2000000;
       bugatti.isNew = false;
       bugatti.seatsInTheCar = 2;
       bugatti.maxSpeed = 378;
       bugatti.model = "Bugatti Veyron";

   }

}
Yeni bir Araba nesnesi yarattık . Bir sorun var: 16 alanımız var, ancak yalnızca 12'yi başlattık ! Şimdi koda bakın ve unuttuğumuz alanları bulmaya çalışın! O kadar kolay değil, değil mi? Bu durumda, bir programcı kolayca hata yapabilir ve bazı alanları başlatamayabilir. Sonuç olarak, program yanlış davranacaktır:

public class Car {

   String model;// model
   int maxSpeed;// maximum speed
   int wheels;// wheel width
   double engineVolume;// engine volume
   String color;// color
   int productionYear;// production year
   String ownerFirstName;// first name of owner
   String ownerLastName;// last name of owner
   long price;// price
   boolean isNew;// flag indicating whether car is new
   int seatsInTheCar;// number of seats in the car
   String cabinMaterial;// interior material
   boolean insurance;// flag indicating whether car is insured
   String manufacturerCountry;// manufacturer country
   int trunkVolume;// size of the trunk
   int accelerationTo100km;// how long it takes to accelerate 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.productionYear = 2016;
       bugatti.insurance = true;
       bugatti.price = 2000000;
       bugatti.isNew = false;
       bugatti.seatsInTheCar = 2;
       bugatti.maxSpeed = 378;
       bugatti.model = "Bugatti Veyron";

       System.out.println("Model: Bugatti Veyron. Engine volume: " + bugatti.engineVolume + ". Trunk volume: " + bugatti.trunkVolume + ". Cabin material: " + bugatti.cabinMaterial +
       ". Wheel width: " + bugatti.wheels + ". Purchased in 2018 by Mr. " + bugatti.ownerLastName);

   }

}
Konsol çıkışı: Model: Bugatti Veyron. Motor hacmi: 6.3. Bagaj hacmi: 0. Kabin malzemesi: boş. Jant genişliği: 0. 2018 yılında Mr. null tarafından satın alındı ​​Araba için 2 milyon dolardan vazgeçen alıcınız, belli ki " Mr. null " olarak anılmaktan hoşlanmayacak! Ama ciddi olarak, sonuç olarak, programımız bir nesneyi yanlış yarattı: tekerlek genişliği 0 olan (yani hiç tekerleği olmayan) bir araba, eksik bir bagaj, bilinmeyen bir malzemeden yapılmış bir kabin ve hepsinden önemlisi, tanımlanmamış bir sahibi . Program çalışırken böyle bir hatanın nasıl "patladığını" ancak hayal edebilirsiniz! Bir şekilde bu tür durumlardan kaçınmamız gerekiyor. Programımızı kısıtlamamız gerekiyor: yeni bir Araba oluştururkennesne, model ve maksimum hız gibi alanların her zaman belirtilmesini istiyoruz. Aksi takdirde, nesnenin oluşturulmasını engellemek istiyoruz. İnşaatçılar bu görevi kolaylıkla halleder. İsimlerini bir sebeple aldılar. Yapıcı, her yeni nesnenin eşleşmesi gereken bir tür "iskelet" sınıfı oluşturur. Kolaylık sağlamak için, Car sınıfının iki alanlı daha basit versiyonuna geri dönelim . Gereksinimlerimizi göz önünde bulundurarak, Araba sınıfının kurucusu şöyle görünecektir:

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

// And creating an object now looks like this:

public static void main(String[] args) {
   Car bugatti = new Car("Bugatti Veyron", 378);
}
Bir yapıcının nasıl bildirildiğine dikkat edin. Normal bir yönteme benzer, ancak dönüş türü yoktur. Ayrıca yapıcı, sınıf adını ( Car ) büyük harfle başlayarak belirtir. Ek olarak, yapıcı sizin için yeni olan bir anahtar kelime ile kullanılır: this . this anahtar sözcüğü belirli bir nesneyi belirtmek içindir. Yapıcıdaki kod

public Car(String model, int maxSpeed) {
   this.model = model;
   this.maxSpeed = maxSpeed;
}
neredeyse kelimesi kelimesine yorumlanabilir: " Bu arabanın modeli (şu anda oluşturduğumuz model), kurucuya iletilen model argümanıdır. yapıcı." Ve olan tam da bu:

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", 378);
       System.out.println(bugatti.model);
       System.out.println(bugatti.maxSpeed);
   }

}
Konsol çıktısı: Bugatti Veyron 378 Yapıcı gerekli değerleri doğru bir şekilde atadı. Bir yapıcının sıradan bir yönteme çok benzediğini fark etmiş olabilirsiniz! İşte bu. Kurucu gerçekten bir yöntemdir, ancak belirli özellikleri vardır :) Tıpkı yöntemlerde olduğu gibi, yapıcımıza argümanlar ilettik. Ve tıpkı bir yöntemi çağırmak gibi, bir yapıcıyı çağırmak siz belirtmediğiniz sürece çalışmaz:

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!
   }
  
}
Yapıcının başarmaya çalıştığımız şeyi başardığını görebilirsiniz. Artık hızı veya modeli olmayan bir araba yaratamazsınız! Yapıcılar ve yöntemler arasındaki benzerlik burada bitmiyor. Tıpkı yöntemler gibi, yapıcılar da aşırı yüklenebilir. Evde 2 evcil kediniz olduğunu düşünün. Onlardan birini yavru kedi olarak aldın. Ama ikincisini daha büyümüşken sokaktan almışsın ve tam olarak kaç yaşında olduğunu bilmiyorsun. Bu durumda, programımızın iki tür kedi oluşturabilmesini istiyoruz: adı ve yaşı olan (ilk kedi için) ve sadece adı olan (ikinci kedi için). Bunun için yapıcıyı aşırı yükleyeceğiz:

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 smudge = new Cat("Smudge", 5);
       Cat streetCatNamedBob = new Cat("Bob");
   }

}
"name" ve "age" parametreli orijinal kurucuya ek olarak, sadece name parametreli bir tane daha ekledik. Tıpkı önceki derslerde yöntemleri aşırı yüklediğimiz gibi. Artık her iki tür kediyi de yaratabiliriz :)
Neden yapıcılara ihtiyacımız var?  - 2
Dersin başında, farkında olmadan kurucuları zaten kullandığınızı söylediğimizi hatırlıyor musunuz? Biz ne dediysek onu kastettik. Gerçek şu ki, Java'daki her sınıf, varsayılan bir kurucu olarak adlandırılan şeye sahiptir. Herhangi bir argüman almaz, ancak herhangi bir sınıftan herhangi bir nesne oluşturduğunuzda çağrılır.

public class Cat {

   public static void main(String[] args) {

       Cat smudge = new Cat(); // The default constructor is invoked here
   }
}
İlk bakışta görünmez. Bir nesne yarattık, ne olmuş yani? Yapıcı burada nerede bir şey yapıyor? Bunu görmek için, açık bir şekilde Cat sınıfı için boş bir oluşturucu yazalım . İçinde bazı ifadeler göstereceğiz. Cümle görüntülenirse, yapıcı çağrıldı.

public class Cat {

   public Cat() {
       System.out.println("A cat has been created!");
   }

   public static void main(String[] args) {

       Cat smudge = new Cat(); // The default constructor is invoked here
   }
}
Konsol çıktısı: Bir kedi yaratıldı! İşte onay! Varsayılan kurucu, sınıflarınızda her zaman görünmez bir şekilde bulunur. Ancak bununla ilgili bir şeyi daha bilmeniz gerekiyor. Bağımsız değişkenlerle bir kurucu oluşturduğunuzda, varsayılan kurucu bir sınıftan elenir. Aslında, bunun kanıtını zaten yukarıda gördük. Bu koddaydı:

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 smudge = new Cat(); //Error!
   }
}
İsimsiz ve yaşsız bir Cat yaratamadık , çünkü string ve int parametreleriyle bir Cat kurucusu tanımladık . Bu, varsayılan kurucunun sınıftan hemen kaybolmasına neden oldu. Bu nedenle, sınıfınızda bağımsız değişken içermeyen bir oluşturucu da dahil olmak üzere birkaç oluşturucuya ihtiyacınız varsa, onu ayrı ayrı bildirmeniz gerekeceğini unutmayın. Örneğin bir veteriner kliniği için bir program oluşturduğumuzu varsayalım. Kliniğimiz, adları ve yaşları bilinmeyen sahipsiz yavru kedilere iyilik yapmak ve yardım etmek istiyor. O zaman kodumuz şöyle görünmelidir:

public class Cat {

   String name;
   int age;

   // For cats with owners
   public Cat(String name, int age) {
       this.name = name;
       this.age = age;
   }

   // For street cats
   public Cat() {
   }

   public static void main(String[] args) {

       Cat smudge = new Cat("Smudge", 5);
       Cat streetCat = new Cat();
   }
}
Artık açık bir varsayılan kurucu yazdığımıza göre, her iki kedi türünü de oluşturabiliriz :) Herhangi bir yöntemde olduğu gibi, bir kurucuya iletilen bağımsız değişkenlerin sırası çok önemlidir. Yapıcımızdaki isim ve yaş argümanlarını değiştirelim .

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 smudge = new Cat("Smudge", 10); // Error!
   }
}
Bir hata! Yapıcı, bir Cat nesnesi oluşturulduğunda, bu sırayla bir sayı ve bir dize iletilmesi gerektiğini açıkça belirtir. Yani kodumuz çalışmıyor. Bunu hatırladığınızdan ve kendi sınıflarınızı ilan ederken aklınızda bulundurduğunuzdan emin olun:

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

public Cat(int age, String name) {
   this.age = age;
   this.name = name;
}
Bunlar tamamen farklı iki kurucu! "Neden bir kurucuya ihtiyacım var?" sorusunun cevabını tek bir cümle ile ifade edecek olursak, "Nesnelerin her zaman geçerli bir duruma sahip olmasını sağlamak için" diyebiliriz. Yapıcıları kullandığınızda, tüm değişkenleriniz doğru bir şekilde başlatılacaktır. Programlarınızda 0 hıza sahip herhangi bir araba veya diğer "geçersiz" nesneler olmayacak. Ana faydaları programcı içindir. Alanları manuel olarak başlatırsanız (bir nesne oluşturduktan sonra), bir şeyi gözden kaçırma ve bir hataya neden olma riskiniz çok yüksektir. Ancak bu bir oluşturucu ile olmaz: gerekli tüm bağımsız değişkenleri iletmezseniz veya yanlış türde bağımsız değişkenleri iletirseniz, derleyici hemen bir hata kaydeder. Programınızı koymamanız gerektiğini de ayrıca söylemeliyiz' Bir yapıcı içindeki mantık. Yöntemler bunun içindir. Yöntemler, gerekli tüm işlevleri tanımlamanız gereken yerdir. Bir yapıcıya mantık eklemenin neden kötü bir fikir olduğunu görelim:

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("It was founded " + this.age + " years ago" );
   System.out.println("Since that time, it has produced " + this.carsCount +  " cars");
   System.out.println("On average, it produces " + (this.carsCount/this.age) + " cars per year");
}

   public static void main(String[] args) {

       CarFactory ford = new CarFactory("Ford", 115 , 50000000);
   }
}
Araba fabrikasını tanımlayan bir CarFactory sınıfımız var . Yapıcının içinde, tüm alanları başlatıyoruz ve bazı mantıklar ekliyoruz: fabrika hakkında bazı bilgiler gösteriyoruz. Bunda kötü bir şey yok gibi görünüyor. Program iyi çalışıyor. Konsol çıktısı: Araba fabrikamızın adı Ford 115 yıl önce kuruldu O zamandan beri 50000000 araba üretti Ortalama olarak yılda 434782 araba üretiyor Ama aslında zaman gecikmeli bir mayın döşedik. Ve bu tür bir kod çok kolay bir şekilde hatalara yol açabilir. Diyelim ki şimdi Ford'dan değil, bir yıldan az bir süredir var olan ve 1000 araba üreten "Amigo Motors" adlı yeni bir fabrikadan bahsediyoruz:

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 factor is called " + this.name);
   System.out.println("It was founded " + this.age + " years ago" );
   System.out.println("Since that time, it has produced " + this.carsCount +  " cars");
   System.out.println("On average, it produces " + (this.carsCount/this.age) + " cars per year");
}


   public static void main(String[] args) {

       CarFactory ford = new CarFactory("Amigo Motors", 0 , 1000);
   }
}
Konsol çıktısı: Araba fabrikamızın adı "main" iş parçacığında Amigo Motors İstisnası java.lang.ArithmeticException: / by zero 0 yıl önce kuruldu O zamandan beri CarFactory'de 1000 araba üretti. (CarFactory.java:15) at CarFactory.main(CarFactory.java:23) İşlem, çıkış kodu 1 ile tamamlandı Boom! Program bir tür anlaşılmaz hatayla sona eriyor. Nedenini tahmin etmeye çalışabilir misin? Sorun, yapıcıya koyduğumuz mantıkta. Daha spesifik olarak, bu satır:

System.out.println("On average, it produces " + (this.carsCount/this.age) + " cars per year");
Burada bir hesaplama yapıyorsunuz ve üretilen araba sayısını fabrikanın yaşına bölüyorsunuz. Ve fabrikamız yeni olduğu için (yani 0 yaşında olduğu için) 0'a bölüyoruz ki bunu matematikte yapamayız. Sonuç olarak, program bir hata ile sonlandırılır.

Ne yapmalıydık?

Tüm mantığı ayrı bir yönteme koyun. Buna printFactoryInfo() diyelim . Argüman olarak ona bir CarFactory nesnesi iletebilirsiniz . Tüm mantığı oraya koyabilir ve aynı anda potansiyel hataları (sıfır yıl içeren bizimki gibi) halledebilirsiniz. Herkesinki kendine. Geçerli nesne durumunu ayarlamak için yapıcılara ihtiyaç vardır. İş mantığı için yöntemlerimiz var. Birini diğeriyle karıştırmayın. Öğrendiklerinizi pekiştirmek için Java Kursumuzdan bir video dersi izlemenizi öneririz.
Yorumlar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION