Basis of Docker #1 – what is it and why this is neat?

Docker everywhere…

Everywhere you look, you can see Dockers. Every big corporation uses it: Google, Microsoft, IBM, etc. Taking this into consideration, you may have a question coming into your mind: why is it so popular? With this post, which opens a series about Dockers and Docker Compose, I would like to answer this question. Let’s begin!

Docker – what is it?

For starters, it is good to know what we are really talking about. Let’s start with explaining what  Docker really is.

Docker is a summary name for two main components:

  • Docker CLI,
  • Docker Engine.

Docker CLI is an interface for command line which allows users to easily manage docker containers and their settings.

Docker Engine is somehow similar to a virtual machine(VM), but it is not the same. In fact, container virtualizes an operating system where VM virtualizes hardware which is below it.

It means that each Docker is not a copy of any kind of operating system, it just virtualizes its functions and its environment upon the host OS, where VM virtualizes a hardware for an OS which will be ran inside of that VM. To use more plain words: VM is just as you create a virtual server on a physical server machine.

This is why we  use a word “container” for Docker instances, thus we can say: Docker containers.

For better understanding, let’s have a look on these pictures below:

VM Image
Virtual Machine concept image src: www.docker.com
Docker concept image
Docker conceptual image src: www.docker.com

Those images above are the best way to understand Docker concept and what a Docker container really is comparing to an operating system and a virtual machine.
However, in spite of the fact, that Docker can be ran on the host OS directly, it can be either ran inside of a VM too, because a VM is just a virtual server upon hardware layer. This operation is called: “adding layer of abstraction vertically”.  So, for example, we can set up virtualization server on a physical device. And then, create Docker containers in one of the VMs for many different applications to be ran inside on virtual server. It is just a plain example for how to use those two concepts together, it is not a real life scenario. To make it real life scenario we need some more sophisticated software such as Kubernetes or Cloud Foundry to hypervise our containers and in case of using Cloud Foundry, we will need the BOSH Platform and a virtualization platform such as Openstack, or we can go for something easier such as Heroku Cloud, Azure Cloud, Google Cloud Platform etc.
But we will come over to it later in this post serie.

So, why Docker is so popular?

Basing on what I said above, we can come up to a conclusion that Docker allows us to move its containers between platform with no cost. It means that it doesn’t matter if you will run it on Windows or Linux – it will be exactly the same thing and it will behave in the same exact way.
This is the main reason for a lot of bussinesses to use Docker as a production solution for deployment of their applications or other services. What’s the most important – it makes everything cheaper and what’s very important too – it shortens “time to market”  drastically.

Okay, it is all for now, see you soon in the next post in that serie. Greetings!

Podstawy Linuxa – komendy z ich objaśnieniem. [PL]

Dawno nic tutaj nie pisałem, w sumie to po prostu zapomniałem o tym blogu. Ale teraz, na studiach stwierdziłem, że zrobię coś dla ogółu i napiszę krótki wpis o potrzebnych komendach Linuxa, a tak na prawdę o komendach powłoki systemu bazującego na kernelu Linux. Zatem do dzieła!

Krótki wstęp

Ogólnie rzecz ujmując, ciężko jest się czegokolwiek uczyć na pamięć. To zwykle po prostu nie działa. Przypadek uczenia się Linuxa nie jest wyjątkiem od tej reguły. Z drugiej strony można zapytać: jak zatem zapamiętać te komendy? Najprościej zwyczajnie w świecie używać Linuxa, ale są “tricki” na to jak sobie ewt. pomóc w tej kwestii, jeśli zrozumie się pewne podstawowe zasady dot. budowy powłoki Linuxa.

Wpierw: sama powłoka to po prostu program, zwykły program oraz zwykły plik znajdujący się na dysku w folderze: /usr/bin.

Notka: Słowo powłoka będę zamieniał na słowo “shell”, słowo “potoki” to to samo co “stream(-s)”. Standardowe wejście to standard-in lub też stdin i analogicznie standard out aka stdout to standardowe wyjście.

Stdin to zwykle urządzenie peryferyjne, które umożliwia wprowadzanie danych na linię komunikacyjną między użytkownikiem a systemem operacyjnym.

Stdout to zwyczajnie linia wyjścia, która najczęściej jest jednoznaczna z monitorem.

A teraz: jakie są te “tricki”?

Na początek warto nadmienić, że większość komend, ich nazw to zwykle skrót z angielskiego lub nawet pełne słowo.

A czym są komendy jako takie? To po prostu pliki wykonywalne (coś jak .exe w Windows) umieszczone w folderze /usr/bin/, w momencie wprowadzenia czegoś na linię wejścia, shell wyszukuje tą nazwę w podanym wcześniej folderze. Jest to standard dla dystrybucji deb i rpm, czyli dla wszelkich systemów pochodnych od Debiana oraz RedHata.

Skoro są to pliki wykonywalne to zwyczajnie wywołanie listingu folderu komendą “ls” pomoże nam zawsze znaleźć komendy, przejrzeć je, gdyż “man” nie zawsze jest wygodny by go przeglądać, nawet używając przeglądania wbudowanego w ten program.

Z kolei, jeśli już znamy nazwę komendy lub wyhaczyliśmy ją w liście plików w folderze to zadajemy sobie pytanie o tzw. przełączniki. Czym są przełączniki? Przełączniki z ang. switches służą do modyfikowania domyślnego zachowania komedny. Mogą wystąpić w dowolnym miejscu po nazwie komendy, ale przyjęło się, że występują zaraz po jej nazwie. Przełączniki możemy łańcuchować, czyli zapisywać ich nazwy jedne po drugich bez rodzielania ich. Jednak ciężko znać je wszystkie, a pomocna byłaby ich lista dla danej komendy. Skróconą i wystarczającą listę przełączników uzyskujemy poprzez skrócony przełącznik “-h”, albo “–help” – jego długą wersję. Czasem niektóre programy wykonywalne zwracają komendę na wprowadzony dowolny, niepoprawny argument znaleziony na stdin.

Na koniec: przydatnym jest by pamiętać, że w zasadzie wszystko w systemach z rodziny Linuxów jest plikiem, więc do wszystkiego podchodzimy tak samo i nie ma większej różnicy między większością obiektów znajdujących się w systemie plików.

Na ten przykład:

ls –help wyświetli coś takiego:

Screenshot_2019-11-14_23-48-51

W tym przypadku występuje tylko przełącznik: –help, jako, że -h jest zarezerwowany do czego innego w przypadku komendy “ls”.

To samo wyświetli taka komenda:

ls -h

To działa w większości przypadków, gdy chcemy dowiedzieć się jaka jest lista przełączników.

A tak wygląda łańcuchowanie przełączników:

ls -lah.

Wynik wywołania ls:

Screenshot_2019-11-14_23-55-26

A tak wygląda wynik wywołania ls -lah:

Screenshot_2019-11-14_23-55-04

 

Lista komend z objaśnieniem

Skoro już wiemy co nieco na temat tego czym tak na prawdę są komendy w shellu systemu operacyjnego, to możemy przejść do obiecanej listy komend. Nie utrzymałem w niej żadnego konkretnego porządku, wypisałem je tak, jak przypomniałem sobie, że dana komenda może być potrzebna.

ls – z angielskiego: list, wywołana wprost, bez argumentów i przełączników zwraca zwykły, posortowany “listing” katalogu, w którym się aktualnie znajdujemy. Najczęściej przydają się tu przełączniki -l -a -h, gdzie:

  • l(ong) oznacza format listy długiej (w pionie a nie w poziomie),
  • a(ll) oznacza wszystko czyli włącznie z plikami ukrytymi,
  • h(uman-readable), czyli format czytelny dla człowieka

pwd – z angielskiego: print working directory, czyli wydrukuj (w domyśle na stdout) aktualny katalog roboczy.

Screenshot_2019-11-15_00-05-36

touch – z angielskiego: dotyk, dotknij. W zasadzie to tylko gra słów, czyli “dotknij systemu plików w tym miejscu tworząc plik”. Tworzy prosty plik w domyślnym porządku bitów i formacie kodowania znaków.

mkdir – z angielskiego: make directory, czyli utwórz katalog. Tworzy katalog w podanym miejscu, a przy braku argumentów w katalogu, w którym jesteśmy aktualnie. Jeśli wprowadzimy jako argument, bez przełączników lub z nimi, ścieżkę absolutną, mkdir utworzy tam folder. W przypadku, gdy chcemy utworzyć kilka folderów jeden w drugim użyjemy przełącznika -p.

rm – z angielskiego: remove, czyli usuń. Usuń dokładnie to co wskazane na stdin programu. Program jest w stanie usunąć zarówno plik jak i katalog, domyślnie działą w trybie usuwania plików.

Przydatne przełączniki dla tej komendy:

  • r(ecurssive) – rekurencyjnie, czyli wchodzi w głąb drzewa katalogów,
  • d(ir) – pusty katalog,
  • f(orcefully) – siłowo, bez pytania o cokolwiek (UWAGA: w przypadku pracy z poziomu użytkownika root ta komenda nie zapyta o pozwolenie na usunięcie wskazanego obiektu bez względu na obecność tego przełącznika!)

rmdir – z angielskiego: remove directory, czyli usuń katalog, dublet z powyższej funkcji.

cp – z angielskiego: copy, czyli skopiuj. Skopiuj to co wprowadzone jako pierwszy argument do miejsca, który wskazujemy jako drugi argument.

Aby skopiować plik, na pierwszy argument należy wskazać ścieżkę, która jednoznacznie wskazuje na ten plik. Drugi argument powinien wskazywać albo na katalog docelowy, albo na plik, który nie istnieje. Różni się to tym, że wtedy w katalogu docelowym pojawi się albo plik o tej samej nazwie co pierwotny plik, albo o takiej nazwie, którą wskazujemy w drugim argumencie.

Przydatne przełączniki:

  • r(ecurssive) – rekurecyjnie skopiuj cały katalog.

file – z angielskiego: plik, teczka, czyli po prostu no, plik. jako argument podajemy ścieżkę do pliku lub jego nazwę, jeśli jest on w folderze, w którym się znajdujemy.

Przydatne przełączniki:

  • i(nformation) – informacje o pliku: ścieżka, zestaw znaków użyty do kodowania oraz MIME type.

tar – z angielskiego: tape archive, czyli archiwum taśmowe. To pochodzi jeszcze z czasów, gdy osobne zbiory danych, pliki zapisywano na archiwum, które było fizycznie taśmą (Tjuring hehehehe). W latach ’90, gdy tworzono “tar”, użyto tej samej logiki, gdyż format pliku typu TAR jest taki, że surowe binarne dane z zachowaniem kodowania jest doklejany do końca tego co go poprzedzało, tak jak na taśmie(oczywiście zachowując pewien format danych typowy dla standardu).

Przydatne przełączniki:

  • c(reate) – z angielskiego stwórz, czyli po prostu stwórz archiwum o właściwościach podanych w argumencie pierwszym i/lub drugim,
  • (e)x(tract) – z angielskiego rozpakuj, czyli wyciągnij zawartość tego co znajdziesz we wskazanym w argumencie pliku do lokalizacji również podanej w argumencie programu tar,
  • (g)z(ip) – po tworzeniu pliku tar, skompresuj go używając bezstratnej, silnej kompresji GZIP,
  • b – to samo co wyżej tylko typ kompresji BZIP2,
  • v(erbose) – drukuj całość logów na stdout.

 

chmod – z angielskiego: change mode, czyli zmień tryb w sensie trybu dostępu do zasobu w systemie plików. Jako argumenty ta komenda przyjmuje ciąg opisujący rządane permisje do zasobu, następnie to czemu chcemy nadać te permisje.

Argument określający permisje może mieć dwie formy:

  • ósemkową,
  • ciągu liter.

 

Forma ósemkowa

Forma ósemkowa składa się z 3 pól, które odpowiadają poziomowi dostępu dla jednego z obiektów docelowych:

  • pierwsze pole: user, użytkownik w sensie właściciela (u),
  • drugie pole: group, grupa, domyślnie ta, do której należy użytkownik będący właścicielem (g),
  • trzecie pole: others, inni (o).

Natomiast na każdym polu wystąpuje suma 3 możliwych wartości:

  • 4 – oznacza nadanie permisji odczytu (r od read),
  • 2 – oznacza nadanie permisji zapisu (w od write),
  • 1 – oznacza nadanie permisji wykonania (x od eXecute).

A, więc przykładowo: chmod 777 ./plik nada wszystkim obiektom w systemie pełny dostęp do obiektu “plik”. Właściciel będzie miał wszystkie prawa, cała grupa, do której obiekt jest przypisany oraz wszyscy pozostali.

Natomiast taka kombinacja: 470 nada właścicielowi tylko i wyłącznie prawo odczytu, grupie pełne prawa, a reszta obiektów w systemie nie będzie miała dostępu do tego zasobu (pliku czy folderu).

Format tekstowa

Forma tekstowa jest bardziej intyuicyjna dla większości ludzi, gdyż posługuje się skrótami ze słów jak następuje wg. schematu – (skrót, rozwinięcie):

Te dotyczące komu przypisujemy uprawnienie:

  • u – user,
  • g – group,
  • o – others,
  • a -all

Te, które dotyczą tego jakie uprawnienie chcemy przypisać:

  • r – read,
  • w – write,
  • x – execute.

Przykładowa sekwencja: chmod a+r plik.

Wszystkim obiektom dodajemy odczyt do tych uprawnień co już mają do zasobu “plik”.

Kolejny przykład: chmod g-w plik.

Całej grupie, która ma dostęp do zasobu plik traci prawo do zapisu do zasobu.

 

Przydatny jest tutaj głównie przełącznik -R co oznacza z angielskiego recurssive, czyli zmieni permisje rekurencyjnie.

chown – z angielskiego: change owner, czyli zmień właściciela. Zmienia właściciela i/lub grupę danego zasobu.

Dla przykładu:

chown user plik

Ta komenda zmieni właściciela zasobu “plik” na użytkownika o nazwie user.

chown user:grupa plik

Taka komenda zmieni właściciela zasobu “plik” na użytkownika o nazwie user, a grupę mającą dostęp na taką o nazwie “grupa”.

Przydatny jest tutaj głównie przełącznik -R co oznacza z angielskiego recurssive, czyli zmieni właściciela rekurencyjnie.

grep – z angielskiego:  Global Regular Expression Parser, co tłumaczone wprost oznacza tyle co: globalny (czyli taki główny) parser wyrażeń regularnych.

Pomaga to nam przeszukiwać dane “wypluwane” z jednego programu przeszukać w poszukiwaniu pewnych wzorców w tekście. Na koniec tego dokumentu będzie szersze omówienie tej kwestii.

Przydatne przełączniki:

  • r(ecurssive) – rekurencyjnie w sensie katalogów, przeszukuje listing katalogów w poszukiwaniu takich nazw co pasują do tego wyrażenia, które program otrzymał na stdin,
  • i(gnore case) – ignoruj wielkość liter, Linux jest systemem case-sensitive, czyli to czy litera w nazwie zasobu jest duża czy też mała ma znaczenie,
  • o(nly-matching) – tylko pasujące do tego w sensie stricte co pasuje do wyrażenia regularnego, nic poza tym, a wszystkie twarde spacje(entery), tabulacje itd zostają “wycięte”.
  • v – z angielskiego: re(V)ert match, czyli odwróć wynik, względem tego co podano na stdin.

less – z angielskiego: mniej, nie ma konkretnego znaczenia względem funkcjonalności programu. Pomaga przeglądać zawartość długiego pliku w sposób wygodny poprzez sterowanie pozycji tekstu strzałkami lub klawiszami PgUp, PgDown, Home, End.

more – starsza wersja less, robi to samo, ale jest bardziej oporne w kwestii obsługi.

env – wyświetla zmienne środowiskowe aktualnie znajdujące się w pamięci shella.

export – pozwala ustawić nową zmienną środowiskową globalną (więcej informacji, gdy będzie taka potrzeba)

source – przeładuje zmienne środowiskowe i uruchomi procedury używając do tego pliku ./bashrc umieszczonego zwykle w katalogu domowym użyszkodnika

clear – czyści konsolę

reset – resetuje terminal (tty), który mu wskażemy, jeśli brak, zresetuj ten z poziomu, którego wywołuejmy komendę. Przydaje się po zmianach zmiennych środowiskowych, w sytuacji, gdy plik ./bashrc zawiera też skrypty lub linkuje do skryptów, których nie chcemy wywoływać w trakcie działania.

 

Edytory tekstu

Standardowo w systemach na kernelu Linux zawarte są 2 podstawowe edytory tekstu w trybie tekstowym:

  • nano,
  • vim.

Ten pierwszy jest prostszy w obsłudze, ale na początek, zaś vim jest chętniej używany do zaawansowanych edycji tekstów np. kodu programu w Python czy w C, głównie ze względu na dużą ilość plug-inów oraz dużą ilość skrótów klawiszowych ułatwiających pracę.

nano

Podstawowo wpisujemy nano a jako argument użyjemy nazwę pliku, który chcemy otworzyć(jeśli go nie ma stworzyć).

Skróty są wypisane na dole i opisane, a podstawowe to:

  • Ctrl+O(ut) – zapisz do wskazanej lokalizacji,
  • Ctrl+W(hereis) – znajdź pasujące sekwencje znaków,
  • Ctrl+(e)X(it) – wyjdź nie zapisując, użytkownik będzie zapytany o zapisanie, jeśli status pliku jest “unsaved”.
  • Ctrl+Z – “wyrzuć” nano w tło.
  • Cltr+Shift+6 – wprowadź karetę edytora w tryb zaznaczania tekstu, sterujemy strzałkami.
  • Ctrl+K – wytnij to co zaznaczone.

Skrótów jest więcej, ale te są podstawowe i zwykle wystarczające na początek.

vim

Podstawowo wpisujesz vim a na argument nazwę pliku… no tak jak wyżej po prostu.

Wejdziesz na główną stronę edytora. Aby wejść w tryb edycji tekstu należy wcisnąć Insert lub i. Aby z niego wyjść wciskamy Esc (przejście do trybu komend).

Po wejściu w tryb edycji, piszemy normalnie tekst.

Aby wydawać komendy wciskasz “:” w trybie komend, czyli po wyjściu z trybu edycji. Następnie wpisujesz komendę.

Na przykład, aby zapisać coś: :w.

Jeśli wywołałeś vima poprzez “vim” bez nazwy pliku to tutaj po tej komendzie po spacji należy wprowadzić nazwę pliku:

:w plik

Aby wyjść: :q .

Jeśli coś edytowałeś, ale chcesz siłowo wyjść wpisz: :q!

A zapisać i wyjść: :wq .

Aby zaznaczyć dowolną ilość rzędów i kolumn należy wcisnąć Esc(wyjść z trybu edycji), a potem wcisnąć Ctrl+v. Wciśnięcie Esc zresetuje zaznaczanie.

Wklejenie tekstu ze schowka: Ctrl+Shift+V.

Aby porzucić wszelkie zmiany a następnie siłowo wyjść: wpisujesz: :aq!

Tak jak wcześniej: w pochodzi od write, q od quit, zaś a od abandon.

Uwaga ogólna:

Te komendy są identyczne dla terminala zarówno z trybu tekstowego (CLI) jak i tego co jest dostępny przez emulator terminala w trybie graficznym (GUI).

W momencie gdy jesteś w trybie graficznym to tak na prawdę i tak jesteśmy na którejś z linii wejścia powłoki, zwykle w przypadku forków Debiana będzie to tty7.

Aby przełączać się między terminalami wystarczy, że wciśniesz:

  • w trybie graficznym: Ctrl+Alt+Fx gdzie x to numerek linii wejścia, gdzie masz wybór od 0 do 9,
  • w trybie tekstowym: Alt+Fx, analogicznie.

 

Coś więcej na temat wyrażeń regularnych

Wyrażenia regularne to coś czego na pewno nie chcesz pamiętać, ale warto wiedzieć co to znaczy oraz jak stworzyć te najprostsze.

Jeśli chodzi o to gdzie możemy tego użyć, możemy tego użyć wszędzie tam, gdzie mam dużo tekstu, który na pewno zawiera pewne wartości jak litery duże, małe, cyfry, znaki specjalne.

Na przykład: jest taki folder, że zawiera on w sobie 1000 plików, który każdy jest nazwany wg. następującej reguły: plik<numer_pliku>. Zatem nazwy będą wyglądać tak:

plik1, plik2, plik3, … plik1000. Teraz pomyśl, że musisz usunąć tylko te, które zawierają cyfrę “5”. Tak jakby ręcznie to będzie to dość mozolne, a z kolei jak inaczej? Najprościej można to zrobić poprzez regex (czyli wyrażenie regularne): plik*5*

Gwiazdka oznacza dowolnie długi ciąg dowolnych znaków. Zatem wszystko co zawiera 5 na dowolnym miejscu zostanie usunięte używając tej komendy:

rm plik*5*

Jest to bardzo proste regularne wyrażenie. Jak widać w przykładzie, większość komend potrafi takowe przyjąć, ale głównie kończy się to na możliwości dopasowywania dowolnej sekwencji znaków, czyli interpretuje tylko “*”.

Taki “prawdziwszy” regex wygląda np. tak: \[0-9A-Za-z]\.

Taki regex dopasuje każdą taką sekwencję znaków w skład, której wchodzą następujące symbole:

  • litery duże,
  • litery małe,
  • cyfry.

W ilości dowolnej, w kolejności dowolnej.

Jak tego użyć? Aby tego użyć musimy to wstawić jako argument komendy “grep”, ale grep musi mieć w takim razie też co sprawdzać, czyli musi dostać na stdin jakiś data stream (strumień danych).

Operatory

W shellu Linuxa występują różne operatory, dla nas najważniejsze są te:

  • > (redirect stream overwriting),
  • >> (redirect stream appending),
  • | (pipe).

Nawiązując do tego co pisałem wyżej o grepie to można mu po prostu wskazać dane jako argument, co jest mało wygodne zwykle, bo rzadko “grepujemy” pliki a teksty często są dłuuuuugie. A, z kolei kopiowanie tego co zwraca komenda do pliku jest średnio wygodne i zaśmiecamy dysk. Tutaj chętnie wykorzystamy operator “pipe”.

Ten operator powoduje, że to co komenda występująća po jego lewej stronie drukuje na stdout, to jest przerzucane automatycznie na stdin tej komendy po prawej stronie. Zatem zakładając, że chcemy mieć tylko pliki ze znakami alfanumerycznymi z danego katalogu prosto to zrobimy taką komendą:

ls -a | grep “0-9A-Za-z”

Dwa pierwsze operatory to operatory przekierowania streamu danych z stdout programu wywołanego po jego lewej stronie do lokalizacji w systemie plików(czyli po prostu na dysku najczęściej) wskazanej po jego prawej stronie. Pojedynczy operator oznacza, że dane w lokalizacji docelowej zostaną nadpisane, zaś podwójny oznacza, że dane zostaną dopisane na koniec pliku od nowej linii.

Na zakończenie…

To tyle w tym wpisie. Mam nadzieję, że wyjaśniłem to w miarę jasno, ale i na tyle rzetelnie, że rozumiesz co tak na prawdę robisz w momencie wydawania komend w shellu systemów bazujących na Linuxie. Najpewniej będę jeszcze uszczeguławiał ten post, ale również napiszę jeszcze jeden post, o bardziej zaawansowanych praktykach używania shella.

Trzymaj się tam na tych studiach, jebla idzie tam dostać!

 

 

 

 

 

Kurs Java #3: Klasy i metody [PL]

Wprowadzenie

W 2. części kursu wyjaśniłem w sposób ogólny pojęcie obiektowości oraz podałem przykłady na to jak to wygląda w Javie, wyłożyłem terminologię i pojęcia dotyczące tego paradygmatu. Zastanawiasz się Czytelniku zapewne jak tworzyć taki obiekt “samemu”.

Czym jest klasa, a czym metoda?

Klasa to wydzielona część programu, która jest definicją dla obiektów oraz dla ich właściwości i zachowań. Za te zachowania i zmiany właściwości obiektu danej klasy odpowiadają tzw. metody. Z definicji metoda to podprogram, który wykonuje pewne operacje na parametrach wejściowych, a następnie zwraca wynik tych operacji w postaci zmiennej lub instancji (obiektu) konkretnej klasy(niezawsze musi być konkretny typ, w pewnych przypadkach nie musi być, ale to nie temat na kurs podstaw).

Budujemy klasę…

Rozpatrzmy następujące zdanie:

Klasa Scanner udostępnia mi konstruktor dzięki, któremu mogę spokojnie utworzyć obiekt tejże klasy.

A teraz “pokazuję i objaśniam”(Copyright©Wojciech Cejrowski 2017):

  • klasa Scanner – udostępnia programiście języka Java metody i stałe; jest jedną z wielu klas wewnętrznych Java API. Jej zadaniem jest obsługa std::in i std::out(stream wejścia i stream wyjścia),
  • konstruktor – to specjalna metoda, która posiada modyfikator(za chwilkę wyjaśnię!) dostępu (z angielskiego: access modifier), a jej nazwa jest dokładnie taka sama jak nazwa klasy, w której się znajduje,
  • obiekt – no tego chyba nie muszę już wyjaśniać, choć w tym kontekście oznacza to byt, który posiada wszystkie definicje właściwości typowe dla klasy, którą reprezentuje.

Punkta wejścia – metoda main()

Każda klasa, która chcemy by była oznaczona jako “runnable”(ang. “uruchamialna”) musi posiadać w swoim ciele metodę main(String[] args).

Jej definicja wygląda zawsze tak samo:

public static void main(String[] args){}

Dzięki występowaniu tej klasy w kodzie kompilator może “wejść” do naszego kodu, czyli oznacza to dla niego punkt startowy w trakcie przeprowadzania procesu kompilacji, ale także używane to może być w innych funkcjach np. testach globalnych. Kompilator nie zaczyna procesu kompilacji od tej metody, tak na prawdę po sparsowaniu i interpretacji, kompilator w trakcie kompilacji, wykonuje niektóre fragmenty kodu i w tej fazie kompilacji, zaczyna od tej metody. Natomiast logicznie ta metoda jest punktem wejściowym klasy, w której się znajduje.  Metoda main() nie wyznacza JVM miejsca “wejścia”, to zadanie spełnia w naszej aplikacji plik: MANIFEST.mf. W nim jest zapisana główna klasa naszej apki stąd klas posiadających w ciele metodę main() może być więcej jak 1, aczkolwiek nie powinno się tego tak rozwiązywać.

No to teraz troszkę w praktyce

Podstawowa definicja klasy wygląda tak:

class Klasa{
}

No, także tak się definiuje klasę w Javie. Jest to najprostszy z możliwych przykładów.
Notka: To co jest pomiędzy nawiasami klamrowymi nazywamy “ciałem klasy“.

Rozszerzmy teraz trochę nasz przykład:

public class Klasa{
     public Klasa(){}
}

Ten kod powyżej od tego pierwszego różni się tylko jednym słowem kluczowym: public oraz tym co jest w ciele klasy Klasa.

Cóż to takiego jest? A to jest właśnie owy modyfikator dostępu, o którym wspominałem wyżej.

W Javie są 3 modyfikatory dostępu:

  • public – oznacza publiczny dostęp dla każdego obiektu(czy z naszej aplikacji czy spoza niej),
  • protected – oznacza określenie dostępu tylko dla klas, które są w konkretnej relacji z inną klasą; relacja ta to tzw. dziedziczenie – wyjaśnię to za chwilę,
  • private – ogranicza dostęp do zasobu danej klasy tylko dla obiektów i metod znajdujących się w obrębie tej klasy.

Domyślnie w Javie jeśli coś nie ma modyfikatora dostępu to automatycznie jest to publiczne w zakresie paczki.

Zmienne globalne oraz słowo kluczowe “static”

Zmienne globalne to takie, które znajdują się bezpośrednio w ciele klasy. Mogą posiadać one swój własny modyfikator dostępu. Ich nazwę zazwyczaj piszemy w ten sposób: globalVariableName. Natomiast w przypadku zmiennych globalnych posiadających słowa kluczowe: static, final lub oba na raz zapis nazwy powinien być utrzymany wg. następującej konwencji: GLOBAL_CONSTANT_VARIABLE.

Klasy, metody, zmienne globalne mogą zostać statycznie alokowane w pamięci, czyli mogą zajmować dany adres fizyczny od momentu rozpoczęcia działania programu aż do jego zakończenia. Aby tego dokonać musimy dodać słowo kluczowe static zaraz po modyfikatorze dostępu. Przykład będzie w kodzie pokazującym praktyczne użycie klas, konstruktorów i metod.

To teraz użyjmy tego, co już wiemy

Stworzyłem przykładową klasę, która będzie reprezentować człowieka. Przykład znajduje się na GitHubie.

W tym przykładzie dokładnie pokazane jest jak stworzyć klasę, konstruktor, jak stworzyć obiekt przy pomocy tego konstruktora oraz jak wyglądają zmienne globalne.

Jak widzisz w kodzie zmienne typu String można dodawać do siebie przy pomocy operatora “+”. To nie spowoduje dodawania wartości byte’owych tych Stringów, a zwykłe sklejenie tego tekstu ze sobą. Dodatkowo, jeśli spowodujesz dodanie wartości stringowej do wartości liczbowej np. do zmiennej typu int to kompilator “w locie” przekonwertuje zmienną liczbową do tekstu prostego.

Dziedziczenie

W obiektówce bardzo istotny jest termin dziedziczenia. Co to znaczy? Znaczy to mniej więcej tyle, że jedna klasa dziedziczy po drugiej klasie metody i pola – wszystkie te, które nie są prywatne.

W Javie dziedziczą po sobie klasy tylko i wyłącznie. Dokonuje się tego poprzez słowo kluczowe extends. 

Przykład:

import course.java.Human;
public class Student extends Human{
    
}

W tym momencie w klasie Student są już dostępne metody klasy Human, gdyż klasa Student dziedziczy je po niej. Zawsze może dojść jednak do sytuacji w, której będziemy chcieli zmienić sposób funkcjonwania danej metody. Wtedy mówimy o tzw. przesłonięciu metody. W kodzie wykonuje się to przy użyciu znacznika @Override .

W tej klasie wszystko jest prawie takie samo prócz jednej zmiennej globalnej: CLASS.

Następnie metoda printPersonalInfo jest przesłonięta, przez co wezwanie jej na obiekcie klasy Student spowoduje wywołanie tej metody znajdującej sie w ciele klasy Student. Nie jest to powiązane z użyciem anotacji @Override, ta anotacja informuje tylko kompilator, że metoda jest dziedziczona po klasie nadrzędnej oraz oczywiście programistę. Daje to też nam pewność, że nie dojdzie do zjawiska zwanego rekurencją.

Polimorfizm

Polimorfizm pochodzi od cechy biologicznej według, której organizmy pochodzące od jednego gatunku organizmu po prostu w efekcie dziedziczenia, posiadają zestawy cech podobnych dla prototypu. Tak samo jest z klasami w Javie. Dzięki dziedziczeniu, możemy tworzyć tzw. rodziny klas, dzięki czemu zestaw klas, a potem zestaw utworzonych od nich obiektów ma te same właściwości i/lub cechy.

Ułatwia to tworzenie zaawansowanych projektów, powoduje, że kod jest czystszy, skalowalny, łatwiejszy do optymalizacji w trakcie rozwoju oprogramowania.

Przykładowy kod zbudowany w oparciu o klasę podaną wcześniej znajduje się tutaj.

W nim w prosty sposób postarałem się pokazać jak działa polimorfizm w Javie.

Rekurencja

Jeśli posiadasz podstawową wiedzę z zakresu ciągów w matematyce to wiesz, że istnieją tam ciągi rekurencyjne. Oznacza to, że wartość wyrazu An jest zależna od wartości wyrazu An-1, czyli wyrazu mniejszego o różnicę/iloraz danego ciągu, gdzie pewne jest, że dana zależność jest stała dla całego ciągu(dla sumy wyrazów ciągu S).

W programowaniu natomiast pojęcie to mówi o algorytmie, który wylicza kolejne n wyrazów danego ciągu właśnie na podstawie wartości wyrazu poprzedniego. Metoda ta jest często nie do zastąpienia poprzez pętle, jednak jeżeli tylko istnieje możliwość by zrezygnować z jej użycia, należy to zrobić, chyba, że wiemy jak spowodować by rekurencja była wydajniejsza od pętli. Niedoświadczony programista może spowodować w ten sposób poważne, często krytyczne błędy w pracy programu, albo nawet systemu operacyjnego.

W przypadku kodu opisującego obliczenie kolejnych wyrazów ciągu np. arytmetycznego poważnym błędem będzie nie podanie warunku kończącego działanie programu. Z kolei w przypadku bardziej zaawansowanych programów spowoduje to błąd zwany stack overflow, czyli przepełnienie stosu.

Najprostszy algorytm prezentujący działanie rekurencji może wyglądać tak:

//ciało klasy
    public static void main(String[] args){
        System.out.printlin("Tekst.");
        main(null);
    }

Taki kod będzie wykonywał się w nieskończoność, a jego wadą jest fakt, że w czasie rzeczywistym dodaje kolejne referencje aka wskaźniki na metodę main() co powoduje przepełnienie stosu.
Spróbuj skompilować i uruchomić ten program. Obiecuję, że komputer nie wybuchnie. A teraz spróbuj zrobić tak, aby ten program robił coś więcej, na przykład wyliczał n wyrazow jakiegoś, prostego ciągu arytmetycznego.

Klasy zagnieżdżone

W Javie istnieje pojęcie klasy zagnieżdżonej. Jest to taka klasa, która jest członkiem innej klasy, klasy publicznej, której nazwa jest zgodna z nazwą pliku .class, w którym się znajduje. Klasa zagnieżdżona moża być statyczną(static inner class) lub też niestatyczna(non-static inner class).

Klasa zagnieżdżona niestatyczna wygląda w ten sposób:

    public class Class2{
      class NestedClass{
      }
    }

Przykładowa klasa tego typu powinna wyglądać tak:

    public class Class{
      static class StaticNestedClass{}
    }

Jeśli chodzi o dostęp to obu z tych klas z zewnątrz to będzie on od siebie się trochę różnił.

Klasy statyczne zagnieżdżone osiąga się w dość logiczny sposób to jest:

Class.NestedClass cnc = new Class.NestedClass();

 

Natomiast obiekt klasy zagnieżdżonej niestatycznej osiąga się w następujący sposób:

Class2 cl2 = new Class2();
     NestedClass nc = cl2.new NestedClass();

Jak widać w przykładzie wyżej, aby uzyskać obiekt klasy zagnieżdżonej niestatycznej należy najpierw w sposób statyczny tj. przy użyciu konstruktora utworzyć obiekt superklasy, a następnie od niego poprzez słowo kluczowe “new” uzyskać obiekt klasy zagnieżdzonej używając jej publicznego konstruktora.

Dalsze omówienie klas i obiektowości będzie w odcinku 4. kursu.

Dzięki za uwagę, cześć!

 

Linux Mint vs mikrofon… [PL]

Linux Mint to system należący do rodziny systemów unix, a jego poprawna nazwa to GNU/Linux Mint. Należy do rodziny deb tj. był budowany na systemie Debian.

Ogółem rzecz ujmując Mint to dobry system dla osoby próbującej przesiąść się na Linuxa bez wkopywania się po uszy w konfigurację systemu.

Jednakże Mint ma swoje wady, które potrafią być irytujące. Mianowicie, jedną z nich, która najbardziej mnie dotknęła, jest problem z dźwiękiem. Ta dystrybucja Linuxa całkowicie nie radzi sobie z obsługą servera dźwięku jakim jest pulseaudio, a samo alsa działa tak jakby chciało a nie mogło.

Jednym z najbardziej trudnych do ogarnięcia tematów jest sprawa mikrofonu wbudowanego w słuchawki.

Istotne jest to, że Mint taki mikrofon widzi, czyli warstwa sprzętowa o nim “wie”. Jednakże jeśli spróbujemy podłączyć mikrofon pod jakiś program okaże się, że nie jest to możliwe.

W przypadku Linux Mint problem ten łatwo rozwiązać poprzez zainstalowanie jednego z dwóch programów, dlatego, że Mint sam w sobie nie potrafi obsłużyć jack audio-in, zatem potrzebuje zewnętrznego oprogramowania, które zrobi robotę za niego.

Alternatywa numer 1

Najprostszy możliwy sposób to zainstalować server obsługujący wejścia jack np. qjackctl. Są dwie wersje v1.0 oraz v.2.0. Należy sprawdzić obie w razie, gdyby jedna z nich nie działała, wszystko jest zależne od wersji Minta(a bardziej kernela). Aby go zainstalować wystarczy wejść w konsolę i wpisać:

sudo apt install qjackctl

To zainstaluje nam paczkę w systemie. Następnie powinna być ona dostępna również z poziomu naszego DE, w przypadku Cinnamon wygląda to tak:

Screenshot from 2017-12-31 14-49-18

Jeśli u Ciebie jest ten program również dostępny to uruchom go.

Wtedy powinno się pojawić takie okno:

Screenshot from 2017-12-31 14-50-18

Oczywiście tutaj klikamy Start i możemy spokojnie podłączyć mikrofon do dowolnego programu.

Notka: W tym momencie to qjackctl dzierżawi wszystkie jacki na Twoim komputerze, system nie ma już kontroli nad nimi. Jeśli zatem chciałbyś sobie słuchać czegoś z YouTube rozmawiając przez Skype czy Discord należy “uświadomić” o tym qjackctl poprzez odpowiedni panel:

Screenshot from 2017-12-31 14-53-31

W tym okienku można łączyć w różny sposób wyjścia i wejścia sygnału dźwiękowego tak, aby odpowiadało to naszym potrzebom.

Alternatywna numer 2

Wpierw musisz zainstalować program Patchage. Możesz to zrobić zarówno pobierając paczkę z ich strony albo też uzywając tej komendy:

sudo apt install patchage

W tym momencie dokładnie tak samo jak w przypadku qjackctl powinieneś mieć ten program dostępny w menu. Otwórz go.

Program automatycznie podłączy się pod jacki, zatem jeśli czegoś słuchasz to nie zdziw się, że nagle przestanie grać.

W tym momencie, jeśli jakikolwiek program zażąda podłączenia mikrofonu, patchage obsłuży to żądanie i będziesz mógł spokojnie nagrywać, jednak tak samo jak w przypadku qjackctl nie możesz słuchać na bieżąco zatem, aby to umożliwiść musisz w odpowiedni sposób połączyć żródło playback z wyjściem.

Notka: Z pewnych powodów możesz w ogóle nie mieć źródeł dźwięku widocznych w patchage, w takim przypadku musisz kombinować, albo pogodzić się z tym, że nie masz mikrofonu i playbacku na raz…