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

Opublikowano w grupie Random-PL
Witam ponownie wszystkich! Nieustannie poszukujemy odpowiedzi na pytania młodszych, średnich i starszych programistów Java. Pytania są niezwykle interesujące. Osobiście lubię je analizować, ponieważ pomaga mi to znaleźć luki w mojej wiedzy teoretycznej i to czasem w najbardziej nieoczekiwanych miejscach. Przeglądanie pytań i odpowiedzi z rozmowy kwalifikacyjnej na stanowisko programisty Java.  Część 2 - 1Poprzednią część znajdziesz w tym artykule . Ale zanim zaczniemy, chcę ci przypomnieć, że:
  1. Pominę pytania, które pokrywają się z tą serią artykułów, aby niepotrzebnie nie powielać informacji. Polecam przeczytać te artykuły, ponieważ omawiają najczęstsze (popularne) pytania podczas rozmów kwalifikacyjnych Java Core.
  2. Odpowiedzi mógłbym opisać bardziej szczegółowo, ale tego nie zrobię, bo wtedy każda odpowiedź mogłaby ciągnąć się przez cały artykuł. I nikt nie będzie Cię pytał o taki poziom szczegółów podczas żadnej rozmowy kwalifikacyjnej.
Jeśli chcesz, zostawię linki do głębszych badań. Lećmy!

11. Nazwij wszystkie metody klasy Object

Klasa Object posiada 11 metod:
  1. Class<?> getClass() — pobierz klasę bieżącego obiektu;

  2. int hashCode() — pobierz kod skrótu bieżącego obiektu;

  3. booleanquals(Object obj) — porównaj bieżący obiekt z innym obiektem;

  4. Object clone() — utwórz i zwróć kopię bieżącego obiektu;

  5. String toString() — pobierz ciąg znaków reprezentujący obiekt;

  6. void notify() — obudź jeden wątek oczekujący na monitorze tego obiektu (wybór wątku jest losowy);

  7. void notifyAll() — obudź wszystkie wątki oczekujące na monitorze tego obiektu;

  8. void Wait() — powoduje, że bieżący wątek czeka na bieżącym monitorze (zatrzymuje bieżący wątek) do czasu, aż wywołanie notify lub notifyAll obudzi wątek (działa tylko w bloku zsynchronizowanym);

  9. void wait(long timeout) — powoduje, że bieżący wątek czeka na bieżącym monitorze (w bieżącym zsynchronizowanym bloku), ale z określonym limitem czasu na wyjście ze stanu oczekiwania (lub ponownie, do czasu, aż wywołanie notify lub notifyAll obudzi wątek);

  10. void wait(long timeout, int nanos) — ta metoda działa podobnie jak poprzednia, ale ma bardziej precyzyjny limit czasu;

  11. void finalize() — ta metoda jest wywoływana (w końcu) zanim obiekt zostanie usunięty przez moduł zbierający elementy bezużyteczne. Służy do oczyszczania zdobytych zasobów.

Aby poprawnie używać metod hashCode , quals , clone , toString i finalize , należy je zastąpić zgodnie ze specyfiką bieżącego zadania.

12. Jaka jest różnica pomiędzy try-with-resources a try-catch-finally podczas pracy z zasobami?

Zwykle podczas korzystania z try - catch-finally ostatni blok służy do zamykania zasobów. W Java 7 wprowadzono nową instrukcję try-with-resources . Jest to analogiczne do try-catch-finale w celu uwolnienia zasobów, ale jest bardziej zwarte i czytelne. Przypomnijmy, jak wygląda try-catch-finale :

String text = "some text......";
BufferedWriter bufferedWriter = null;
try {
   bufferedWriter = new BufferedWriter(new FileWriter("someFileName"));
   bufferedWriter.write(text); 
} catch (IOException e) {
   e.printStackTrace();
} finally {
   try {
       bufferedWriter.close();
   } catch (IOException e) {
       e.printStackTrace();
   }
}
Przepiszmy teraz ten kod, ale używając try-with-resources :

String text = "some text......";
try(BufferedWriter bufferedWriter =new BufferedWriter(new FileWriter("someFileName"))) {
   bufferedWriter.write(text);
} catch (IOException e) {
   e.printStackTrace();
}
Teraz jest to w jakiś sposób prostsze, nie sądzisz? Oprócz prostszego kodu należy zwrócić uwagę na kilka innych kwestii:
  1. W try-with-resources zasoby zadeklarowane w nawiasach (zasoby, które zostaną zamknięte) muszą implementować interfejs AutoCloseable i jego jedyną metodę close() .

    Metoda zamykania jest wykonywana w ukrytym bloku final . W przeciwnym razie w jaki sposób program miałby dowiedzieć się, jak zamknąć zasób?

    Ale prawdopodobnie rzadko będziesz pisać własne implementacje zasobów i metodę ich zamykania.

  2. Bloki wykonywane są w następującej kolejności:

    1. Blok próbny .
    2. Ukryty blok wreszcie .
    3. Blok catch , który wychwytuje wyjątki występujące w poprzednich krokach.
    4. Wyraźny blok wreszcie .

    Z reguły wyjątki zgłoszone niżej na liście przerywają wyjątki zgłoszone wyżej.

Wyobraź sobie, że używasz try-catch-finale i otrzymujesz wyjątek w bloku try . Następnie natychmiast rozpoczyna się wykonywanie określonego bloku catch , w którym napisaliśmy kolejny wyjątek (na przykład z komunikatem bardziej szczegółowo opisującym błąd) i chcesz, aby metoda rzuciła ten wyjątek w górę. Następnie wykonywany jest blok Final i zgłaszany jest w nim również wyjątek. Ale tym razem inny. Który z tych dwóch wyjątków ostatecznie wyrzuci ta metoda? Wyjątek zgłoszony przez blok last ! Ale teraz doszliśmy do innego punktu dotyczącego próbowania z zasobami . Zastanówmy się, jak zachowuje się funkcja try-with-resources w tej samej sytuacji. Przy próbie zamknięcia zasobów metodą close() , czyli w ukrytym bloku Final , pojawia się wyjątek w bloku try. Który z tych wyjątków zostanie przechwycony przez blok catch ? Ten wyrzucony przez blok try ! Wyjątek od ukrytego bloku wreszcie (z metody los() ) zostanie zignorowany. To ignorowanie wyjątków nazywa się także tłumieniem wyjątków.

13. Czym są operacje bitowe?

Operacje bitowe to operacje na ciągach bitów. Obejmują one operacje logiczne i przesunięcia bitowe. Operatory logiczne:
  • bitowe AND — Porównuje wartości bitowe. Dowolny bit ustawiony na 0 (fałsz) ustawia odpowiedni bit w wyniku na 0. Oznacza to, że jeśli bit ma wartość 1 (prawda) w obu porównywanych wartościach, wówczas bit wynikowy również będzie miał wartość 1.

    Oznaczone jako AND lub &

    Przykład: 10111101 i 01100111 = 00100101

  • bitowe LUB — Ta operacja jest przeciwieństwem poprzedniej. Dowolny bit ustawiony na 1 ustawia odpowiedni bit wyniku na 1. Odpowiednio, jeśli bit ma wartość 0 w obu porównywanych wartościach, wówczas wynikowy bit również będzie miał wartość 0.

    Oznaczone jako OR lub |

    Przykład: 10100101 | 01100011 = 11100111

  • bitowe NOT — Ten operator jest stosowany do pojedynczej wartości. Odwraca (odwraca) bity. Oznacza to, że bity, które miały wartość 1, stają się 0; a te, które były 0, stają się 1.

    Oznaczone jako NOT lub ~

    Przykład: ~10100101 = 01011010

  • bitowe wyłączne OR — Porównuje wartości bitowe. Jeśli oba bity mają wartość 1, wynikowy bit ma wartość 0. Jeśli oba bity mają wartość 0, wówczas wynikowy bit ma wartość 0. Innymi słowy, aby wynikowy bit miał wartość 1, tylko jeden z bitów musi mieć wartość 1, a drugi bit musi wynosić 0.

    Oznaczone jako XOR lub ^

    Przykład: 10100101 ^ 01100011 = 11000110

Przesunięcia bitowe ( >> i << ) przesuwają bity operandu w określonym kierunku o określoną liczbę miejsc. Zwolnione pozycje są wypełniane zerami. Na przykład:
  1. 01100011 >> 4 = 00000110
  2. 01100011 << 3 = 00011000
Wyjątkiem jest przesunięcie liczby ujemnej w prawo. Jak pamiętasz, pierwszy bit liczby ze znakiem wskazuje znak. Jeśli ten bit ma wartość 1, liczba jest ujemna. Jeśli przesuniesz liczbę ujemną, zwolnione pozycje nie zostaną wypełnione zerami, ale raczej jedynkami, ponieważ bit znaku musi zostać zachowany. Na przykład: 10100010 >> 2 = 11101000 To powiedziawszy, Java ma dodatkowy operator przesunięcia w prawo bez znaku (>>>). Operator ten jest analogiczny do >>, ale po przesunięciu zwolnione pozycje są wypełniane wartością 0, niezależnie od tego, czy operand jest liczbą ujemną, czy dodatnią. Na przykład: 10100010 >>> 2 = 00101000 Przeczytaj więcej o operacjach bitowych tutaj . Przeglądanie pytań i odpowiedzi z rozmowy kwalifikacyjnej na stanowisko programisty Java.  Część 2 - 2Możesz wziąć metodę hash() w HashMaps jako przykład przesunięć bitowych w Javie. Ta metoda służy do określenia specjalnego wewnętrznego kodu skrótu klucza: Przeglądanie pytań i odpowiedzi z rozmowy kwalifikacyjnej na stanowisko programisty Java.  Część 2 - 3Ta metoda umożliwia równomierne rozmieszczenie danych w HashMap, aby zminimalizować liczbę kolizji.

14. Jakie standardowe obiekty niezmienne znajdują się w Javie?

Obiekt jest niezmienny , jeśli nie pozwala na zmianę jego oryginalnych wartości. Może mieć metody zwracające nowe obiekty tego samego typu o różnych wartościach. Niektóre standardowe obiekty niezmienne obejmują:
  • niewątpliwie najsłynniejszym niezmiennym typem Javy jest String;
  • instancje klas opakowań, które otaczają typy standardowe: Boolean, Character, Byte, Short, Integer, Long, Double, Float;
  • Obiekty BigInteger i BigDecimal, które są zwykle używane w przypadku szczególnie DUŻYCH liczb;
  • StackTraceElement obiekty tworzące ślad stosu (na przykład ślad stosu wyjątku);
  • obiekt klasy File — może modyfikować pliki, ale jednocześnie sam obiekt pozostaje niezmieniony;
  • identyfikatory UUID, które są często używane do jednoznacznej identyfikacji elementów;
  • wszystkie obiekty klas w pakiecie java.time;
  • Obiekty regionalne, które służą do identyfikacji regionu geograficznego, politycznego lub kulturowego.

15. Jaka jest przewaga obiektu niezmiennego nad zwykłymi obiektami?

  1. Niezmiennych obiektów można bezpiecznie używać w środowisku wielowątkowym . Sprawiają, że nie musisz się martwić utratą danych z powodu warunków wyścigowych. Inaczej jest w przypadku pracy ze zwykłymi obiektami. W takim przypadku trzeba pomyśleć i wymyślić dobre mechanizmy podczas używania obiektu w środowisku równoległym.

  2. Niezmienne obiekty są dobre jako klucze na mapie. Jeśli użyjesz modyfikowalnego obiektu jako klucza HashMap, a następnie stan obiektu się zmieni, struktura danych może zostać pomieszana: obiekt będzie nadal obecny, ale jeśli użyjesz funkcji includeKey(), możesz go nie znaleźć.

  3. Obiekty niezmienne doskonale nadają się do przechowywania niezmiennych (stałych) danych, których nigdy nie należy zmieniać podczas działania programu.

  4. Kolejną zaletą jest atomowość awarii. Jeśli niezmienny obiekt zgłosi wyjątek, nie pozostanie w niepożądanym (zepsutym) stanie.

  5. Klasy te są łatwe do przetestowania.

  6. Nie potrzebujesz żadnych dodatkowych mechanizmów, takich jak konstruktor kopiujący lub implementacja klonowania obiektów.

Pytania dotyczące OOP

16. Jakie są zalety OOP w ogóle i w porównaniu z programowaniem proceduralnym?

OK, zalety OOP:
  1. Złożone aplikacje są łatwiejsze do napisania przy użyciu OOP niż programowania proceduralnego, ponieważ wszystko jest podzielone na małe moduły — obiekty, które wchodzą ze sobą w interakcję — w wyniku czego programowanie ogranicza się do relacji między obiektami.

  2. Aplikacje napisane przy użyciu OOP są znacznie łatwiejsze do modyfikacji (przy odpowiednim przestrzeganiu zasad projektowania).

  3. Ponieważ zarówno dane, jak i operacje na danych tworzą jedną całość, nie są rozmazane po całej aplikacji (co często ma miejsce w programowaniu proceduralnym).

  4. Zasada enkapsulacji chroni najważniejsze dane przed użytkownikiem.

  5. Ten sam kod można ponownie wykorzystać z różnymi danymi, ponieważ klasy umożliwiają tworzenie wielu obiektów, każdy z własnymi wartościami.

  6. Dziedziczenie i polimorfizm umożliwiają także ponowne wykorzystanie i rozszerzenie istniejącego kodu (zamiast powielania podobnej funkcjonalności).

  7. Rozszerzenie wniosku jest prostsze niż w przypadku podejścia proceduralnego.

  8. Podejście OOP umożliwia wyodrębnienie szczegółów implementacji.

17. Powiedz nam, jakie wady ma OOP

Niestety, istnieją również:
  1. OOP wymaga dużej wiedzy teoretycznej, którą należy opanować, zanim będzie można cokolwiek napisać.

  2. Idee OOP nie są tak łatwe do zrozumienia i zastosowania w praktyce (trzeba mieć w głębi serca trochę filozofa).

  3. OOP nieznacznie zmniejsza wydajność programu ze względu na zwiększoną złożoność systemu.

  4. Podejście OOP wymaga więcej pamięci, ponieważ wszystko składa się z klas, interfejsów, metod, które zajmują znacznie więcej pamięci niż zwykłe zmienne.

  5. Czas potrzebny na wstępną analizę jest dłuższy niż w przypadku podejścia proceduralnego.

18. Czym jest polimorfizm statyczny a polimorfizm dynamiczny?

Polimorfizm pozwala obiektom tej samej klasy lub interfejsu zachowywać się inaczej. Istnieją dwa typy polimorfizmu, znane również jako wczesne i późne wiązanie. Polimorfizm statyczny lub wczesne wiązanie:
  • występuje w czasie kompilacji (na początku cyklu życia programu);
  • decyduje, którą metodę wykonać w czasie kompilacji;
  • przeciążanie metod jest przykładem polimorfizmu statycznego;
  • wczesne wiązanie obejmuje metody prywatne, statyczne i końcowe;
  • dziedziczenie nie jest związane z wczesnym wiązaniem;
  • polimorfizm statyczny nie dotyczy konkretnych obiektów, ale raczej informację o typie klasy, która pojawia się po lewej stronie nazwy zmiennej.
Dynamiczny polimorfizm lub późne wiązanie:
  • występuje w czasie wykonywania (kiedy program jest uruchomiony);
  • dynamiczny polimorfizm decyduje, jaką konkretną implementację będzie miała metoda w czasie wykonywania;
  • nadpisywanie metod jest przykładem polimorfizmu dynamicznego;
  • późne wiązanie oznacza przypisanie konkretnego obiektu, odniesienia do jego typu lub jego nadklasy;
  • dziedziczenie jest związane z dynamicznym polimorfizmem.

19. Podaj definicję zasady abstrakcji w OOP

W OOP abstrakcja jest sposobem na wyizolowanie zestawu znaczących cech obiektu, przy jednoczesnym wykluczeniu nieistotnych szczegółów. Oznacza to, że projektując program z podejściem OOP, skupiasz się na ogólnych modelach, bez wchodzenia w szczegóły ich realizacji. W Javie abstrakcja jest realizowana poprzez interfejsy . Na przykład masz samochód i to będzie interfejs. A różne interakcje z nim – na przykład uruchomienie silnika, zmiana biegów – to funkcje, z których korzystamy bez wnikania w szczegóły implementacji. Rzeczywiście, kiedy prowadzisz, nie zastanawiasz się, jak dokładnie skrzynia biegów spełnia swoje zadanie, jak kluczykiem uruchamia silnik, ani jak dokładnie kierownica obraca koła. A jeśli wymienisz implementację jakiejś funkcjonalności (na przykład silnika), możesz nawet tego nie zauważyć. Dla Ciebie to nie ma znaczenia: nie zagłębiasz się w szczegóły implementacji. Dla Ciebie liczy się to, że akcja została wykonana. W istocie jest to abstrakcja szczegółów implementacji. W tym miejscu dzisiaj zatrzymamy się: ciąg dalszy!
Komentarze
  • Popularne
  • Najnowsze
  • Najstarsze
Musisz się zalogować, aby dodać komentarz
Ta strona nie ma jeszcze żadnych komentarzy