To jest darmowy podgląd

To jest próbka 16 pytań z naszej pełnej kolekcji 150 pytań rekrutacyjnych. Uzyskaj pełny dostęp do wszystkich pytań ze szczegółowymi odpowiedziami i przykładami kodu.

Kup pełny dostęp

Podstawy języka Java

Jakie są główne różnice między JDK, JRE a JVM?

  • JDK (Java Development Kit) zawiera kompilator (javac), debugger i inne narzędzia służące do tworzenia, kompilowania oraz uruchamiania programów w Javie.
  • JRE (Java Runtime Environment) to środowisko uruchomieniowe, w którego skład wchodzi JVM i biblioteki potrzebne do działania aplikacji, ale nie zawiera kompilatora.
  • JVM (Java Virtual Machine) to maszyna wirtualna odpowiedzialna za interpretację (lub kompilację JIT) kodu bajtowego (bytecode) na instrukcje zrozumiałe dla danej platformy.

Więcej informacji:

↑ Powrót na górę

Dlaczego Java jest uznawana za język niezależny od platformy?

Dzięki kompilacji do kodu bajtowego (bytecode), który jest uruchamiany na maszynie wirtualnej JVM. Każda platforma (Windows, Linux, macOS) ma własną implementację JVM, co pozwala na uruchomienie tego samego bajtowego kodu niezależnie od systemu operacyjnego. Więcej informacji:

↑ Powrót na górę

Czym różni się operator „==” od metody equals() podczas porównywania obiektów i typów prymitywnych?

  • == – dalekie od obiektów służy do porównywania wartości prymitywnej (np. int, char); w przypadku obiektów sprawdza, czy obiekty stanowią ten sam odnośnik w pamięci (to samo miejsce w pamięci).
  • equals() – metoda dziedziczona z klasy Object (często przesłaniana w konkretnych klasach), służy do porównywania zawartości obiektów (np. dwa Stringi o takiej samej wartości znakowej).

Więcej informacji:

↑ Powrót na górę

Jakie jest zastosowanie słowa kluczowego „final” w Javie?

  • final przy zmiennej – wartość nie może być zmieniona po inicjalizacji (stała).
  • final przy metodzie – metoda nie może zostać przesłonięta (overriden) w klasach potomnych.
  • final przy klasie – klasa nie może zostać rozszerzona (dziedziczenie jest niemożliwe).

Więcej informacji:

↑ Powrót na górę

Programowanie obiektowe w Javie

Jakie są cztery główne filary OOP i w jaki sposób są one zaimplementowane w Javie?

Cztery główne filary Programowania Obiektowego (OOP) to:

  1. Enkapsulacja (Encapsulation): Ukrywanie wewnętrznego stanu obiektu i udostępnianie go tylko poprzez publiczne metody. W Javie realizowana przez używanie modyfikatorów dostępu (private, public, protected) oraz metod getter/setter.
  2. Dziedziczenie (Inheritance): Mechanizm umożliwiający tworzenie nowych klas na podstawie istniejących, dziedzicząc ich właściwości i zachowania. W Javie osiągane poprzez słowa kluczowe extends i implements.
  3. Polimorfizm (Polymorphism): Możliwość traktowania obiektów różnych klas w sposób jednolity poprzez wspólny interfejs lub klasę bazową. W Javie realizowany przez przeciążanie (overloading) i przesłanianie (overriding) metod oraz wykorzystanie klasy Object.
  4. Abstrakcja (Abstraction): Ukazywanie tylko niezbędnych cech obiektu, ukrywając złożoność. W Javie osiągana poprzez definiowanie klas abstrakcyjnych i interfejsów.

Więcej informacji:

↑ Powrót na górę

Czym jest polimorfizm oraz czym różni się przesłanianie metod od przeciążania metod?

Polimorfizm w OOP oznacza zdolność obiektów do przyjmowania wielu form. W Javie polimorfizm pozwala na traktowanie obiektów różnych klas w sposób zunifikowany poprzez wspólne interfejsy lub klasy bazowe. Rodzaje polimorfizmu w Javie:

  1. Polimorfizm kompilacyjny (przeciążanie metod):
    • Polega na definiowaniu wielu metod o tej samej nazwie, ale różniących się listą parametrów w obrębie tej samej klasy.
    • Rozstrzygany w czasie kompilacji.
   public class Calculator {
       public int add(int a, int b) {
           return a + b;
       }

       public double add(double a, double b) {
           return a + b;
       }
   }
  1. Polimorfizm dynamiczny (przesłanianie metod):
    • Polega na redefiniowaniu metod klasy bazowej w klasie pochodnej.
    • Rozstrzygany w czasie wykonywania.
   public class Animal {
       public void makeSound() {
           System.out.println("Some sound");
       }
   }

   public class Dog extends Animal {
       @Override
       public void makeSound() {
           System.out.println("Bark");
       }
   }

Różnice między przesłanianiem a przeciążaniem metod:

  • Przez przeciążanie:

    • Metody muszą mieć tę samą nazwę, ale różną listę parametrów.
    • Dotyczy jednej klasy.
    • Rozstrzygane w czasie kompilacji.
  • Przez przesłanianie:

    • Metody muszą mieć tę samą nazwę i listę parametrów.
    • Dotyczy klas powiązanych dziedziczeniem.
    • Rozstrzygane w czasie wykonywania.

Więcej informacji:

↑ Powrót na górę

Jakie jest zastosowanie klas abstrakcyjnych i interfejsów? Kiedy ich używać?

Klasy abstrakcyjne i interfejsy w Javie służą do definiowania wspólnego zachowania dla różnych klas, ale różnią się w sposobie zastosowania i możliwościami.

Klasy abstrakcyjne:

  • Mogą zawierać zarówno metody abstrakcyjne (bez implementacji), jak i konkretne (z implementacją).
  • Mogą posiadać pola z modyfikatorami dostępu.
  • Służą jako klasa bazowa, z której dziedziczą klasy pochodne.
  • Pozwalają na dzielenie wspólnej implementacji między klasami.

Kiedy używać:

  • Gdy klasy pochodne mają wspólne cechy i zachowania, które można zaimplementować w klasie bazowej.
  • Kiedy chcemy częściowo zdefiniować klasę, ale pozostawić częściową implementację klasom pochodnym.

Przykład:

public abstract class Vehicle {
    private String brand;

    public Vehicle(String brand) {
        this.brand = brand;
    }

    public abstract void drive();

    public void displayBrand() {
        System.out.println("Brand: " + brand);
    }
}

Interfejsy:

  • Definiują tylko metody abstrakcyjne (do Javy 7) lub domyślne statyczne/metody domyślne (od Javy 8).
  • Nie mogą posiadać stanów (pól) z wyjątkiem stałych public static final.
  • Pozwalają na implementację wielu interfejsów przez jedną klasę, co wspiera wielokrotne dziedziczenie typu.
  • Służą do definiowania kontraktów, które klasy muszą spełniać.

Kiedy używać:

  • Gdy różne klasy muszą implementować ten sam zestaw metod, ale ich implementacja może być różna.
  • Gdy chcemy zapewnić elastyczność i możliwości wielokrotnego dziedziczenia typu.

Przykład:

public interface Drivable {
    void drive();
}

public class Car implements Drivable {
    @Override
    public void drive() {
        System.out.println("Car is driving");
    }
}

Podsumowanie różnic:

  • Klasy abstrakcyjne mogą zawierać implementację metod i stan, interfejsy głównie definiują metody bez implementacji (od Javy 8 można mieć metody domyślne).
  • Dziedziczenie: Klasa może rozszerzać tylko jedną klasę abstrakcyjną, ale implementować wiele interfejsów.

Więcej informacji:

↑ Powrót na górę

Zarządzanie pamięcią i Garbage Collection w Javie

Na czym polega wewnętrzne działanie Garbage Collection w Javie?

Garbage Collection (GC) w Javie działa na zasadzie automatycznego zarządzania pamięcią poprzez identyfikację i usuwanie obiektów, które nie są już dostępne dla aplikacji.

Podstawowe zasady działania:

  1. Marking (Oznaczanie):

    • Identyfikacja obiektów, które są nadal używane
    • Przejście przez graf referencji
  2. Sweeping (Czyszczenie):

    • Usuwanie nieoznaczonych obiektów
    • Zwolnienie zajmowanej przez nie pamięci
  3. Compacting (Kompaktowanie):

    • Defragmentacja pamięci
    • Przesuwanie pozostałych obiektów

Generacyjne podejście:

Heap
├── Young Generation
│   ├── Eden Space
│   ├── Survivor Space 0
│   └── Survivor Space 1
└── Old Generation

Więcej informacji:

↑ Powrót na górę

Jak porównałbyś pracę kolektorów: Serial, Parallel, CMS i G1?

Serial GC (-XX:+UseSerialGC):

  • Jednowątkowy
  • Dobry dla małych aplikacji
  • Prosty i przewidywalny

Parallel GC (-XX:+UseParallelGC):

  • Wielowątkowy
  • Optymalizowany pod względem przepustowości
  • Domyślny do Java 8

CMS (Concurrent Mark Sweep) (-XX:+UseConcMarkSweepGC):

  • Minimalizuje przestoje
  • Złożony
  • Deprecated od Java 14

G1 (Garbage First) (-XX:+UseG1GC):

  • Domyślny od Java 9
  • Przewidywalne czasy pauz
  • Automatyczne balansowanie
# Przykłady użycia
java -XX:+UseG1GC -jar application.jar
java -XX:+UseParallelGC -jar application.jar

Więcej informacji:

↑ Powrót na górę

Kolekcje w Javie (Java Collections Framework)

Jakie właściwości ma ArrayList w porównaniu z LinkedList?

  • ArrayList:
    • Oparta na tablicy dynamicznej.
    • Szybki dostęp do elementu przez indeks (operacja O(1) amortyzowane).
    • Wstawianie/ usuwanie na końcu jest stosunkowo szybkie, jednak wstawianie lub usuwanie w środku listy wymaga przesunięcia wielu elementów (O(n)).
  • LinkedList:
    • Oparta na węzłach połączonych wskaźnikami.
    • Zupełnie inny rozkład kosztów: łatwe (szybsze) wstawianie i usuwanie w środku listy, ale dostęp przez indeks jest wolniejszy (O(n)).
    • Może działać także jako kolejka FIFO (posiada dodatkowe metody).

Referencje:

↑ Powrót na górę

Jak HashMap przechowuje pary klucz-wartość i na czym polega kolizja hashy?

  • HashMap wykorzystuje tablicę tzw. bucketów, gdzie każdy element tablicy odpowiada wartości skrótu (hashCode()) klucza. Wewnątrz bucketa przechowywana jest struktura (kiedyś lista połączona, w nowszych wersjach Javy drzewo binarne przy większej liczbie kolizji) do przechowywania par klucz-wartość.
  • Kolizja hashy występuje wtedy, gdy dwa różne klucze mają ten sam wynik hashCode(). Wtedy oba elementy muszą być przechowywane w tym samym buckecie i rozróżniane dzięki dodatkowej kontroli equals().

Referencje:

↑ Powrót na górę

Obsługa wyjątków (Exception Handling)

Na czym polega różnica między wyjątkami typu checked a unchecked w Javie?

  • Wyjątki checked (np. IOException, SQLException) muszą zostać jawnie obsłużone – kompilator wymaga, aby były przechwycone (try-catch) lub deklarowane w sygnaturze metody (throws).
  • Wyjątki unchecked (np. NullPointerException, ArithmeticException) dziedziczą po RuntimeException. Ich obsługa nie jest wymuszana przez kompilator; można je przechwytywać, ale nie jest to obowiązkowe.

Linki referencyjne:

↑ Powrót na górę

Czym różni się klasa Error od Exception w Javie?

  • Error: reprezentuje poważne błędy środowiskowe (np. OutOfMemoryError), których zazwyczaj nie powinniśmy przechwytywać ani próbować obsługiwać.
  • Exception: oznacza błąd, który możemy przechwycić i ewentualnie obsłużyć (np. IOException, NullPointerException).

Linki referencyjne:

↑ Powrót na górę

Co to jest wyciek zasobów i jak instrukcja „try-with-resources” pomaga go uniknąć?

  • Wyciek zasobów (ang. resource leak) występuje, gdy zasób (np. strumień pliku, połączenie sieciowe) nie zostanie zwolniony (zamknięty) po zakończeniu użytkowania. Może to prowadzić do wyczerpania dostępnych zasobów systemowych.
  • Instrukcja try-with-resources (od Javy 7) automatycznie wywołuje metodę close() na obiektach implementujących interfejs AutoCloseable po zakończeniu bloku try. Zapewnia to bezpieczne zamknięcie zasobu nawet w przypadku wystąpienia wyjątku.

Przykład:

try (FileInputStream fis = new FileInputStream("plik.txt")) {
    // Przetwarzanie pliku
} catch (IOException e) {
    // Obsługa wyjątku
}

Linki referencyjne:

↑ Powrót na górę

Programowanie wielowątkowe i współbieżność

Jak utworzyć wątek w Javie, korzystając z klasy Thread oraz interfejsu Runnable?

  • Klasa Thread: należy utworzyć klasę dziedziczącą po Thread oraz przesłonić metodę run(). Następnie tworzymy obiekt tej klasy i wywołujemy start().
class MyThread extends Thread {
    @Override
    public void run() {
        // Kod wykonywany w wątku
    }
}

MyThread t = new MyThread();
t.start();
  • Interfejs Runnable: tworzymy klasę/obiekt implementujący Runnable, przekazujemy go do konstruktora Thread, a następnie wywołujemy start().
class MyRunnable implements Runnable {
    @Override
    public void run() {
        // Kod wykonywany w wątku
    }
}

Thread t = new Thread(new MyRunnable());
t.start();

Przydatne linki:

↑ Powrót na górę

Jak działa słowo kluczowe synchronized i jakie są potencjalne wady korzystania z niego?

  • synchronized synchronizuje dostęp do sekcji kodu lub metody, co oznacza, że tylko jeden wątek może w danym momencie wykonywać kod chroniony tą samą blokadą (lock).
  • Potencjalne wady:
    • Może prowadzić do wąskich gardeł (obniżenie wydajności w przypadku dużej liczby wątków).
    • Ryzyko zakleszczenia (deadlock), jeśli niepoprawnie zaprojektowane są blokady.

Przydatne linki:

↑ Powrót na górę

Chcesz więcej pytań?

Uzyskaj dostęp do 800+ pytań z 13 technologii - JavaScript, React, TypeScript, Node.js, SQL i więcej. Natychmiastowy dostęp na 30 dni.

Kup pełny dostęp za 49,99 zł