CodeGym /Blog Java /Random-PL /Przeglądanie pytań i odpowiedzi z rozmowy kwalifikacyjnej...
John Squirrels
Poziom 41
San Francisco

Przeglądanie pytań i odpowiedzi z rozmowy kwalifikacyjnej na stanowisko programisty Java. Część 4

Opublikowano w grupie Random-PL
Witam wszystkich! Dzisiaj kontynuuję przegląd pytań do wywiadu z programistą Java. Przeglądanie pytań i odpowiedzi z rozmowy kwalifikacyjnej na stanowisko programisty Java.  Część 4 - 1

29. Czy w konstruktorze można zastosować funkcję return?

Tak, ale tylko bez wartości po prawej stronie słowa kluczowego return . Możesz użyć zwrotu; jako instrukcja pomocnicza w konstruktorze, aby pilnie zakończyć (przerwać) wykonywanie dalszego kodu i zakończyć inicjalizację obiektu. Załóżmy na przykład, że mamy klasę Kot i jeśli Kot jest bezdomny ( isHomeless = true , to chcemy zakończyć inicjalizację i nie wypełniać pozostałych pól (w końcu są nam nieznane, ponieważ kot jest bezdomny) :
public Cat(int age, String name, boolean isHomeless) {
   if (isHomeless){
       this.isHomeless = isHomeless;
       return;
   }
   this.isHomeless = isHomeless;
   this.age = age;
   this.name = name;
}
Ale jeśli mówimy o konkretnych wartościach, to słowo kluczowe return nie może zwrócić określonej wartości, ponieważ:
  • kiedy zadeklarujesz konstruktora, nie będziesz mieć niczego podobnego do typu zwracanego;
  • z reguły konstruktor jest wywoływany niejawnie podczas tworzenia instancji;
  • konstruktor nie jest metodą: jest oddzielnym mechanizmem, którego jedynym celem jest inicjalizacja zmiennych instancji, tzn. używamy operatora new do utworzenia obiektu.
Przeglądanie pytań i odpowiedzi z rozmowy kwalifikacyjnej na stanowisko programisty Java.  Część 4 - 2

30. Czy konstruktor może zgłosić wyjątek?

Konstruktory działają z wyjątkami w taki sam sposób, jak metody. Metody pozwalają nam zgłaszać wyjątki poprzez zapisanie rzutów <ExceptionType> w nagłówku metody. Konstruktorzy pozwalają nam zrobić to samo. Kiedy dziedziczymy i definiujemy konstruktor klasy podrzędnej, możemy rozszerzyć typ wyjątku — na przykład IOException -> Wyjątek (ale nie odwrotnie). Użyjmy konstruktora klasy Cat jako przykładu konstruktora zgłaszającego wyjątek. Powiedzmy, że tworząc obiekt chcemy z konsoli wpisać imię i wiek:
public Cat() throws IOException {
   BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
   this.name = reader.readLine();
   this.age = Integer.parseInt(reader.readLine());
}
Ponieważ funkcja reader.readLine() zgłasza wyjątek IOException, zapisujemy go w nagłówku jako możliwy zgłoszony wyjątek.

31. Jakie są elementy nagłówka klasy? Napisz przykład

Aby zilustrować elementy tworzące nagłówek klasy, spójrzmy na mały schemat:
  • elementy obowiązkowe znajdują się w nawiasach <>
  • elementy opcjonalne znajdują się w {}
{modyfikator dostępu} {static} {final} abstrakt <class name>{inheritance of Parent class}} implementacja interfejsów} A więc co mamy: { modyfikator dostępu} — dostępne są tylko publiczne i domyślne modyfikatory dostępu dla klasy klasa. {static} — modyfikator static wskazuje, że ta klasa jest statyczna; dotyczy to tylko klas wewnętrznych (klas znajdujących się wewnątrz innych klas). {final} — jest to oczywiście ostateczny modyfikator, który sprawia, że ​​klasy nie można dziedziczyć (gotowym przykładem jest String ). {abstract} — modyfikator abstrakcyjny , który wskazuje, że klasa może posiadać niezaimplementowane metody. Modyfikator ten koliduje z modyfikatorem końcowym . Nagłówek klasy może zawierać tylko jeden z nich, ponieważ modyfikator abstrakcyjny oznacza, że ​​klasa zostanie odziedziczona, a jej abstrakcyjne elementy zostaną zaimplementowane. Ale final wskazuje, że jest to ostateczna wersja klasy i że nie można jej dziedziczyć. Właściwie jednoczesne stosowanie obu modyfikatorów byłoby absurdem. Kompilator nam na to nie pozwoli. <class> to obowiązkowe słowo kluczowe wskazujące deklarację klasy. <nazwa klasy> to prosta nazwa klasy, która staje się identyfikatorem określonej klasy Java. W pełni kwalifikowana nazwa klasy składa się z kwalifikowanej nazwy pakietu oraz znaku „.” plus prosta nazwa klasy. {Dziedziczenie klasy nadrzędnej} jest wskazaniem klasy nadrzędnej (jeśli istnieje) za pomocą słowa kluczowego Extends . Na przykład ... rozszerza ParentClass . {implementacja interfejsów} — lista interfejsów, które ta klasa implementuje (jeśli istnieją), przy użyciu słowa kluczowego implements . Na przykład: ... implementuje FirstInterface, SecondInterface ... Jako przykład rozważmy nagłówek klasy klasy Lion , która dziedziczy Cat i implementuje interfejs WildAnimal :
public final class Lion extends Cat implements WildAnimal
Przeglądanie pytań i odpowiedzi z rozmowy kwalifikacyjnej na stanowisko programisty Java.  Część 4 - 3

32. Jakie są elementy nagłówka metody? Napisz przykład

Rozważając elementy tworzące nagłówek metody, rozważmy ponownie mały schemat:
  • elementy obowiązkowe znajdują się w nawiasach <>
  • elementy opcjonalne znajdują się w {}
{access modifier}{static}{abstract}{final}{synchronized} {native} <wartość zwracana><nazwa metody> <(>{parametry metody}>{throw wyjątki} {modyfikator dostępu} — wszystkie modyfikatory dostępu są dostępne dla metody — public , chroniony , domyślny , prywatny {static} — modyfikator static , który wskazuje, że metoda jest statyczna i dlatego jest powiązana z klasą, a nie obiektem {abstract} — modyfikator abstrakcyjny , który wskazuje, że metoda nie ma implementacji (treści). Aby działać poprawnie, klasa deklarująca metodę musi mieć również modyfikator abstrakcyjny . Podobnie jak w nagłówku klasy, modyfikator ten koliduje z modyfikatorem final , a także koliduje z modyfikatorem static , ponieważ metoda abstrakcyjna implikuje przesłonięcie metody w potomku, a metod statycznych nie można przesłonić. {finale}końcowy modyfikator, który wskazuje, że tej metody nie można przesłonić. {synchronized} — modyfikator zsynchronizowany , co oznacza, że ​​metoda jest zabezpieczona przed jednoczesny dostęp do niego z różnych wątków. Jeśli metoda nie jest statyczna, to jest zamknięta dla muteksu this obiektu. Jeżeli metoda jest statyczna, to zostaje zamknięta dla muteksu bieżącej klasy. {native} — modyfikator natywny wskazuje, że metoda jest napisana w innym języku programowania. <typ zwracany> — typ wartości, którą metoda musi zwrócić. Jeśli metoda nic nie zwróci, to void . <nazwa metody> — nazwa nazwy metody, czyli jej identyfikatora w systemie. {parametry metody} — parametry akceptowane przez metodę: są niezbędne do realizacji jej funkcjonalności. {thown wyjątki}zgłasza <ExceptionType> — listę sprawdzonych wyjątków, które ta metoda może zgłosić. Jako przykład nagłówka metody podam następujący przykład:
public static void main(String[] args) throws IOException

33. Utwórz domyślny konstruktor w klasie potomnej, jeśli nie jest on jeszcze zdefiniowany w klasie bazowej (ale zdefiniowany jest inny konstruktor)

Nie jestem pewien, czy w pełni rozumiem pytanie, ale może to oznaczać, że w klasie nadrzędnej mamy takiego konstruktora:
public Cat(int age, String name) {
   this.age = age;
   this.name = name;
}
W takim przypadku w klasie nadrzędnej zdecydowanie musimy zdefiniować konstruktor, który zainicjalizuje rodzica (tzn. wywoła konstruktor nadrzędny):
public class Lion extends Cat {

   public Lion(int age, String name) {
       super(age, name);
   }
}
Przeglądanie pytań i odpowiedzi z rozmowy kwalifikacyjnej na stanowisko programisty Java.  Część 4 - 4

34. Kiedy używane jest słowo kluczowe this?

W Javie ma to dwa różne znaczenia. 1. Jest to odniesienie do aktualnego obiektu, np. this.age = 9 . Oznacza to, że odnosi się to do obiektu, w którym jest używane i do którego odnosi się kod z tym . Głównym celem jest poprawa czytelności kodu i uniknięcie niejednoznaczności. Na przykład, jeśli pole instancji i argument metody mają tę samą nazwę:
public void setName(String name) {
   this.name = name;
}
Oznacza to, że this.name jest polem obiektu, a name jest parametrem metody. Odniesienia this nie można używać w metodach statycznych. 2. W konstruktorze można to wywołać jak metodę, np. this(value) . W tym przypadku będzie to wywołanie innego konstruktora tej samej klasy. Zasadniczo podczas tworzenia obiektu możesz wywołać dwa konstruktory:
public Cat(int age, String name) {
   this(name);
   this.age = age;
}

public Cat(String name) {
   this.name = name;
}
Podczas wywoływania pierwszego konstruktora w celu utworzenia obiektu Cat oba pola instancji zostaną pomyślnie zainicjowane. Jest tu kilka niuansów:
  1. this() działa tylko w konstruktorze.
  2. Odwołanie do innego konstruktora musi znajdować się w pierwszej linii bloku konstruktora (treści). Oznacza to, że konstruktor nie może wywołać więcej niż jednego (innego) konstruktora swojej klasy.
Przeglądanie pytań i odpowiedzi z rozmowy kwalifikacyjnej na stanowisko programisty Java.  Część 4 - 5

35. Co to jest inicjator?

O ile rozumiem, to pytanie dotyczy zwykłych i statycznych bloków inicjujących. Najpierw przypomnijmy sobie, czym jest inicjalizacja. Inicjalizacja to tworzenie, aktywacja, przygotowanie i definicja pól. Przygotowanie programu lub komponentu do użycia. Jak pamiętasz, kiedy tworzysz obiekt, zmienna klasy może zostać zainicjowana natychmiast po jej zadeklarowaniu:
class Cat {
   private int age = 9;
   private String name = "Tom";
Lub ustaw po fakcie za pomocą konstruktora:
class Cat {
   private int age;
   private String name;

   public Cat(int age, String name) {
       this.age = age;
       this.name = name;
   }
Ale jest inny sposób: możesz ustawić zmienną instancji za pomocą bloku inicjującego, który ma postać nawiasów klamrowych {} wewnątrz klasy, bez nazwy (jak bezimienna metoda lub konstruktor):
class Cat {
   private int age;
   private String name;

   {
       age = 10;
       name = "Tom";
   }
Blok inicjujący to fragment kodu ładowany podczas tworzenia obiektu. Takie bloki są zwykle używane do wykonywania pewnych złożonych obliczeń, które są wymagane podczas ładowania klasy. Wyniki tych obliczeń można ustawić jako wartości zmiennych. Oprócz zwykłych bloków inicjujących istnieją bloki statyczne. Wyglądają tak samo, ale mają słowo kluczowe static przed otwierającym nawiasem klamrowym:
class Cat {
   private static int age;
   private static String name;

   static{
       age = 10;
       name = "Tom";
   }
Ten blok jest taki sam jak poprzedni. Ale jeśli zwykły jest wykonywany podczas inicjowania każdego obiektu, to statyczny jest wykonywany tylko raz, kiedy klasa jest ładowana. Z reguły pewne złożone obliczenia wykonywane są w bloku statycznym, służącym do inicjalizacji zmiennych klasy statycznej. Te same ograniczenia dotyczą bloku statycznego, co metody statyczne: nie można używać danych niestatycznych, takich jak odwołanie do bieżącego obiektu ( this ) w bloku statycznym. Przeglądanie pytań i odpowiedzi z rozmowy kwalifikacyjnej na stanowisko programisty Java.  Część 4 - 6Teraz możemy przyjrzeć się kolejności inicjalizacji klasy (wraz z jej klasą nadrzędną), aby lepiej zrozumieć, kiedy dokładnie wywoływane są bloki inicjujące.

36. Mając publiczną klasę Child, która rozszerza Parent, zapisz kolejność inicjalizacji obiektu

Podczas ładowania klasy Child kolejność inicjalizacji będzie następująca:
  1. Pola klasy statycznej klasy Parent .
  2. Statyczny blok inicjujący klasy Parent .
  3. Pola statyczne klasy Сhild .
  4. Statyczny blok inicjujący klasy Child .
  5. Pola niestatyczne klasy Parent .
  6. Niestatyczny blok inicjujący klasy Parent .
  7. Konstruktor klasy nadrzędnej .
  8. Pola niestatyczne klasy Сhild .
  9. Niestatyczny blok inicjujący klasy Сhild .
  10. Konstruktor klasy Сhild .
Przeglądanie pytań i odpowiedzi z rozmowy kwalifikacyjnej na stanowisko programisty Java.  Część 4 - 7

37. Jakie znasz relacje pomiędzy klasami (obiektami)?

W Javie istnieją dwa rodzaje zmiennych: typy pierwotne i odniesienia do pełnoprawnych obiektów.
  • Relacje IS-A
Zasada IS-A OOP opiera się na dziedziczeniu klas lub implementacji interfejsów. Na przykład, jeśli klasa Lion dziedziczy Cat , wówczas mówimy, że Lion is a Cat :
Lion IS-A Cat
(ale nie każdy kot jest lwem ) Ta sama sytuacja ma miejsce w przypadku interfejsów. Jeśli klasa Lion implementuje interfejs WildAnimal , to one również istnieją w relacji:
Lion IS-A WildAnimal
  • Związek MA-A
Ten typ relacji ma miejsce, gdy jedna klasa korzysta z innych klas, co nazywa się także „powiązaniem”. Stowarzyszenie to jedna klasa, która odnosi się do innej klasy (lub wzajemne odniesienia do siebie). Na przykład klasa Car może odwoływać się do klasy Passenger , co tworzyłoby następującą relację:
Car HAS-A Passenger
I odwrotnie: jeśli Pasażer ma odniesienie do Car , to będzie to relacja:
Passenger HAS-A Car

38. Jakie znasz relacje z obiektami skojarzeniowymi?

Agregacja i kompozycja to nic innego jak szczególne przypadki asocjacji. Agregacja to relacja, w której jeden obiekt jest częścią drugiego. Na przykład pasażer może znajdować się w samochodzie. Co więcej, pasażerów może być wielu lub wcale (a jeśli mówimy o Tesli, może nie być kierowcy). Na przykład:
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();
   }
}
Innymi słowy, liczba pasażerów (w ogóle) nie jest dla nas istotna: funkcjonalność klasy Car nie jest od tego zależna. Agregacja oznacza również, że gdy inny obiekt korzysta z jednego obiektu, pierwszy obiekt może być używany przez inne obiekty. Na przykład ten sam uczeń może należeć zarówno do klubu dziewiarskiego, jak i do zespołu rockowego i jednocześnie uczęszczać na zajęcia z hiszpańskiego. Jak możesz sobie wyobrazić, agregacja to luźniejsza relacja asocjacyjna między klasami. Kompozycja to jeszcze ściślejszy związek, w którym obiekt nie jest tylko częścią innego obiektu, ale działanie jednego obiektu jest w dużym stopniu zależne od drugiego. Na przykład samochód ma silnik. Silnik może istnieć bez samochodu, ale poza samochodem jest bezużyteczny. A samochód nie może działać bez silnika:
public class Car {
   private Engine engine;

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

   void startMoving() {
       engine.start();
           ...
   }
Kompozycja oznacza również, że gdy inny przedmiot korzysta z obiektu, pierwszy obiekt nie może należeć do żadnego innego obiektu. Wracając do naszego przykładu, silnik może należeć tylko do jednego samochodu, a nie do dwóch lub więcej jednocześnie. Myślę, że na dzisiaj wystarczy, więc na tym poprzestaniemy.
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION