Java

Baza pytań rekrutacyjnych i wiedzy. Filtruj, szukaj i sprawdzaj swoją wiedzę.

Tematy
easyooppolymorphismjava+1

Odpowiedź

Polimorfizm pozwala traktować różne obiekty przez ten sam interfejs lub klasę bazową. Wywołując metodę nadpisaną na referencji typu bazowego, Java wybiera implementację w czasie działania (dynamic dispatch); przeciążanie metod daje polimorfizm czasu kompilacji.

class Animal {
    void sound() {
        System.out.println("Animal makes a sound");
    }
}

class Dog extends Animal {
    @Override
    void sound() {
        System.out.println("Dog barks");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal myDog = new Dog();
        myDog.sound(); // Output: Dog barks
    }
}
mediumexceptionerror-handlingjava

Odpowiedź

Wyjątki checked muszą być obsłużone lub zadeklarowane w throws (np. IOException) i zwykle oznaczają sytuacje możliwe do obsłużenia. Wyjątki unchecked dziedziczą po RuntimeException (np. NullPointerException) i najczęściej wskazują błąd programisty; ich obsługa jest opcjonalna.

mediumoopinterfaceabstract-class+2

Odpowiedź

Interfejs definiuje kontrakt; klasa może implementować wiele interfejsów, a interfejs może mieć metody domyślne/statyczne, ale nie ma stanu instancji. Klasa abstrakcyjna może zawierać pola, konstruktory i częściową implementację, ale dziedziczyć można tylko po jednej klasie. Interfejsy stosuj do „zdolności”, a abstrakcyjne do wspólnej logiki bazowej.

Odpowiedź

String jest niemutowalny, aby można go było bezpiecznie współdzielić między wątkami, buforować i internować w puli Stringów oraz używać jako klucz w kolekcjach hashujących (stały hashCode). Zwiększa to też bezpieczeństwo, bo np. nazwy klas czy ścieżki nie mogą zostać zmienione po utworzeniu.

Odpowiedź

Stack to pamięć per‑wątek przechowująca ramki wywołań, lokalne prymitywy i referencje; jest alokowana/zwalniana przy wejściu/wyjściu z metody i działa bardzo szybko. Heap to współdzielona pamięć, gdzie znajdują się obiekty i tablice; zarządza nią GC i obiekty zwykle żyją dłużej niż jedno wywołanie metody.

Odpowiedź

`==` dla obiektów porównuje referencje (czy to ta sama instancja), a `.equals()` porównuje równość logiczną zdefiniowaną przez klasę (np. `String` porównuje treść). Dla typów prostych `==` porównuje wartości.

String a = new String("hi");
String b = new String("hi");

System.out.println(a == b);       // false
System.out.println(a.equals(b));  // true

Odpowiedź

`final` zmienna nie może być ponownie przypisana, `final` metoda nie może być nadpisana, a `final` klasa nie może być dziedziczona. (To nie czyni obiektu automatycznie niemutowalnym.)

Odpowiedź

`String` jest niemutowalny, więc wielokrotne konkatenacje tworzą dużo obiektów. `StringBuilder` jest mutowalny i szybki do składania tekstu w jednym wątku; `StringBuffer` jest podobny, ale zsynchronizowany (dziś rzadko potrzebny).

StringBuilder sb = new StringBuilder();
for (int i = 0; i < 3; i++) {
  sb.append(i).append(",");
}
System.out.println(sb.toString());
mediumexceptionscheckedruntimeexception

Odpowiedź

Checked exceptions muszą być obsłużone lub zadeklarowane w sygnaturze (dziedziczą po `Exception`, ale nie po `RuntimeException`). Unchecked (`RuntimeException`) nie wymagają tego i zwykle oznaczają błąd programistyczny lub niepoprawny stan.

Odpowiedź

Autoboxing zamienia prymitywy na wrappery (np. `int`→`Integer`), a unboxing odwrotnie. Pułapki: unboxing `null` daje NPE, cache’owanie `Integer` może mylić przy `==`, a dodatkowe alokacje potrafią zaboleć wydajnościowo.

Integer x = null;
// int y = x; // NullPointerException due to unboxing

Integer a = 100;
Integer b = 100;
System.out.println(a == b); // true (Integer cache)

Integer c = 1000;
Integer d = 1000;
System.out.println(c == d); // false

Odpowiedź

`HashMap` nie jest thread-safe; równoległe zapisy mogą go uszkodzić. `ConcurrentHashMap` wspiera bezpieczny dostęp współbieżny z dobrą wydajnością (i nie pozwala na null jako klucz/wartość). Użyj, gdy wiele wątków czyta/zapisuje bez zewnętrznej blokady.

Odpowiedź

Jeśli dwa obiekty są równe wg `equals()`, muszą mieć ten sam `hashCode()`. Kolekcje haszujące (HashMap/HashSet) na tym polegają; złamanie kontraktu powoduje „znikające” wpisy i trudne bugi.

final class User {
  private final String email;

  User(String email) {
    this.email = email;
  }

  @Override public boolean equals(Object o) {
    if (this == o) return true;
    if (!(o instanceof User)) return false;
    return email.equals(((User) o).email);
  }

  @Override public int hashCode() {
    return email.hashCode();
  }
}

Odpowiedź

`volatile` gwarantuje widoczność (i porządek) zmiennej między wątkami, ale nie robi atomowości dla operacji złożonych. `synchronized` daje wzajemne wykluczanie i jednocześnie zapewnia happens-before (widoczność) dla chronionego fragmentu.

class StopFlag {
  private volatile boolean stop = false;

  void requestStop() {
    stop = true;
  }

  void runLoop() {
    while (!stop) {
      // do work
    }
  }
}

Odpowiedź

Heap jest zwykle podzielony na młodą i starą generację: większość obiektów szybko umiera, więc sprzątanie young gen jest częste i tanie (minor GC). Obiekty żyjące dłużej są promowane; czyszczenie old gen jest rzadsze i zwykle droższe.

Odpowiedź

To reprezentacja asynchronicznego obliczenia, które możesz składać (`thenApply/thenCompose`) bez blokowania. Typowa pułapka to zbyt wczesne `get()/join()` (zamiana na kod blokujący) albo brak obsługi wyjątków (`exceptionally/handle`).

CompletableFuture<Integer> result = CompletableFuture
  .supplyAsync(() -> 40)
  .thenApply(x -> x + 2)
  .exceptionally(e -> 0);

System.out.println(result.join());

Odpowiedź

`static` oznacza, że element należy do klasy, a nie do konkretnej instancji. Pole statyczne jest współdzielone przez wszystkie obiekty, a metodę statyczną można wywołać bez tworzenia instancji (ale nie ma ona bezpośredniego dostępu do pól instancji).

Odpowiedź

HashSet jest zwykle szybszy dla add/contains (średnio O(1)), bo jest oparty o hash. TreeSet trzyma elementy posortowane (zbalansowane drzewo), więc operacje są O(log n), ale dostajesz kolejność i zapytania zakresowe.

Odpowiedź

`Optional` reprezentuje wartość, która może być obecna albo nie, i wymusza obsłużenie przypadku pustego. Typowe nadużycie to trzymanie `Optional` jako pola w encjach/DTO wszędzie; najczęściej jest przeznaczony dla wartości zwracanych, a nie pól do serializacji czy persystencji.

Optional<User> user = repo.findById(id);
String name = user.map(User::getName).orElse("unknown");

Odpowiedź

GC zwalnia tylko obiekty nieosiągalne. Jeśli przez błąd trzymasz referencje (np. rosnąca statyczna lista/mapa, cache bez eviction, listenery nieusuwane), obiekty pozostają osiągalne i pamięć rośnie.

Odpowiedź

`ArrayList` nie ma synchronizacji, więc równoległe zapisy mogą uszkodzić stan wewnętrzny albo dać niespójne odczyty. Rozwiązania: zewnętrzny lock, `Collections.synchronizedList`, `CopyOnWriteArrayList` (gdy głównie czytasz) albo inne kolekcje współbieżne zależnie od przypadku.

Odpowiedź

Interfejs definiuje kontrakt (jakie metody istnieją) i wspiera wielokrotne dziedziczenie typu. Klasa abstrakcyjna może współdzielić stan i implementację, ale możesz dziedziczyć tylko po jednej klasie. Interfejs jest dla „umiejętności”, a abstrakcyjna dla wspólnej bazy zachowania.

Odpowiedź

HashMap nie gwarantuje kolejności iteracji. LinkedHashMap utrzymuje kolejność dodania (albo kolejność dostępu, jeśli tak ustawisz), co daje przewidywalną iterację i pozwala budować cache typu LRU.

mediumtry-with-resourcesautocloseableio

Odpowiedź

Automatycznie zamyka zasoby implementujące `AutoCloseable` (pliki, streamy, JDBC) nawet gdy poleci wyjątek. Zapobiega wyciekom i upraszcza, a jednocześnie uwiarygadnia sprzątanie zasobów.

try (var in = Files.newInputStream(path)) {
  return new String(in.readAllBytes(), StandardCharsets.UTF_8);
}

Odpowiedź

Happens-before to reguła gwarantująca widoczność i porządek między wątkami. Jeśli A happens-before B, to B musi zobaczyć efekty A (np. przez `synchronized`, `volatile` albo start/join wątku).

Odpowiedź

Weak reference nie blokuje GC: jeśli obiekt ma tylko słabe referencje, może zostać zebrany. Przydaje się w cache’ach wrażliwych na pamięć (np. WeakHashMap), gdzie lepiej „zgubić” wpis niż leakować pamięć.

Odpowiedź

JVM uruchamia bytecode Javy. JRE to środowisko uruchomieniowe (JVM + biblioteki standardowe) potrzebne do odpalania aplikacji. JDK to zestaw deweloperski (JRE + kompilator i narzędzia) potrzebny do budowania aplikacji.

Odpowiedź

Record to zwięzła składnia dla niezmiennego nośnika danych. Generuje final pola, konstruktor oraz `equals/hashCode/toString`. Jest dobry do DTO, wiadomości i obiektów “wartościowych” — nie do encji z rozbudowanym, mutowalnym cyklem życia.

Odpowiedź

Kolekcja przechowuje dane; stream opisuje potok operacji (filter/map/reduce), który produkuje wynik. Streamy są zwykle jednorazowe, a częsty błąd to efekty uboczne (mutowanie zewnętrznego stanu) w `map/forEach`, co utrudnia myślenie o kodzie.

List<String> activeNames = users.stream()
  .filter(User::isActive)
  .map(User::getName)
  .toList();
hardthreadlocalconcurrencythread-pool+1

Odpowiedź

`ThreadLocal` przechowuje osobną wartość na wątek (często jako kontekst requestu). Częsty problem to pule wątków: wątki są recyklingowane, więc wartości mogą “przeciekać” między requestami, jeśli ich nie wyczyścisz (`remove()` w `finally`).

Odpowiedź

`synchronized` jest prostsze i używa monitorów JVM, dając wzajemne wykluczenie oraz jasne happens-before. `ReentrantLock` jest bardziej elastyczny: `tryLock()`, timeouty, opcje fairness i wiele `Condition` — ale musisz zawsze robić `unlock()` w `finally`.

Odpowiedź

Classpath to lista miejsc, w których JVM szuka klas i zasobów (katalogi i pliki JAR). Jeśli czegoś nie ma na classpath, możesz dostać `ClassNotFoundException` / `NoClassDefFoundError`. Ustawiasz go przez build tool, IDE albo opcję `-cp` przy uruchamianiu Javy.

mediumjavavartype-inference+1

Odpowiedź

`var` daje inferencję typu dla zmiennych lokalnych: kompilator wywnioskuje statyczny typ z inicjalizatora. To NIE robi z Javy języka dynamicznego. `var` działa tylko dla zmiennych lokalnych z inicjalizatorem (nie dla pól, parametrów metod ani bez przypisania).

Odpowiedź

`List.of(...)` tworzy listę niemodyfikowalną (unmodifiable). Próba add/remove skończy się `UnsupportedOperationException`. Częsty gotcha: nie pozwala też na elementy null (rzuci `NullPointerException` już przy tworzeniu).

List<String> xs = List.of("a", "b");
// xs.add("c"); // throws UnsupportedOperationException

Odpowiedź

Parallel streamy mogą pomóc przy pracy CPU-bound na dużych kolekcjach, gdy elementy są niezależne, a praca jest na tyle ciężka, żeby opłacił się narzut. Pułapki: domyślnie używają `ForkJoinPool.commonPool`, mogą być wolniejsze dla małych zadań, są złe dla blokującego I/O, a efekty uboczne i współdzielony stan łatwo prowadzą do race condition.

Odpowiedź

ClassLoader ładuje klasy i zasoby. W Javie typ jest identyfikowany przez (nazwa klasy + ClassLoader, który ją załadował). To znaczy, że “ta sama” nazwa klasy załadowana przez dwa różne classloadery jest traktowana jako dwa różne typy, co potrafi dać `ClassCastException` w setupach typu pluginy albo app-serwery.

Odpowiedź

Type erasure oznacza, że informacja o typach generycznych jest usuwana w runtime. W efekcie nie zrobisz `new T()`, `T.class` ani `instanceof T`, a część sprawdzeń działa tylko w czasie kompilacji. W runtime widzisz typy „surowe”.

Odpowiedź

`record` to zwięzły nośnik danych. Generuje prywatne finalne pola, kanoniczny konstruktor, akcesory, `equals`, `hashCode` i `toString`. Sprawdza się jako DTO/obiekt wartości, gdzie równość wynika z danych, ale nie czyni zagnieżdżonych obiektów niemutowalnymi.

Odpowiedź

Sealed class ogranicza, które klasy mogą ją dziedziczyć/implementować (`permits`). Dzięki temu hierarchia jest jawna i można pisać wyczerpujące `switch`. To przydatne do modelowania zamkniętych zestawów wariantów.

Odpowiedź

`synchronized` używa wbudowanych monitorów i automatycznie zwalnia blokadę. `ReentrantLock` to jawny lock z funkcjami typu `tryLock`, polityką fairness i możliwością przerwania oczekiwania — ale musisz go zwolnić w `finally`. Oba są reentrant.

Odpowiedź

Wymaga zasobów implementujących `AutoCloseable`. Zasób jest zamykany automatycznie (nawet przy wyjątku), co zmniejsza boilerplate i zapobiega wyciekom. Jest bezpieczniejsze niż ręczne `finally`.

try (var in = Files.newInputStream(path)) {
  return new String(in.readAllBytes(), StandardCharsets.UTF_8);
}

Odpowiedź

StringBuilder nie jest synchronizowany i jest szybszy w kodzie jednowątkowym. StringBuffer jest synchronizowany (thread‑safe), ale zwykle wolniejszy. Oba są mutowalnymi alternatywami dla `String`.

Odpowiedź

HashMap nie jest thread‑safe i najlepiej używać go w kodzie jednowątkowym lub zewnętrznie synchronizowanym. ConcurrentHashMap wspiera bezpieczne współbieżne odczyty/zapisy z lepszą skalowalnością; nie pozwala na null key/value. Używaj, gdy wiele wątków korzysta z mapy bez dodatkowych locków.

Odpowiedź

Większość obiektów szybko umiera. JVM wykorzystuje to, często sprzątając young generation (szybkie minor GC) i promując długo żyjące obiekty do old generation, które sprząta rzadziej. To poprawia throughput i czasy pauz.

Odpowiedź

JVM startuje od interpretacji bytecode, a potem JIT kompiluje „gorące” metody do kodu natywnego na podstawie profilowania. Na początku bywa wolniej; po rozgrzaniu działa szybciej dzięki zoptymalizowanemu kodowi maszynowemu.

Odpowiedź

Statyczna klasa zagnieżdżona nie trzyma ukrytej referencji do obiektu zewnętrznego i można ją tworzyć bez instancji klasy zewnętrznej. Inner class ma referencję do obiektu zewnętrznego, co zwiększa zużycie pamięci i może prowadzić do leaków.