Kumusta, lahat! Ngayon ay ipinagpapatuloy ko ang aking pagsusuri sa mga tanong sa panayam ng developer ng Java. Paggalugad ng mga tanong at sagot mula sa isang job interview para sa isang Java developer position.  Bahagi 4 - 1

29. Maaari bang gamitin ang return sa isang constructor?

Oo, ngunit walang halaga lamang sa kanan ng return keyword. Maaari mong gamitin ang pagbabalik; bilang isang katulong na pahayag sa isang constructor upang agarang wakasan (i-interrupt) ang pagpapatupad ng karagdagang code at tapusin ang pagsisimula ng bagay. Halimbawa, ipagpalagay na mayroon kaming klase ng Cat , at kung ang isang Pusa ay walang tahanan ( isHomeless = true , gusto naming wakasan ang pagsisimula at huwag punan ang iba pang mga field (pagkatapos ng lahat, hindi namin sila kilala, dahil ang pusa ay walang tirahan) :
public Cat(int age, String name, boolean isHomeless) {
   if (isHomeless){
       this.isHomeless = isHomeless;
       return;
   }
   this.isHomeless = isHomeless;
   this.age = age;
   this.name = name;
}
Ngunit kung ang pinag-uusapan natin ay tungkol sa mga kongkretong halaga, kung gayon ang return keyword ay hindi makakapagbalik ng isang partikular na halaga dahil:
  • kapag nagdeklara ka ng isang tagabuo, hindi ka magkakaroon ng anumang bagay tulad ng uri ng pagbabalik;
  • bilang panuntunan, ang tagabuo ay tahasang tinatawag sa panahon ng instantiation;
  • ang constructor ay hindi isang paraan: ito ay isang hiwalay na mekanismo na ang tanging layunin ay upang simulan ang mga variable ng instance, ibig sabihin, ginagamit namin ang bagong operator upang lumikha ng isang bagay.
Paggalugad ng mga tanong at sagot mula sa isang job interview para sa isang Java developer position.  Bahagi 4 - 2

30. Maaari bang itapon ang isang exception mula sa isang constructor?

Gumagana ang mga konstruktor na may mga pagbubukod sa parehong paraan na ginagawa ng mga pamamaraan. Binibigyang-daan kami ng mga pamamaraan na maghagis ng mga pagbubukod sa pamamagitan ng pagsulat ng mga throws <ExceptionType> sa header ng pamamaraan. At pinapayagan kami ng mga konstruktor na gawin ang pareho. Kapag minana at tinutukoy natin ang constructor ng isang child class, maaari nating palawakin ang uri ng exception — halimbawa, IOException -> Exception (ngunit hindi vice versa). Gamitin natin ang constructor ng Cat class bilang isang halimbawa ng isang constructor na naghahagis ng exception. Sabihin nating kapag gumawa tayo ng object, gusto nating ilagay ang pangalan at edad mula sa console:
public Cat() throws IOException {
   BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
   this.name = reader.readLine();
   this.age = Integer.parseInt(reader.readLine());
}
Dahil naghagis ang reader.readLine() ng IOException, isinusulat namin ito sa header bilang posibleng itinapon na exception.

31. Ano ang mga elemento ng header ng klase? Sumulat ng isang halimbawa

Upang ilarawan ang mga elemento na bumubuo sa isang header ng klase, tingnan natin ang isang maliit na schema:
  • lumilitaw ang mga kinakailangang elemento sa mga bracket <>
  • ang mga opsyonal na elemento ay nasa {}
{access modifier}{static}{final}{abstract}<class name>{inheritance of Parent class}{implementation of interfaces} Kaya, kung ano ang mayroon kami: {access modifier } — tanging ang pampubliko at default na access modifier ang available para sa klase. {static} — ang static na modifier ay nagpapahiwatig na ang klase ay static; nalalapat lamang ito sa mga panloob na klase (mga klase sa loob ng ibang mga klase). {final} — ito ang panghuling modifier, siyempre, na ginagawang hindi mamanahin ang klase (isang out-of-the-box na halimbawa ay String ). {abstract} — ang abstract modifier, na nagpapahiwatig na ang klase ay maaaring may mga hindi naipatupad na pamamaraan. Sumasalungat ang modifier na ito sa panghuling modifier. Ang header ng klase ay maaari lamang magkaroon ng isa sa mga ito dahil ang abstract modifier ay nangangahulugan na ang klase ay mamanahin at ang mga abstract na elemento nito ay ipapatupad. Ngunit ipinahihiwatig ng final na ito ang panghuling bersyon ng klase, at hindi ito maaaring mamana. Sa totoo lang, ang sabay-sabay na paggamit ng parehong mga modifier ay magiging walang katotohanan. Hindi kami hahayaan ng compiler na gawin ito. Ang <class> ay isang mandatoryong keyword na nagsasaad ng deklarasyon ng klase. Ang <class name> ay isang simpleng pangalan ng klase na nagiging identifier ng isang partikular na klase ng Java. Ang ganap na kwalipikadong pangalan ng klase ay binubuo ng kwalipikadong pangalan ng package kasama ang '.' kasama ang simpleng pangalan ng klase. Ang {inheritance of the Parent class} ay isang indikasyon ng parent class (kung mayroon man) gamit ang extends na keyword. Halimbawa, ... pinalawak ang ParentClass . {implementation of interfaces} — isang listahan ng mga interface na ipinapatupad ng klase na ito (kung mayroon man), gamit ang mga implement na keyword. Halimbawa: ... nagpapatupad ng FirstInterface, SecondInterface ... Bilang halimbawa, isaalang-alang ang heading ng klase ng klase ng Lion , na nagmamana ng Cat at nagpapatupad ng interface ng WildAnimal :
public final class Lion extends Cat implements WildAnimal
Paggalugad ng mga tanong at sagot mula sa isang job interview para sa isang Java developer position.  Bahagi 4 - 3

32. Ano ang mga elemento ng isang header ng pamamaraan? Sumulat ng isang halimbawa

Kapag isinasaalang-alang ang mga elemento na bumubuo sa isang header ng pamamaraan, muli nating isaalang-alang ang isang maliit na schema:
  • lumilitaw ang mga kinakailangang elemento sa mga bracket <>
  • ang mga opsyonal na elemento ay nasa {}
{access modifier}{static}{abstract}{final}{synchronized} {native} <return value><method name> <(>{method parameters}<}>{throw exceptions} {access modifier} — lahat ng access modifiers ay magagamit para sa pamamaraan — pampubliko , protektado , default , pribado . {static} — ang static na modifier, na nagpapahiwatig na ang pamamaraan ay static at samakatuwid ay nauugnay sa klase, hindi isang bagay. {abstract} — ang abstract modifier, na nagpapahiwatig na ang pamamaraan ay walang pagpapatupad (katawan). Upang gumana nang tama, ang klase na nagdedeklara ng pamamaraan ay dapat ding mayroong abstract modifier. Gaya sa header ng klase, ang modifier na ito ay sumasalungat sa panghuling modifier, at sumasalungat din sa static na modifier, dahil ang isang Ang abstract na pamamaraan ay nagpapahiwatig ng pag-override sa pamamaraan sa isang descendant, at ang mga static na pamamaraan ay hindi maaaring i-override. {finale} — ang panghuling modifier, na nagpapahiwatig na ang pamamaraang ito ay hindi maaaring i-override. {synchronized} — ang naka-synchronize na modifier, na nangangahulugan na ang pamamaraan ay protektado mula sa sabay-sabay na pag-access dito mula sa iba't ibang mga thread. Kung ang pamamaraan ay hindi static, pagkatapos ito ay sarado para sa bagay na ito mutex. Kung ang pamamaraan ay static, pagkatapos ito ay sarado para sa mutex ng kasalukuyang klase. {native} — ang katutubong modifier ay nagpapahiwatig na ang pamamaraan ay nakasulat sa ibang programming language. <return type> — ang uri ng value na dapat ibalik ng paraan. Kung ang pamamaraan ay hindi nagbabalik ng anuman, pagkatapos ay walang bisa . <pangalan ng pamamaraan> — ang pangalan ng pangalan ng pamamaraan, ibig sabihin, ang pagkakakilanlan nito sa system. {method parameters} — ang mga parameter na tinatanggap ng pamamaraan: kinakailangan ang mga ito para ipatupad ang functionality nito. {thrown exceptions}throws <ExceptionType> — isang listahan ng mga may check na exception na maaaring itapon ng paraang ito. Iaalok ko ang sumusunod bilang isang halimbawa ng isang header ng pamamaraan:
public static void main(String[] args) throws IOException

33. Gumawa ng default na constructor sa isang child class kung ang isa ay hindi pa tinukoy sa base class (ngunit ibang constructor ang tinukoy)

Hindi ako sigurado na lubos kong nauunawaan ang tanong, ngunit marahil ito ay nangangahulugan na mayroon kaming ilang tagabuo na tulad nito sa klase ng magulang:
public Cat(int age, String name) {
   this.age = age;
   this.name = name;
}
Sa kasong iyon, sa parent class, tiyak na kailangan nating tukuyin ang isang constructor na magpapasimula sa parent (ibig sabihin, tawagan ang parent constructor):
public class Lion extends Cat {

   public Lion(int age, String name) {
       super(age, name);
   }
}
Paggalugad ng mga tanong at sagot mula sa isang job interview para sa isang Java developer position.  Bahagi 4 - 4

34. Kailan ginagamit ang keyword na ito?

Sa Java, ito ay may dalawang magkaibang kahulugan. 1. Ito ay isang sanggunian sa kasalukuyang bagay, hal this.age = 9 . Ibig sabihin, ito ay tumutukoy sa bagay kung saan ito ginagamit at kung saan ang code na may ganito ay tumutukoy. Ang pangunahing layunin ay upang mapabuti ang pagiging madaling mabasa ng code at maiwasan ang kalabuan. Halimbawa, kung ang isang instance field at isang method argument ay may parehong pangalan:
public void setName(String name) {
   this.name = name;
}
Ibig sabihin, this.name ay ang field ng object, habang ang pangalan ay ang method parameter. Ang sanggunian na ito ay hindi maaaring gamitin sa mga static na pamamaraan. 2. Sa constructor, ito ay maaaring tawaging tulad ng isang pamamaraan, hal this(value) . Sa kasong ito, ito ay magiging isang tawag sa isa pang constructor ng parehong klase. Karaniwan, maaari kang tumawag ng dalawang konstruktor sa panahon ng proseso ng paglikha ng isang bagay:
public Cat(int age, String name) {
   this(name);
   this.age = age;
}

public Cat(String name) {
   this.name = name;
}
Kapag tinatawagan ang unang constructor para gumawa ng Cat object, ang parehong field ng instance ay matagumpay na masisimulan. Mayroong ilang mga nuances dito:
  1. this() gumagana lang sa isang constructor.
  2. Ang isang reference sa isa pang constructor ay dapat nasa unang linya ng constructor block (katawan). Nangangahulugan ito na ang isang constructor ay hindi maaaring tumawag ng higit sa isang (iba pang) constructor ng klase nito.
Paggalugad ng mga tanong at sagot mula sa isang job interview para sa isang Java developer position.  Bahagi 4 - 5

35. Ano ang initializer?

Sa pagkakaintindi ko, ang tanong na ito ay tungkol sa ordinaryong at static na mga bloke ng pagsisimula. Tandaan muna natin kung ano ang initialization. Ang pagsisimula ay ang paglikha, pag-activate, paghahanda, at kahulugan ng mga field. Paghahanda ng isang programa o bahagi upang maging handa para sa paggamit. Maaalala mo na kapag lumikha ka ng isang bagay, ang isang variable ng klase ay maaaring masimulan kaagad kapag ito ay idineklara:
class Cat {
   private int age = 9;
   private String name = "Tom";
O itakda pagkatapos ng katotohanan sa pamamagitan ng constructor:
class Cat {
   private int age;
   private String name;

   public Cat(int age, String name) {
       this.age = age;
       this.name = name;
   }
Ngunit may isa pang paraan: maaari kang magtakda ng instance variable gamit ang isang initialization block, na kumukuha ng anyo ng curly braces {} sa loob ng isang klase, na walang pangalan (tulad ng isang walang pangalan na paraan o constructor):
class Cat {
   private int age;
   private String name;

   {
       age = 10;
       name = "Tom";
   }
Ang initialization block ay isang piraso ng code na nilo-load kapag nilikha ang isang bagay. Ang ganitong mga bloke ay karaniwang ginagamit upang magsagawa ng ilang mga kumplikadong kalkulasyon na kinakailangan kapag ang isang klase ay na-load. Ang mga resulta ng mga kalkulasyong ito ay maaaring itakda bilang mga halaga ng mga variable. Bilang karagdagan sa mga ordinaryong bloke ng pagsisimula, mayroong mga static. Magkamukha ang mga ito ngunit may static na keyword sa harap ng pambungad na curly brace:
class Cat {
   private static int age;
   private static String name;

   static{
       age = 10;
       name = "Tom";
   }
Ang bloke na ito ay kapareho ng nauna. Ngunit kung ang ordinaryong isa ay naisakatuparan kapag ang bawat bagay ay sinimulan, kung gayon ang static ay isasagawa lamang ng isang beses, kapag ang klase ay na-load. Bilang isang patakaran, ang ilang mga kumplikadong kalkulasyon ay ginagawa sa isang static na bloke, na ginagamit upang simulan ang mga static na variable ng klase. Ang parehong mga paghihigpit ay nalalapat sa isang static na bloke na nalalapat sa mga static na pamamaraan: hindi ka maaaring gumamit ng hindi static na data, tulad ng isang reference sa kasalukuyang bagay ( ito ) sa isang static na bloke. Paggalugad ng mga tanong at sagot mula sa isang job interview para sa isang Java developer position.  Bahagi 4 - 6Ngayon ay maaari nating tingnan ang pagkakasunud-sunod ng pagsisimula ng klase (kasama ang parent class nito) upang mas maunawaan kung kailan eksaktong ginagamit ang mga initialization block.

36. Dahil sa pampublikong klase ng Bata na nagpapalawak ng Magulang, isulat ang pagkakasunud-sunod ng pagsisimula ng bagay

Kapag nilo-load ang klase ng Bata , ang pagkakasunud-sunod ng pagsisimula ay ang mga sumusunod:
  1. Static class field ng Parent class.
  2. Static initialization block ng Parent class.
  3. Mga static na field ng Сhild class.
  4. Static initialization block ng klase ng Bata .
  5. Mga non-static na field ng Parent class.
  6. Non-static na initialization block ng Parent class.
  7. Tagabuo ng klase ng magulang .
  8. Mga non-static na field ng Сhild class.
  9. Non-static na initialization block ng Сhild class.
  10. Ang constructor ng Сhild class.
Paggalugad ng mga tanong at sagot mula sa isang job interview para sa isang Java developer position.  Bahagi 4 - 7

37. Anong uri ng mga relasyon sa pagitan ng mga klase (mga bagay) ang alam mo?

Mayroong dalawang uri ng mga variable sa Java: mga primitive na uri at mga sanggunian sa ganap na mga bagay.
  • IS-A na mga relasyon
Ang prinsipyo ng IS-A ng OOP ay batay sa class inheritance o pagpapatupad ng mga interface. Halimbawa, kung ang klase ng Lion ay nagmamana ng Cat , pagkatapos ay sasabihin namin na ang Lion ay isang Pusa :
Lion IS-A Cat
(ngunit hindi lahat ng Pusa ay isang Lion ) Ang parehong sitwasyon ay umiiral sa mga interface. Kung ang klase ng Lion ay nagpapatupad ng interface ng WildAnimal , kung gayon mayroon din sila sa relasyon:
Lion IS-A WildAnimal
  • MAY-Isang relasyon
Ang ganitong uri ng relasyon ay kung saan ang isang klase ay gumagamit ng iba pang mga klase, na tinatawag ding "asosasyon". Ang asosasyon ay isang klase na tumutukoy sa ibang klase (o mutual reference sa isa't isa). Halimbawa, maaaring tukuyin ng klase ng Kotse ang klase ng Pasahero , na bubuo ng sumusunod na kaugnayan:
Car HAS-A Passenger
At kabaliktaran: kung ang Pasahero ay may reference sa Kotse , ito ang magiging ugnayan:
Passenger HAS-A Car

38. Anong mga ugnayang nauugnay sa bagay ang alam mo?

Ang pagsasama-sama at komposisyon ay hindi hihigit sa mga espesyal na kaso ng pagsasamahan. Ang pagsasama-sama ay isang relasyon kung saan ang isang bagay ay bahagi ng isa pa. Halimbawa, ang isang pasahero ay maaaring matatagpuan sa isang kotse. Higit pa rito, maaaring maraming pasahero o wala (at kung Tesla ang pag-uusapan, maaaring walang driver). Halimbawa:
public class Car {
   private List passengers = new ArrayList<>();

 void setPassenger(Passenger passenger) {
     passengers.add(passenger);
 }

   void move() {
       for (Passenger passenger : passengers) {
           System.out.println("Transporting passenger - " + passenger.toString());
       }
       passengers.clear();
   }
}
Sa madaling salita, ang bilang ng mga pasahero (sa alinmang) ay hindi mahalaga sa amin: ang paggana ng klase ng Kotse ay hindi nakasalalay dito. Ang pagsasama-sama ay nagpapahiwatig din na kapag ang isa pang bagay ay gumagamit ng isang bagay, ang unang bagay ay maaaring gamitin ng iba pang mga bagay. Halimbawa, ang parehong mag-aaral ay maaaring nasa isang knitting club at isang rock band at sabay-sabay na dumalo sa isang klase sa Espanyol. Gaya ng maiisip mo, ang pagsasama-sama ay isang mas maluwag na ugnayan sa pagitan ng mga klase. Ang komposisyon ay isang mas mahigpit na ugnayan kung saan ang isang bagay ay hindi lamang bahagi ng isa pang bagay, ngunit ang gawain ng isang bagay ay nakadepende sa iba. Halimbawa, ang isang kotse ay may makina. Ang isang makina ay maaaring umiral nang walang kotse, ngunit ito ay walang silbi sa labas ng isang kotse. At ang isang kotse ay hindi maaaring gumana nang walang makina:
public class Car {
   private Engine engine;

   public Car(Engine engine) {
       this.engine = engine;
   }

   void startMoving() {
       engine.start();
           ...
   }
Ang komposisyon ay nagpapahiwatig din na kapag ang isa pang bagay ay gumagamit ng isang bagay, ang unang bagay ay hindi maaaring kabilang sa anumang iba pang bagay. Kung babalikan ang aming halimbawa, ang isang makina ay maaari lamang pag-aari ng isang kotse, hindi dalawa o higit pa sa parehong oras. Sa tingin ko ay sapat na iyon para sa araw na ito, kaya titigil na tayo rito.