Skip to content
RemigiuszDudek edited this page Dec 4, 2016 · 19 revisions

Spis pytań

01. W jaki sposób mogę utworzyć klasę main?

Przykład klasy z metodą main zamieściłem w niniejszym repozytorium Main.java Klasa oczywiście nie musi się nazywać Main, ważne natomiast żeby miała w sobie zdefiniowaną metodę main o dokładnie takiej sygnaturze:

public static void main(String[] args) {
  //coś co ma się dziać po uruchomieniu programu
}

Ważne by zaznaczyć, iż do żadnego ćwieczenia nie potrzebujecie tworzyć takiej klasy/metody.

02. Z niewiadomych przyczyn nie działa mi skrót sout

Jak bardzo dużo rzeczy w Intellij, skróty działają kontekstowo. Jeśli w danym kontekście nie ma on sensu (np. poza metodą), Intellij nie będzie podpowidała i będzie to traktowała jako błąd. Zatem gdzie działa skrót sout, tylko w ciele metody.

03. Jaką polecasz literaturę do Javy? Najlepiej jakąś książkę z ćwiczeniami.

  • Head First Java - dobra pozycja, przystępnie napisana z dużą ilością ćwieczeń
  • Java for testers - przeglądnąłem tylko darmową próbkę na leanpub'ie, nie mniej słyszałem wiele dobrego o tej książce i z próbki widzę, że jest napisana w podobnym duchu jak ja prowadzę zajęcia no i ma również dużo ćwiczeń - potencjalny minus, nie ma tłumaczenia na język polski
  • Kurs na Udemy - Java for complete beginners - dobry kurs, niestety tylko po angielsku
  • Kurs na "Kobiety do kodu" - pomimo "sugerowanej" grupy docelowej ;-), myślę że ów kurs będzie wartościowy dla całej grupy, choć jeśli chodzi o ćwiczenia to trochę słabiej

04. Co to jest dziedziczenie?

Dziedziczenie należy rozumieć jako relację "coś jest czymś" np. "Student jest Osobą", "Wykładowca jest Osobą". Modelując taką rzeczywistość moglibyśmy się zdecydować na dziedziczenie:

class Osoba {
  private String imię;
  private String nazwisko;
  
  public Osoba(String imię, String nazwisko) {
    this.imię = imię;
    this. nazwisko = nazwisko;
  }

  public String imię() {
    return this.imię;
  }

  public String nazwisko() {
    return this.nazwisko;
  }
}

class Student extends Osoba {
  private List<Integer> oceny;

  public Student(String imię, String nazwisko) {
    super(imię, nazwisko);
  }
  
  public dodajOcenę(Integer ocena) {
    oceny.add(ocena);
  }

  public float średniaOcen() {
    return średnia(oceny); //trzeba by zaimplementować metodę średnia
  }
}

W powyższej sytuacji klasa Student rozszerza klasę Osoba. Korzysta z wszystkich pól/metod zdefiniowanych w klasie bazowej Osoba i dodaje nową funkcjonalność związaną z ocenami.

Nieco inny przykład dziedziczenia to sytuacja gdy mamy wiele klas dzielących wspólne części i nie chcemy się powtarzać. Przykład: piszemy testy stronki webowej i nie chcemy non-stop instancjonować webdriver'a (jest to zarówno duplikacja z perspektywy kodu jak i strata czasu) w takiej sytuacji również możemy zdecydować się na dziedziczenie:

//słówko abstract mówi o tym, że intencją twórcy klasy było nieinstancjonowanie tej klasy
public abstract class WebPageTest { 
    protected static WebDriver webDriver;

    @BeforeClass
    public static void setUpClass() {
        webDriver = new FirefoxDriver();
    }

    @AfterClass
    public static void cleanWebdriver() {
        webDriver.quit();
    }
}

public class HomePageTest extends WebPageTest {
    // mam dostęp do obiektu webDriver zainicjowanego w klasie nadrzędnej
    private HomePage homePage = new HomePage(webDriver);

    @Test
    public void shouldHaveExpectedPosts() {
      //coś tu testuję
    }
}

Podsumowując są dwie motywacje dlaczego możemy chcieć użyć dziedziczenia:

  • Chcemy rozszerzyć funkcjonalność klasy
  • Chcemy usunąć duplikację

Żeby oddać w pełni sprawiedliwość powiem wam, że odpowiedź na pytanie kiedy użyć dziedziczenia a kiedy go nie używać jest nieco bardziej skomplikowana natomiast jest to temat dużo bardziej zaawansowany. Dla zainteresowanych polecam wpisanie w google "kompozycja a dziedziczenie" lub "composition over inheritance".

Co to znaczy, że w konstruktorze nie definiujemy zwracanego typu?

Konstruktor służy do tworzenia instancji danej klasy np:

class Osoba {
  private String imię;
  private String nazwisko;
  
  //to jest konstruktor
  public Osoba(String imię, String nazwisko) {
    this.imię = imię;
    this. nazwisko = nazwisko;
  }

  public String imię() {
    return this.imię;
  }

  public String nazwisko() {
    return this.nazwisko;
  }
}

Konstruktor wygląda trochę jak metoda tylko właśnie nie ma zdefiniowanego zwracanego Typu. Typem/Klasą obiektu tworzonego przez konstruktor jest zawsze klasa w której konstruktor jest zdefiniowany. W powyższym przykładzie typem jest Osoba. Jeszcze jedna ważna rzecz - nazwa konstruktora musi być taka sama jak nazwa klasy w której konstruktor jest zdefiniowany.

06. Do czego służy framework?

Framework to narzędzie, które ułatwia nam pracę. Frameworki mogą być bardzo różne i służyć do różnych rzeczy dlatego najprościej będzie mi to wytłumaczyć na przykładach:

  • JUnit - nie przejmujemy się tym jak klasy testowe są instancjowane, jak są uruchamiane. Wystarczy że zaanotujemy metodę w klasie i framework już będzie wiedział że to jest metoda do wykonania (oczywiście framework narzuca na nas pewne ograniczenia np. metoda powinna być publiczna, nie powinna nic zwracać i nie może brać parametrów)
@Test
public void shouldBehaveProperly() {
  //some test
}
  • JUnitParams - framework do pisania testów parametryzowanych - pozwala poprzez dodanie anotacji @Parameters({"1", "2", "3"} przekazanie parametru do testu
@Test
@Parameters({"18","20","67"})
public void shouldBeConsideredAsAbleToWork(int age) {
  //some test
}
  • JBehave - pozwala tworzyć dokumentację wykonywalną, której każde zdanie jest kojarzone z konkretnym testem do wykonania (poniższy przykład jest wzięty z głównej strony JBehave) Oczywiście instnieją też framework'i nietestowe, których możemy użyć w kodzie produkcyjnym aplikacji ale zazwyczaj są one nieco bardziej skomplikowane więc jak na razie skupmy się na frameworkach testowych.

07. Pętla for

Ma dwie formy:

  • w podstawowej formie służy do wykonania tej samej operacji "n" razy (w przykładzie poniżej 10 razy)
@Test
public void basicForLoop() {
    // for (warunek początkowy; warunek kontynuacji; operacja na zakończenie pętli)
    for (int i = 0; i < 10; i++) {
        System.out.println(i);
    }
}
  • druga forma pętli for służy do przejścia przez wszystkie obiekty danej kolekcji i potencjalnie wykonanie jakichś operacji
@Test
public void collectionFor() {
    ArrayList<WebPage> webPages = new ArrayList<WebPage>();
    webPages.add(new WebPage("title1"));
    webPages.add(new WebPage("title2"));
    webPages.add(new WebPage("title3"));
    webPages.add(new WebPage("title4"));
        
    for (WebPage webPage : webPages) {
        System.out.println(webPage.getTitle());
    }
}

08. Pętla while

Służy do wykonywania danej części kodu, dopóty dopóki warunek w pętli jest spełniony. Warunek w pętli podobnie jak w przypadku dyrektywy if musi ewaluować się do zmiennej typu boolean (true/false).

@Test
public void basicWhileLoop() {
    int i = 0;
    while (i < 10) {
        System.out.println(i);
        i++;
    }
}