JavaRush /Blog Java /Random-PL /Rdzeń Javy. Pytania do rozmowy kwalifikacyjnej, część 3
Vadim625
Poziom 27

Rdzeń Javy. Pytania do rozmowy kwalifikacyjnej, część 3

Opublikowano w grupie Random-PL
W poprzednich dwóch artykułach omówiliśmy kilka ważnych pytań, które najczęściej zadawane są na rozmowach kwalifikacyjnych. Czas przejść dalej i przyjrzeć się pozostałym pytaniom.
Rdzeń Javy.  Pytania do rozmowy kwalifikacyjnej, część 3 - 1

Głębokie kopiowanie i płytkie kopiowanie

Dokładną kopią oryginału jest jego klon. W Javie oznacza to możliwość stworzenia obiektu o strukturze podobnej do obiektu oryginalnego. Metoda clone()zapewnia taką funkcjonalność. Płytkie kopiowanie powoduje utworzenie jak najmniejszej ilości informacji. Domyślnie klonowanie w Javie jest płytkie, tj. Object classnie wie o strukturze klasy, którą kopiuje. Podczas klonowania maszyna JVM wykonuje następujące czynności:
  1. Jeśli klasa zawiera tylko elementy typów pierwotnych, zostanie utworzona całkowicie nowa kopia obiektu i zwrócone zostanie odwołanie do tego obiektu.
  2. Jeśli klasa zawiera nie tylko elementy typów pierwotnych, ale także dowolny inny typ klasy, wówczas kopiowane są odniesienia do obiektów tych klas. Dlatego oba obiekty będą miały te same odniesienia.
Głębokie kopiowanie duplikuje wszystko. Głębokie kopiowanie to dwie kolekcje, z których jedna powiela wszystkie elementy oryginalnej kolekcji. Zależy nam na wykonaniu kopii w taki sposób, aby dokonanie zmian w jakimkolwiek elemencie kopii nie miało wpływu na oryginalną kolekcję. Głębokie klonowanie wymaga następujących zasad:
  1. Nie ma potrzeby osobnego kopiowania prymitywnych danych;
  2. Wszystkie klasy członkowskie w klasie oryginalnej muszą obsługiwać klonowanie. Dla każdego członka klasy musi zostać wywołana, super.clone()gdy metoda zostanie zastąpiona clone();
  3. Jeśli któryś element klasy nie obsługuje klonowania, to w metodzie clone należy utworzyć nową instancję tej klasy i po jednym na raz skopiować każdego jej członka ze wszystkimi atrybutami do nowego obiektu klasy.
Więcej informacji na temat klonowania znajdziesz tutaj

Co to jest synchronizacja? Blokowanie na poziomie obiektu i blokowanie na poziomie klasy?

Synchronizacja odnosi się do wielowątkowości. Zsynchronizowany blok kodu może być wykonywany tylko przez jeden wątek na raz. Java umożliwia jednoczesne przetwarzanie wielu wątków. Może to spowodować, że dwa lub więcej wątków będzie chciało uzyskać dostęp do tego samego pola. Synchronizacja pomaga uniknąć błędów pamięci występujących w przypadku nieprawidłowego użycia zasobów pamięci. Kiedy metoda jest zadeklarowana jako zsynchronizowana, wątek wstrzymuje swój monitor. Jeśli w tym momencie inny wątek spróbuje uzyskać dostęp do metody zsynchronizowanej, wątek zostanie zablokowany i czeka, aż monitor się zwolni. Synchronizacja w Javie odbywa się za pomocą specjalnego słowa kluczowego synchronized . Możesz w ten sposób oznaczać poszczególne bloki lub metody w swojej klasie. Słowo kluczowe synchronized nie może być używane w połączeniu ze zmiennymi lub atrybutami klas. Blokowanie na poziomie obiektu to mechanizm, który pozwala zsynchronizować niestatyczną metodę lub niestatyczny blok kodu, tak aby tylko jeden wątek mógł wykonać blok kodu w danej instancji klasy. Należy to zawsze robić, aby wątek instancji klasy był bezpieczny. Blokowanie na poziomie klasy uniemożliwia wielu wątkom wejście do zsynchronizowanego bloku dla wszystkich dostępnych instancji klasy. Na przykład, jeśli istnieje 100 instancji klasy DemoClass, to tylko 1 wątek będzie mógł w danym momencie wykonać demoMethod() przy użyciu jednej ze zmiennych. Należy to zawsze robić, aby zapewnić bezpieczeństwo statyczne wątku. Dowiedz się więcej o synchronizacji tutaj.

Jaka jest różnica między funkcjami Sleep() i Wait()?

Sleep()to metoda stosowana do opóźnienia procesu o kilka sekund. W przypadku wait()wątek znajduje się w stanie oczekiwania do momentu wywołania metody notify()or notifyAll(). Główna różnica polega na tym, że wait()zwalnia blokadę monitora, podczas gdy sleep()nie zwalnia blokady. Wait()używany w aplikacjach wielowątkowych, sleep()używany po prostu do wstrzymywania wykonywania wątku. Thread.sleep()ustawia bieżący wątek w stan „Nie można uruchomić” na określony czas. Wątek zapisuje stan monitora, jaki był przed wywołaniem tej metody. Jeśli inny wątek wywoła t.interrupt(), wątek, który „zasnął” się obudzi. Należy pamiętać, że sleep()jest to metoda statyczna, co oznacza, że ​​zawsze wpływa na bieżący wątek (ten, który wykonuje metodę sleep()). Częstym błędem jest wywoływanie t.sleep()gdzie tjest inny wątek; nawet jeśli bieżący wątek wywołujący metodę sleep()nie jest twątkiem. Object.wait()wysyła bieżący wątek do stanu „Nie można uruchomić” na chwilę, podobnie jak sleep(), ale z pewnymi niuansami. Wait()wywołany obiekt, a nie wątek; nazywamy ten obiekt „obiektem blokującym”. Przed wywołaniem lock.wait()bieżący wątek musi zostać zsynchronizowany z „obiektem blokady”; wait()następnie zwalnia tę blokadę i dodaje wątek do „listy oczekujących” powiązanej z tą blokadą. Później inny wątek może zsynchronizować się z tym samym obiektem blokady i wywołać metodę lock.notify(). Ta metoda „obudzi” oryginalny wątek, który wciąż czeka. W zasadzie wait()/ notify()można porównać do sleep()/ interrupt(), tylko aktywny wątek nie potrzebuje bezpośredniego wskaźnika do uśpionego wątku, wystarczy znać obiekt blokady współdzielonej. Przeczytaj szczegółową różnicę tutaj.

Czy można przypisać wartość null do zmiennej referencyjnej?

Nie, nie możesz. W Javie lewa strona operatora przypisania musi być zmienną. „This” to specjalne słowo kluczowe, które zawsze podaje bieżącą instancję klasy. To nie jest byle jaka zmienna. Podobnie wartości null nie można przypisać do zmiennej za pomocą słowa kluczowego „super” ani żadnego innego podobnego słowa kluczowego.

Jaka jest różnica między && i &?

&- bitowo i &&- logicznie.
  1. &ocenia obie strony operacji;
  2. &&ocenia lewą stronę operacji. Jeśli to prawda, nadal ocenia prawą stronę.
Spójrz tutaj, aby uzyskać głębsze zrozumienie.

Jak zastąpić metody równości() i hachCode()?

hashCode()i equals()metody są zdefiniowane w klasie Object, która jest klasą nadrzędną dla obiektów Java. Z tego powodu wszystkie obiekty Java dziedziczą domyślną implementację metod. Metoda hashCode()służy do uzyskania unikalnej liczby całkowitej dla danego obiektu. Ta liczba całkowita służy do określenia lokalizacji obiektu, kiedy obiekt ten musi być przechowywany, na przykład HashTable. Domyślnie hashCode()zwraca integerreprezentację adresu lokalizacji pamięci, w której przechowywany jest obiekt. Metoda equls(), jak sama nazwa wskazuje, służy po prostu do sprawdzenia, czy dwa obiekty są równe. Domyślna implementacja sprawdza odniesienia do obiektów, aby sprawdzić, czy są równe. Poniżej znajdują się ważne wskazówki dotyczące ponownego ładowania tych metod:
  1. Zawsze używaj tych samych atrybutów obiektu podczas generowania hashCode()i equals();
  2. Symetria. Te. jeśli dla niektórych obiektów xzwróci wartość true y x.equals(y), to y.equals(x)powinno zwrócić wartość true;
  3. Refleksyjność. Ponieważ każdy obiekt x x.equals(x)musi zwracać wartość true;
  4. Konsystencja. Dla dowolnych obiektów xi y x.equals(y)zwraca to samo, jeśli informacje użyte w porównaniach nie ulegną zmianie;
  5. Przechodniość. Dla dowolnych obiektów i x, jeśli zwróci wartość true i zwróci wartość true, wówczas powinno zwrócić wartość true;yzx.equals(y)y.equals(z)x.equals(z)
  6. Ilekroć metoda zostanie wywołana na tym samym obiekcie podczas wykonywania aplikacji, powinna zwrócić ten sam numer, chyba że użyte informacje ulegną zmianie. hashCodemoże zwracać różne wartości dla identycznych obiektów w różnych instancjach aplikacji;
  7. Jeśli dwa obiekty są równe, zgodnie z equals, to hashCodemuszą zwracać te same wartości;
  8. Odwrotny wymóg jest opcjonalny. Dwa nierówne obiekty mogą zwrócić ten sam hashCode. Aby jednak poprawić wydajność, lepiej jest, aby różne obiekty zwracały różne kody.
Przeczytaj ciekawe fakty na temat tych metod tutaj.

Opowiedz nam o modyfikatorach dostępu

Klasy, pola, konstruktory i metody Java mogą mieć jeden z czterech różnych modyfikatorów dostępu: prywatny Jeśli metoda lub zmienna jest oznaczona jako prywatna , tylko kod w tej samej klasie może uzyskać dostęp do zmiennej lub wywołać metodę. Kod znajdujący się w podklasach nie może uzyskać dostępu do zmiennej lub metody, ani nie może uzyskać do nich dostępu z żadnej innej klasy. Modyfikator dostępu prywatnego jest najczęściej używany w przypadku konstruktorów, metod i zmiennych. default Domyślny modyfikator dostępu jest deklarowany, jeśli w ogóle nie określono modyfikatora. Modyfikator ten oznacza, że ​​dostęp do pól, konstruktorów i metod danej klasy można uzyskać poprzez kod wewnątrz samej klasy, kod wewnątrz klas w tym samym pakiecie. Podklasy nie mogą uzyskać dostępu do metod i zmiennych składowych nadklasy, jeśli są zadeklarowane jako domyślne , chyba że podklasa znajduje się w tym samym pakiecie co nadklasa. chroniony Modyfikator chroniony działa tak samo jak modyfikator domyślny , z tą różnicą, że podklasy mogą również uzyskiwać dostęp do chronionych metod i zmiennych nadklasy. To stwierdzenie jest prawdziwe nawet jeśli podklasa nie znajduje się w tym samym pakiecie co nadklasa. public Modyfikator dostępu publicznego oznacza, że ​​cały kod może uzyskać dostęp do klasy, jej zmiennych, konstruktorów lub metod, niezależnie od tego, gdzie znajduje się ten kod. Rdzeń Javy.  Pytania do rozmowy kwalifikacyjnej, część 3 - 2

Co to jest śmieciarz? Możemy do niego zadzwonić?

Odśmiecanie to funkcja automatycznego zarządzania pamięcią w wielu nowoczesnych językach programowania, takich jak Java i języki w NET.Framework. Języki korzystające z odśmiecania często interpretują odśmiecanie na maszynie wirtualnej, takiej jak JVM. Wyrzucanie elementów bezużytecznych ma dwa cele: należy zwolnić nieużywaną pamięć i nie należy zwalniać pamięci, jeśli program nadal jej używa. Czy można ręcznie uruchomić zbieranie śmieci? Nie, System.gc()daje Ci tak duży dostęp, jak to tylko możliwe. Najlepszą opcją jest wywołanie metody System.gc(), która zasygnalizuje modułowi wyrzucania elementów bezużytecznych, że musi zostać uruchomiony. Nie ma możliwości jego natychmiastowego uruchomienia, ponieważ moduł zbierający elementy bezużyteczne jest niedeterministyczny. Ponadto zgodnie z dokumentacją OutOfMemoryErrornie zostanie on przekazany, jeśli maszynie wirtualnej nie udało się zwolnić pamięci po pełnym odśmieceniu. Więcej o śmieciarce dowiesz się tutaj.

Co oznacza natywne słowo kluczowe? Wyjaśnij szczegółowo

Słowo kluczowe native wskazuje, że metoda jest zaimplementowana w języku programowania innym niż plik Java. W przeszłości stosowano metody rodzime . W obecnych wersjach Javy jest to potrzebne rzadziej. Obecnie metody natywne potrzebne są gdy:
  1. Musisz wywołać bibliotekę z Java napisaną w innym języku.
  2. Potrzebujesz dostępu do zasobów systemowych lub sprzętowych, do których można uzyskać dostęp tylko w innym języku (zwykle C). W rzeczywistości wiele funkcji systemowych wchodzących w interakcję z prawdziwym komputerem (takich jak dyski lub dane sieciowe) można wywołać wyłącznie metodą natywną.
Wady stosowania natywnych bibliotek metod są również istotne:
  1. JNI/JNA może zdestabilizować maszynę JVM, szczególnie jeśli spróbujesz zrobić coś złożonego. Jeśli Twoja natywna metoda zrobi coś złego, istnieje możliwość awarii maszyny JVM. Ponadto złe rzeczy mogą się zdarzyć, jeśli Twoja natywna metoda zostanie wywołana z wielu wątków. I tak dalej.
  2. Trudniej jest debugować program za pomocą kodu natywnego .
  3. Kod natywny wymaga osobnej budowy frameworków, co może powodować problemy przy przenoszeniu na inne platformy.

Co to jest serializacja?

W informatyce, w kontekście przechowywania i transmisji danych, serializacja to proces tłumaczenia struktury danych lub stanu obiektu na format, który można zapisać, a następnie odtworzyć w innym środowisku komputerowym. Po otrzymaniu serii bitów są one przeliczane zgodnie z formatem serializacji i można je wykorzystać do stworzenia semantycznie identycznego klonu oryginalnego obiektu. Java zapewnia automatyczną serializację, która wymaga od obiektu implementacji interfejsu java.io.Serializable. Implementacja interfejsu oznacza klasę jako „możliwą do serializacji”. Interfejs java.io.Serializable nie zawiera metod serializacji, ale klasa możliwa do serializacji może opcjonalnie definiować metody, które będą wywoływane w ramach procesu serializacji/diserializacji. Dokonując zmian w klasach, należy rozważyć, które z nich będą, a które nie będą kompatybilne z serializacją. Pełną instrukcję możesz przeczytać tutaj. Podam najważniejsze punkty: Niekompatybilne zmiany:
  1. Usuń pole;
  2. Przesuń klasę w górę lub w dół w hierarchii;
  3. Zmiana pola niestatycznego na statyczne lub nieprzejściowego na przejściowe;
  4. Zmiana zadeklarowanego pierwotnego typu danych;
  5. Zmiana metody WriteObjecttak ReadObject, aby domyślnie nie zapisywała ani nie czytała pól;
  6. Zmiana klasy Serializablena Externalizablelub odwrotnie;
  7. Zmiana klasy wyliczeniowej na klasę inną niż wyliczeniowa i odwrotnie;
  8. Usuwanie Serializablelub Externalizable;
  9. Dodanie writeReplacemetody readResolvedo klasy.
Kompatybilne zmiany:
  1. Dodawanie pól;
  2. Dodawanie/usuwanie klas;
  3. Dodawanie metod WriteObject/ReadObject[metody defaultReadObjectlub defaultWriteObjectnależy wywołać na początku];
  4. Usuwanie metod WriteObject/ReadObject;
  5. Dodatek java.io.Serializable;
  6. Zmiana dostępu do pola;
  7. Zmiana pola statycznego na niestatyczne lub przejściowego na nieprzejściowe .
Linki do poprzednich części: Java Core. Pytania do rozmowy kwalifikacyjnej, część 1 Java Core. Pytania do rozmowy kwalifikacyjnej, część 2 Artykuł oryginalny Miłej nauki!
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION