Witaj w kolejnym artykule z serii „Rozmowa kwalifikacyjna z Javy? Żaden problem!”W poprzednim artykule omawialiśmy pytania z rozmów kwalifikacyjnych odnoszące się do jednej z najważniejszych pojęć Javy – Kolekcji, w dzisiejszym artykule będziemy kontynuować tematykę pytań na rozmowach kwalifikacyjnych z Javy. Artykuł ten będzie przeznaczony głównie dla osób aplikujących na stanowiska juniorskie (będzie on zawierał pytania dotyczące podstaw Javy oraz jej głównych założeń), niemniej polecamy również doświadczonym developerom – miłej wiedzy nigdy za wiele;-)

Czym jest JVM?

JVM jest to nic innego jak wirtualna maszyna Javy (Java Virtual Machine). Jest to swojego rodzaju procesor wykonujący skompilowany kod języka Java. Każdy plik źródłowy Javy jest skompilowany w kod bajtowy, który jest wykonywany właśnie poprzez JVM. Głównym założeniem Javy jest akronim WORA (Write Once, Run Anywhere,) tłumaczony, jako „napisz raz, uruchamiaj gdziekolwiek. Aby osiągnąć ten cel potrzebna była właśnie wirtualna maszyna, która działała o poziom wyżej niż kod maszynowy – dzięki temu kodu nie trzeba było kompilować do różnych wersji danego programu dla różnych korzystających z niego platform.

Jaka jest różnica pomiędzy JDK oraz JRE?

JRE (Java Runtime Environment) jest wirtualną maszyną Javy, w której Twoje programy są uruchamiane. JDK stanowi natomiast skrót od Java Development Kit, zawarte są w nim wszystkie komponenty potrzebne do tworzenia aplikacji w języku Java. Zawarte są w nim chociażby takie rzeczy jak JRE, kompilator oraz narzędzia takie jak JavaDoc, Debugger.

Rys. 1 Różnica pomiędzy JRE, JDK oraz JVM

Co rozumiesz przez pojęcie klasa oraz obiekt?

Klasa jest swojego rodzaju schematem na podstawie, którego powstają obiekty. W klasie definiujemy pola zawierające dane, oraz metody wykonywane przez obiekt.

Obiekt jest natomiast konkretną jednostką, która zawiera stany zapisane w polach, oraz zachowania definiowane przez metody. Metody odpowiadają za operacje wykonywane na wewnętrznych stanach obiektu, oraz za komunikację pomiędzy dwoma różnymi obiektami. Obie jednostki są podstawowymi elementami programowania obiektowego.

Czym jest polimorfizm?

Nazwa ta wywodzi się z greckiego i oznacza wiele form (z angielskiego Poly = wiele, Morph = zmiana lub forma). Oznacza to tyle, iż obiekt ma możliwość przyjmowania wielu form. Każdy obiekt, który jest w stanie pozytywnie przejść więcej niż jeden test IS-A (z ang. IS-A – jest – angielski odpowiednik lepiej tłumaczy według nas istotę polimorfizmu) jest polimorficzny. W Javie wszystkie obiekty są polimorficzne, ponieważ wszystkie są dziećmi superklasy Object.

Rys.  2 Jak widać na rysunku klasa „Kitten” (kociak) zdaje test Is-A (Kitten IS-A Cat, Kitten IS-A Animal), a więc jest polimorficzny. Chcemy tylko dodać – wiemy że kotom nie powinno się podawać mleka 😉

Czym jest interfejs w Javie i jakie mają zastosowanie?

Interfejs jest to typ referencyjny w Javie. Zawiera pewne podobieństwo do klasy, ponieważ definiowane są w nim zmienne (będące domyślnie finalne oraz statyczne) i metody (ich typ zwracanej zmiennej, nazwę oraz argumenty przyjmowane przez metody), aczkolwiek nie zawiera ich konkretnej implementacji. Klasy mogą implementować dowolną ilość interfejsów (w odróżnieniu dziedziczenia po innych klasach), dziedzicząc wszystkie ich metody, oraz implementując ich funkcjonalność. W ósmej odsłonie Javy uległo to jednak trochę zmianie – metody typu domyślne (default) oraz statyczne mogą zawierać konkretną funkcjonalność w interfejsie.  Warto również zaznaczyć, że interfejsy mogą być rozszerzane przez inne interfejsy. Nie istnieje tutaj ograniczenie jak w klasie gdzie metody mogą być dziedziczone poprzez tylko jedną klasę – Interfejsy mogą dziedziczyć po nieograniczonej ilości innych interfejsów.

Rys.  3 Przykładowa klasa interfejsu – jak widać, w odróżnieniu od klas, interfejs może rozszerzać kilka interfejsów. Ponadto może również zawierać metody statyczne które posiadają już funkcjonalność (Java 8).

>> Sprawdź nasze aktualne oferty w obszarze: Java Developer

Czym jest klasa abstrakcyjna?

Klasa abstrakcyjna jest to klasa, która została zdefiniowana poprzez słówko kluczowe abstract. Może ona zawierać zwykłe metody bądź metody abstrakcyjne (w klasach abstrakcyjnych brakuje konkretnej funkcjonalności). Nie można utworzyć instancji klasy abstrakcyjnej – inne klasy mogą natomiast dziedziczyć funkcjonalność po tych klasach. Jeżeli klasa nie zaimplementuje funkcjonalności wszystkich metod zadeklarowanych jako abstrakcyjne, musi być również zadeklarowana jako klasa abstrakcyjna.

Rys.  4 Przykładowa klasa abstrakcyjna. Jak widać może ona zawierać pewną funkcjonalność w swoich metodach (tych które nie są zadeklarowane abstrakcyjne). W odróżnieniu od interfejsu, może dziedziczyć jedynie po jednej klasie.

Rys.  5 Klasa abstrakcyjna, po której dziedziczy klasa abstrakcyjna Protagonist.

Jaka jest różnica pomiędzy interfejsem a klasą abstrakcyjną?

Po pierwsze – interfejsy mogą zawierać tylko deklaracje danych metod – nie mogą zawierać w sobie konkretnie zaimplementowanych metod (poza metodami statycznymi oraz domyślnymi). Klasy abstrakcyjne mogą natomiast zawierać konkretną implementację danych metod, dzięki czemu mogą definiować podstawową funkcjonalność.

Kolejną ważną różnicą jest to, że interfejs może rozszerzać mnogą ilość interfejsów, oraz że klasy mogą implementować również mnogą ilość interfejsów. Rozszerzając klasę abstrakcyjną klasa może uczestniczyć jedynie w jednej hierarchii, natomiast używając interfejsów klasa może uczestniczyć w wielu typach hierarchii.

Po trzecie, interfejsy wymagają od użytkownika implementacji wszystkich metod w nich zawartych (co może okazać się dosyć męczące). Klasy abstrakcyjne nie wymagają tego od użytkownika, mogą to również ułatwić umożliwiając podstawową implementację danej funkcjonalności.

Jaka jest różnica pomiędzy wyjątkiem sprawdzonym oraz niesprawdzonym (checked/uncheckedException)?

Sprawdzony wyjątek to wyjątek, który powstaje przy kompilacji aplikacji. Programista musi to uwzględnić w swoim kodzie wykonać jedną z dwóch czynności – stwierdzić jak poradzić sobie z danym wyjątkiem, bądź podać go o poziom wyżej przy użyciu słówka kluczowego throws. Wyjątek niesprawdzony nie jest wykrywany podczas kompilacji, jego przyczyną są najczęściej błędy logiczne w kodzie (np. dzielenie przez zero, bądź wskazanie na wartość null).

Jakie typy danych występują w Javie?

Typy danych można podzielić przede wszystkim na dwa główne typy – prymitywne oraz złożone (nie-prymitywne). Prymitywne typy danych zawsze zaczynają się małą literą (większość IDE nadaje im również specjalny kolor, podobnie jak słówkom kluczowym. Nazwy typów złożonych powinny rozpoczynać się dużą litera. Do typów prymitywnych należą:

  • boolean,
  • char,
  • byte,
  • short,
  • int,
  • long,
  • float,

Natomiast do typów złożonych należą wszystkie typy danych stworzone przez programistów, przykładowo String, Array, List…

Skoro istnieją typu prymitywne (np. boolean) i wiemy, że ich nazwy rozpoczynają się małą literą to czym w takim razie są klasy typu Boolean, Byte, Float?

Są to tak zwane klasy opakowujące (wrapperclasses). Pozwalają nam one na opakowanie prymitywnych typów danych. Dzięki temu jesteśmy w stanie używać prymitywnych typów danych (opakowanych we wrappery) np. w listach lub mapach. Występuje tu również zjawisko autoboxingu oraz unboxingu – pierwsze z nich opisuje automatyczną konwersje danych prymitywnych do klas opakowujących (np. int do Integera), drugie natomiast opisuje tą samą operację, ale w odwrotną stronę.

Jakie nowe funkcjonalności zostały wprowadzone w Javie 8 i Javie 9?

Można powiedzieć, że kluczową zmianą dla użytkowników języka Java, było wprowadzenie w 2014 roku wyrażenia lambda w wersji Java 8. Jest to idealna metoda na tworzenie czytelnego i zwięzłego kodu! Java 9 ma doskonałe nowe i inteligentne funkcje, które przeniosły Javę na nowy poziom. Obsługa języka JavaScript to najlepsza funkcja w Javie 9 w porównaniu z Javą 8.

Java 8 ma różne funkcje, takie jak Java Stream API, Java Time API, ulepszenia Java IO, współbieżność, wyrażenia lambda, interfejsy funkcjonalne i ulepszenia interfejsu Collection API.

Java 9 ma różne funkcje, takie jak JShell (REPL), różne metody Factory dla API kolekcji, Module System i Reactive Streams API. W Javie 8 metody domyślne i statyczne zostały wprowadzone w interfejsach.

Czym jest Serializacja (Serialization) i Deserializacja (Deserialization)?

Jest to proces, w którym obiekt jest konwertowany na sekwencje bitów. Obiekt, który został poddany serializacji, może zostać zapisany w postaci pliku na dysk twardy, lub przesyłany poprzez strumienie danych. Jeżeli proces ten odbywa się w stronę odwrotną (tzn. z pliku do obiektu) obiekt poddawany jest wtedy procesowi deserializacji. Aby była możliwa serializacja, klasa obiektu musi implementować interfejs Serializable.

Czym jest proces Garbage Collection (Zbierania odpadów)?

Jest to proces przeprowadzany przez program GarbageCollector (zbieracz odpadów), który wykonywany jest w wirtualnej maszynie javy (JVM). Proces ten pozbywa się nieużywanych przez aplikację obiektów. Dzięki temu uwalniana jest pamięć, która może być wykorzystana do zapisywania nowych obiektów. Pierwszym podejmowanym w trakcie działania procesu jest oznaczanie czy dana pamięć jest używana czy nie – dzięki temu w następnym procesie (usuwaniu normalnym) GarbageCollectorwie, których obiektów zajmujących pamięć ma się pozbyć. Następnie, aby poprawić wydajność można również zastosować kompaktowanie pamięci, przesuwając pozostałe używane obiekty obok siebie, dzięki czemu dostęp do pamięci jest prostszy oraz szybszy.

Jaka jest różnica pomiędzy porównywaniem obiektów przy pomocy metody .equals() oraz ==?

W Javie operator dwóch znaków „=” używany jest, aby sprawdzić czy dwa obiekty odwołują się do tego samego miejsca w pamięci. Metoda .equals() używana jest natomiast do porównywania obiektów poprzez ustalone kryteria (metoda jest zawarta w klasie Object a wiec implementują je wszystkie klasy, ponadto może zostać przez nas nadpisana w celu porównywania konkretnych pól danych obiektów). Dlatego jeżeli chcemy sprawdzić czy dwa obiekty typu String mają taką samą wartość powinniśmy używać metody .equals(). W przypadku, gdy chcemy sprawdzić czy dwa obiekty odwołują się do tego samego miejsca w pamięci (rzadkie przypadki – najczęściej == używane jest do porównywania prymitywów) używamy operatora ==.

Zobacz też:

Rozmowa kwalifikacyjna z Javy? Żaden problem! – cz. II (Kolekcje)

Rozmowa kwalifikacyjna z Javy? Żaden problem! Cz. IV (Multithreading)

Rozmowa kwalifikacyjna z Javy? Żaden problem! Cz. V (Wzorce projektowe)

Rozmowa kwalifikacyjna z Javy? Żaden problem! Cz. VI (Spring)

Rozmowa kwalifikacyjna z Javy? Żaden problem! Cz. VII (Spring)

Rozmowa kwalifikacyjna z Javy? Żaden problem! Cz. VIII (JPA)

Rozmowa kwalifikacyjna z Javy – Żaden problem! Cz. IX – Algorytmy i struktury danych

Comments (3)

  1. Pingback: Rozmowa kwalifikacyjna z Javy? Żaden problem! Cz. IV (Multithreading)

Comments are closed.