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ęść 11

Opublikowano w grupie Random-PL
Cześć! Nawet najszybszy statek będzie po prostu dryfował po falach, jeśli nie będzie miał kursu. Jeśli czytasz teraz ten artykuł, na pewno masz cel. Najważniejsze, żeby nie zejść z kursu i zamiast tego dać z siebie wszystko, aby zostać programistą Java. Dzisiaj chcę kontynuować przegląd pytań do programistów Java, aby pomóc wypełnić niektóre luki w teorii. Przeglądanie pytań i odpowiedzi z rozmowy kwalifikacyjnej na stanowisko programisty Java.  Część 11 - 1

97. Czy przy zastępowaniu funkcji równości() obowiązują jakieś zasady?

Nadpisując metodę równości() należy przestrzegać następujących zasad:
  • zwrotność — dla dowolnej wartości x funkcja x.equals(x) musi zawsze zwracać wartość true (gdzie x != null ).

  • symetria — dla dowolnych wartości x i y x.equals(y) musi zwracać wartość true tylko wtedy, gdy y.equals(x) zwraca wartość true .

  • przechodniość — dla dowolnych wartości x , y i z , jeśli x.equals(y) zwraca wartość true i y.equals(z) również zwraca wartość true , to x.equals(z) musi zwracać wartość true .

  • spójność — dla dowolnych wartości x i y wielokrotne wywołanie x.equals(y) zawsze zwróci tę samą wartość, o ile pola używane do porównania dwóch obiektów nie uległy zmianie pomiędzy każdym wywołaniem.

  • porównanie null — dla dowolnej wartości x wywołanie x.equals(null) musi zwrócić false .

98. Co się stanie, jeśli nie zastąpisz funkcji równości() i hashCode()?

W tym przypadku hashCode() zwróci liczbę wygenerowaną na podstawie adresu komórki pamięci, w której przechowywany jest obiekt. Innymi słowy, gdy oryginalna metoda hashCode() zostanie wywołana na dwóch obiektach z dokładnie tymi samymi polami, wynik będzie inny (ponieważ są one przechowywane w różnych lokalizacjach pamięci). Oryginalna metoda równa() porównuje referencje, czyli wskazuje, czy referencje wskazują na ten sam obiekt. Innymi słowy, porównanie wykorzystuje operator == i zawsze zwraca wartość false dla różnych obiektów, nawet jeśli ich pola są identyczne. true jest zwracane tylko podczas porównywania odniesień do tego samego obiektu. Czasami nie ma sensu zastępować tych metod. Na przykład chcesz, aby wszystkie obiekty określonej klasy były unikalne — zastąpienie tych metod może tylko zepsuć istniejącą gwarancję unikalnych kodów skrótu. Ważną rzeczą jest zrozumienie niuansów tych metod, niezależnie od tego, czy zostaną one zastąpione czy nie, i zastosowanie dowolnego podejścia, jakiego wymaga sytuacja.

99. Dlaczego wymóg symetrii jest spełniony tylko wtedy, gdy x.equals(y) zwraca wartość true?

To pytanie jest trochę dziwne. Jeśli obiekt A jest równy obiektowi B, to obiekt B jest równy obiektowi A. Jeśli B nie jest równy obiektowi A, to jak mogłoby być możliwe odwrotne zjawisko? To jest zdrowy rozsądek.

100. Co to jest kolizja HashCode? Jak sobie z tym radzisz?

Kolizja HashCode ma miejsce , gdy dwa różne obiekty mają ten sam HashCode . Jak to możliwe? Cóż, kod skrótu jest mapowany na liczbę całkowitą, która ma zakres od -2147483648 do 2147483647. Oznacza to, że może to być jedna z około 4 miliardów różnych liczb całkowitych. Zakres ten jest ogromny, ale nie nieskończony. Oznacza to, że zdarzają się sytuacje, w których dwa zupełnie różne obiekty mogą mieć ten sam kod skrótu. Jest to mało prawdopodobne, ale możliwe. Źle zaimplementowana funkcja skrótu może sprawić, że identyczne kody skrótu będą częstsze, zwracając liczby z małego zakresu, zwiększając w ten sposób ryzyko kolizji. Aby ograniczyć kolizje, konieczna jest dobra implementacja metody HashCode , która równomiernie rozkłada wartości i minimalizuje ryzyko ich powtórzenia.

101. Co się stanie jeśli zmieni się wartość elementu uczestniczącego w kontrakcie hashCode?

Jeśli zmieni się element biorący udział w obliczaniu kodu skrótu, wówczas kod skrótu obiektu powinien się zmienić (jeśli funkcja skrótu jest dobra). Dlatego powinieneś używać niezmiennych obiektów jako kluczy w HashMap , ponieważ ich stanu wewnętrznego (pól) nie można zmienić po utworzeniu. Wynika z tego, że ich kod skrótu zmienia się po utworzeniu. Jeśli użyjesz modyfikowalnego obiektu jako klucza, to gdy pola obiektu ulegną zmianie, jego kod skrótu ulegnie zmianie i możesz utracić odpowiednią parę klucz-wartość w HashMap . Przecież będzie on przechowywany w zasobniku powiązanym z oryginalnym kodem skrótu, ale po zmianie obiektu będziesz go szukać w innym zasobniku.

102. Napisz metody równości() i hashCode() dla klasy Student, która ma pola String name i int age.

public class Student {
int age;
String name;

 @Override
 public boolean equals(final Object o) {
   if (this == o) {
     return true;
   }
   if (o == null || this.getClass() != o.getClass()) {
     return false;
   }

   final Student student = (Student) o;

   if (this.age != student.age) {
     return false;
   }
   return this.name != null ? this.name.equals(student.name) : student.name == null;
 }

 @Override
 public int hashCode() {
   int result = this.age;
   result = 31 * result + (this.name != null ? this.name.hashCode() : 0);
   return result;
 }
}
równa się():
  • Najpierw porównujemy odniesienia bezpośrednio, ponieważ jeśli odniesienia wskazują na ten sam obiekt, jaki jest sens dalszego sprawdzania równości? Wiemy już, że wynik będzie prawdziwy .

  • Sprawdzamy, czy nie ma wartości null i czy typy klas są takie same, ponieważ jeśli parametr ma wartość null lub jest innego typu, wówczas obiekty nie mogą być równe, a wynik musi być fałszywy .

  • Rzutujemy parametr na ten sam typ (w końcu co, jeśli jest to obiekt typu nadrzędnego).

  • Porównujemy pola pierwotne ( wystarczy porównanie za pomocą =! ). Jeśli nie są równe, zwracamy false .

  • Sprawdzamy, czy pole nieprymitywne ma wartość null i stosujemy metodę równości ( klasa String nadpisuje metodę, dzięki czemu porównanie zostanie wykonane poprawnie). Jeśli oba pola mają wartość null lub równa się zwraca wartość true , przestajemy sprawdzać, a metoda zwraca wartość true .

hashCode() :
  • Ustawiamy wartość początkową kodu skrótu równą wartości pola wieku obiektu .

  • Mnożymy bieżący kod skrótu przez 31 (w celu uzyskania większego rozrzutu wartości), a następnie dodajemy kod skrótu nieprymitywnego pola String (jeśli nie ma wartości null).

  • Zwracamy wynik.

  • Zastąpienie metody w ten sposób oznacza, że ​​obiekty o tej samej nazwie i wartościach int zawsze będą zwracać ten sam kod skrótu.

103. Jaka jest różnica między użyciem „if (obj instancja Studenta)” i „if (getClass() == obj.getClass())”?

Przyjrzyjmy się, co robi każde wyrażenie:
  • instancja sprawdza, czy odwołanie do obiektu po lewej stronie jest instancją typu po prawej stronie, czy jednym z jego podtypów.

  • „getClass() == …” sprawdza, czy typy są takie same.

Innymi słowy, getClass() zwraca konkretną tożsamość klasy, ale instancja zwraca wartość true , nawet jeśli obiekt jest tylko podtypem, co może zapewnić nam większą elastyczność podczas stosowania polimorfizmu. Obydwa podejścia są obiecujące, jeśli dokładnie zrozumiesz, jak działają i zastosujesz je we właściwych miejscach.

104. Podaj krótki opis metody clone().

Metoda clone() należy do klasy Object . Jego celem jest utworzenie i zwrócenie klonu (kopii) bieżącego obiektu. Przeglądanie pytań i odpowiedzi z rozmowy kwalifikacyjnej na stanowisko programisty Java.  Część 11 - 2Aby skorzystać z tej metody, musisz zaimplementować interfejs znacznika Cloneable :
Student implements Cloneable
I zastąp samą metodę clone() :
@Override
protected Object clone() throws CloneNotSupportedException {
 return super.clone();
}
Przecież jest on chroniony w klasie Object , czyli będzie widoczny tylko w klasie Student i nie będzie widoczny dla klas zewnętrznych.

105. O jakich specjalnych uwagach należy pamiętać w związku z metodą clone() i zmiennymi referencyjnymi w obiekcie?

Podczas klonowania obiektów kopiowane są tylko wartości pierwotne i wartości odniesień do obiektów. Oznacza to, że jeśli obiekt posiada pole odwołujące się do innego obiektu, to sklonowane zostanie tylko odniesienie – ten inny obiekt, do którego istnieje odniesienie, nie zostanie sklonowany. Nazywa się to płytką kopią. A co, jeśli potrzebujesz pełnoprawnej kopii, w której klonowany jest każdy zagnieżdżony obiekt? Jak upewnić się, że nie są to zwykłe kopie odniesień, ale pełnoprawne kopie odrębnych obiektów zajmujących różne adresy pamięci na stercie? Właściwie wszystko jest całkiem proste — dla każdej klasy, do której odwołuje się wewnętrznie, musisz zastąpić metodę clone() i dodać interfejs znacznika Cloneable . Gdy to zrobisz, operacja klonowania nie skopiuje odniesień do istniejących obiektów, ale zamiast tego skopiuje obiekty, do których się odwołują, ponieważ teraz mają one również możliwość kopiowania samych siebie.

Wyjątki

106. Jaka jest różnica między błędem a wyjątkiem?

Wyjątki, podobnie jak błędy, są podklasami Throwable . Mają jednak swoje różnice. Błąd wskazuje na problem, który występuje głównie z powodu braku zasobów systemowych. A nasza aplikacja nie powinna widzieć tego typu problemów. Przykładami tych błędów są awarie systemu i błąd braku pamięci. Błędy pojawiają się najczęściej w czasie wykonywania, ponieważ nie są sprawdzane. Przeglądanie pytań i odpowiedzi z rozmowy kwalifikacyjnej na stanowisko programisty Java.  Część 11 - 3Wyjątki to problemy, które mogą wystąpić w czasie wykonywania i kompilacji. Problemy te zwykle pojawiają się w kodzie, który piszemy jako programiści. Oznacza to, że te wyjątki są bardziej przewidywalne i bardziej zależne od nas. Natomiast błędy są bardziej przypadkowe i bardziej niezależne od nas. Zamiast tego zależą one od problemów w systemie, na którym działa nasza aplikacja.

107. Jaka jest różnica między zaznaczonym, niesprawdzonym, wyjątkiem, rzutem i rzutem?

Jak powiedziałem wcześniej, wyjątkiem jest błąd w czasie wykonywania lub kompilacji, który pojawia się w kodzie napisanym przez programistę (z powodu jakiejś nietypowej sytuacji). Sprawdzane jest to, co nazywamy wyjątkami, które metoda musi zawsze obsługiwać przy użyciu mechanizmu try-catch lub ponownego zgłoszenia do metody wywołującej. Słowo kluczowe rzuca jest używane w nagłówku metody w celu wskazania wyjątków, które metoda może zgłosić. Innymi słowy, zapewnia nam mechanizm zgłaszania wyjątków do metody wywołującej. Niesprawdzone wyjątki nie muszą być obsługiwane. Są one mniej przewidywalne i mniej prawdopodobne. To powiedziawszy, możesz sobie z nimi poradzić, jeśli chcesz. Rzutu używamy podczas ręcznego zgłaszania wyjątku, na przykład:
throw new Exception();

108. Jaka jest hierarchia wyjątków?

Hierarchia wyjątków jest bardzo obszerna. Jest tu zbyt wiele, żeby to odpowiednio opisać. Zamiast tego rozważymy tylko jej kluczowe gałęzie: Przeglądanie pytań i odpowiedzi z rozmowy kwalifikacyjnej na stanowisko programisty Java.  Część 11 - 4 tutaj, na samym szczycie hierarchii, widzimy klasę Throwable , która jest ogólnym przodkiem hierarchii wyjątków i z kolei dzieli się na:
  • Błędy — krytyczne, niesprawdzone problemy.
  • Wyjątki — wyjątki, które można sprawdzić.
Wyjątki dzielą się na różne niesprawdzone wyjątki środowiska wykonawczego i różne sprawdzone wyjątki.

109. Czym są wyjątki zaznaczone i niesprawdzone?

Jak już mówiłem:
  • Sprawdzone wyjątki to wyjątki, z którymi musisz sobie jakoś poradzić. Oznacza to, że musisz albo obsłużyć je w bloku try-catch , albo rzucić je do powyższej metody. Aby to zrobić, po wymienieniu argumentów metody w sygnaturze metody, użyj rzutów <typ wyjątku>, aby wskazać, że metoda może zgłosić ten wyjątek. Przypomina to trochę ostrzeżenie, informujące metodę wywołującą, że musi ona wziąć na siebie odpowiedzialność za obsługę tego wyjątku.

  • Niesprawdzone wyjątki nie muszą być obsługiwane, ponieważ nie są sprawdzane w czasie kompilacji i zwykle są bardziej nieprzewidywalne. Ich główna różnica w stosunku do sprawdzonych wyjątków polega na tym, że obsługa ich za pomocą bloku try-catch lub ponownego rzutu jest opcjonalna, a nie obowiązkowa.

101. Napisz przykład użycia bloku try-catch do przechwycenia i obsługi wyjątku.

try{                                                 // Start of the try-catch block
 throw new Exception();                             // Manually throw an exception
} catch (Exception e) {                              // Exceptions of this type and its subtypes will be caught
 System.out.println("Oops! Something went wrong =("); // Display the exception
}

102. Napisz przykład, w którym przechwytujesz i obsługujesz własne niestandardowe wyjątki.

Najpierw napiszmy własną klasę wyjątków, która dziedziczy wyjątek i zastąpmy jej konstruktora, który jako argument przyjmuje komunikat o błędzie:
public class CustomException extends Exception {

 public CustomException(final String message) {
   super(message);
 }
}
Następnie ręcznie rzucimy jeden i złapiemy go, tak jak to zrobiliśmy w przykładzie z poprzednim pytaniem:
try{
 throw new CustomException("Oops! Something went wrong =(");
} catch (CustomException e) {
 System.out.println(e.getMessage());
}
Po raz kolejny, gdy uruchomimy nasz kod, otrzymamy następujące dane wyjściowe:
Ups! Coś poszło nie tak =(
Przeglądanie pytań i odpowiedzi z rozmowy kwalifikacyjnej na stanowisko programisty Java.  Część 11 - 5Cóż, to wszystko na dzisiaj! Do zobaczenia w kolejnej części!
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION