-
Notifications
You must be signed in to change notification settings - Fork 1
Java
Spis pytań
- 01. W jaki sposób mogę utworzyć klasę main?
- 02. Z niewiadomych przyczyn nie działa mi skrót sout
- 03. Jaką polecasz literaturę do Javy? Najlepiej jakąś książkę z ćwiczeniami?
- 04. Co to jest dziedziczenie?
- 05. Co to znaczy, że w konstruktorze nie definiujemy zwracanego typu?
- 06. Do czego służy framework?
- 07. Pętla
for - 08. Pętla
while
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.
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.
- 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
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".
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.
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.
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());
}
}
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++;
}
}
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.