REKLAMA
Jeżeli jesteś zainteresowany/a reklamą swoich produktów w naszym magazynie Jeżeli jesteś zainteresowany/a wypromowaniem swojej marki wśród specjalistów IT Jeżeli szukasz klientów lub pracowników Zareklamuj się u nas!
Posiadamy bazę 90 tysięcy specjalistów z różnych działów IT! W celu uzyskania oferty reklamowej skontaktuj się z nami: sdjpl@sdjournal.pl tel. 799 46 34 76
Java SE 8
4
MARCIN MICHALSKI
Java SE 8 jest w środowisku programistów Java najbardziej oczekiwaną wersją platformy od 2004 roku. Otrzymamy nie tylko nowe funkcjonalności i poprawki API, ale wprowadzone zostaną również nowe elementy składni języka Java. Przyjrzyjmy się bliżej nowej wersji Java SE 8!
Injection po raz kolejny…
12
Marek Puchalski
Open Web Application Security Project (OWASP) jest społecznością skupiającą osoby, instytucje i organizacje zainteresowane poprawą bezpieczeństwa aplikacji webowych. W ramach realizowanych przez OWASP projektów tworzone są narzędzia, dokumenty i procesy wspomagające pracę przy tworzeniu systemów. Dobrze o tym pamiętać, aby w różnych sytuacjach nie wynajdywać koła na nowo, tym bardziej że oferowane zasoby wspomagają pracę nie tylko deweloperów i architektów, lecz również testerów i menadżerów projektów.
18
Strefy czasowe w Javie i bazach danych? Marek Berkan
Jak pamiętamy ze szkoły podstawowej, Ziemia obraca się wokół własnej osi, co powoduje występowanie po sobie pory dnia i pory nocy. Raz na dobę ustawienie promieni słonecznych jest w zenicie (najwyższym punkcie względem horyzontu), co potocznie nazywamy „południem”.
26
Wehikuł czasu w komputerze, czyli o systemach kontroli wersji na przykładzie Subversion
Sławomir Andrzejewski
Artykuł przybliża Czytelnikowi koncepcje i strategie ozwoju oprogramowania przy wykorzystaniu systemów kontroli wersji. Oprócz zagadnień teoretycznych zaprezentowano podstawowe scenariusze pracy z Subversion.
38
Sposób na cyberprzestępców czyli jak się wyszkolić z bezpieczeństwa informatycznego
Kamil Brzeziński
www.sdjournal.pl
Najsłabszym ogniwem bezpieczeństwa jest paradoksalnie człowiek. Nawet najbardziej zaawansowany system informatycznych zabezpieczeń nie sprawdzi się w walce z hakerami, jeśli jego użytkownik sam nie zadba o poufność przetwarzanych danych.
Software Developer’s Journal
Redakcja dokłada wszelkich starań, by publikowane w piśmie informacje i
jest wydawany przez
programy były poprawne, jednakże nie bierze odpowiedzialności za efekty
NPRACA Sp. z o.o.
wykorzystania ich; nie gwarantuje także poprawnego działania programów
Redakcja: sdjpl@sdjournal.pl
shareware, freeware i public domain.
Kierownik produkcji: Andrzej Kuca
Wszystkie znaki firmowe zawarte w piśmie są własności odpowiednich firm. Zostały użyte wyłącznie w celach informacyjnych.
Adres korespondencyjny:
Osoby zainteresowane wspópracą prosimy o kontakt:
NPRACA Spółka z o.o.
sdjpl@sdjournal.pl
ul. 3 Maja 46, 72-200 Nowogard, Polska Oddział w Warszawie:
Skład i łamanie / projekt okładki:
ul. Postępu 17 D, 02-676 Warszawa, Polska
Digital Concept
www.sdjournal.pl
www.digitalconcept.pl admin@digitalconcept.pl
Facebook: https://www.facebook.com/SoftwareDevelopersJournal
Java SE 8
Java SE 8 jest w środowisku programistów Java najbardziej oczekiwaną wersją platformy od 2004 roku. Otrzymamy nie tylko nowe funkcjonalności i poprawki API, ale wprowadzone zostaną również nowe elementy składni języka Java. Przyjrzyjmy się bliżej nowej wersji Java SE 8!
Dowiesz się
Powinieneś wiedzieć
Czym są wyrażenia lambda, poznasz nowe elementy języka Java oraz nowe możliwości wielowątkowego przetwarzania danych.
W
2004 roku światło dzienne ujrzała Java SE 5. Otrzymaliśmy tak bardzo oczekiwane typy generyczne, enumeracje, pętlę foreach, autoboxing, możliwość definiowania metod ze zmienną liczbą parametrów... Śmiało można powiedzieć, że mieliśmy do czynienia z rewolucją w programowaniu w języku Java, jakości kodu oraz jakości tworzonych przez nas aplikacji. Następne rewizje przynosiły raczej kosmetyczne zmiany - poprawki w API, bugfixy, implementacje nowych funkcji języka dyskutowanych w ramach Java Community Process, jednak sama składnia języka nie zmieniła się prawie wcale. W 2010 roku pojawiły się pierwsze oficjalne dokumenty opisujące szczegóły wprowadzenia domknięć (closure) dla języka Java w ramach Lambda Project – długo oczekiwanych przez programistów. Po rezygnacji z wprowadzenia domknięc w siódmej wersji platformy Java, Java SE 8 nareszcie wprowadza Project Lambda pod strzechy!
Project Lambda
Project Lambda powstał w celu rozwiązania „problemu wertykalnego” w Java. Zarówno Java API jak i wiele bibliotek i frameworków Java wykorzystuje technikę wywołań zwrotnych realizowanych poprzez interfejsy zawierające tylko jedną metodę (SAM Type – Single Abstract Method Type). Implementacja takiego interfejsu często realizowana jest poprzez anonimowe klasy wewnętrzne: button.addActionListener(new ActionListener() {
4
@Override
Czym jest dziedziczenie i typy generyczne. Powinieneś posiadać praktyczną wiedzę z zakresu kolekcji w języku Java oraz znać zagadnienie przetwarzania wielowątkowego.
public void actionPerformed(ActionEvent e) {
long when = e.getWhen();
System.out.println(″Action prformmed at:″ +
});
Date whenDate = new Date(when);
}
whenDate.toString());
Przykład 1
Implementacja właściwej logiki wymaga dodatkowego, powtarzalnego kodu niepotrzebnie wydłużającego kod proste wywołania metod. Wykorzystując nowe wyrażenia lambda powyższa implementacja wyglądać będzie następująco: button.addActionListener(event -> {
long when = event.getWhen();
System.out.println(″Action performmed at:″ +
});
Date whenDate = new Date(when);
whenDate.toString());
Przykład 2
Stosując wyrażenia lambda możemy pozbyć się nadmiarowego kodu i skupić na implementacji logiki systemu. Kod staje się zdecydowanie bardziej czytelny. Przyjrzyjmy się szczegółom implementacji i zobaczmy jak to działa! Wyrażenia lambda są ściśle związane z interfejsami funkcyjnymi – nowym pojęciem wprowadzonym w Java SE 8. Interfejs funkcyjny jest to interfejs definiujący dokładnie jedną metodę abstrakcyjną. Przykładem 1/2014
JAVA SE 8
takiego interfejsu jest wykorzystany w przykładzie 1 Przy czym słowo definiujący nie oznacza, że interfejs nie może posiadać większej ilości metod. Interfejs może definiować dowolną ilość metod, jednak pozostałe metody abstrakcyjne muszą być nadpisywane przez klasę java.lang. Object. Mówiąc prościej – interfejs funkcyjny może posiadać tylko jedną metodę, która nie została zadeklarowana w klasie java.lang.Object java.awt.event.ActionListener.
@FunctionalInterface
public interface Comparator<T> { }
int compare(T o1, T o2);
boolean equals(Object obj);
Przykład 3
Kompilator automatycznie rozpoznaje interfejsy funkcyjne, jednak dla celów informacyjnych została wprowadzona adnotacja @FunctionalInterface Java SE 8 wprowadza nowy pakiet java.util.function zawierający podstawowy zestaw interfejsów funkcyjnych reprezentujących podstawowe funkcje: • • • • • •
– testowanie własności obiektu – dla obiektu zwracana jest wartość boolean Consumer<T> - wykonanie akcji na obiekcie bez zwracania wartości Function<T,R> - funkcja zwracająca obiekt typu R na podstawie obiektu T Supplier<T> - konstruktor, fabryka obiektów typu T UnaryOperator<T> - funkcja zwracająca obiekt typu T – obpowiednik Function<T,T> BinaryOperator<T> - funkcja zwracająca obiekt typu T, przyjmująca dwa argumenty typu T Predicate<T>
Dodatkowo dostępne są specjalizacje powyższych interfejsów, np. specjalizacje interfejsów dla typów prymitywnych int, long oraz double – pozostałe typy można uzyskać poprzez rzutowanie. Zobaczmy jak teraz zbudowana jest deklaracja wyrażenia lambda. Składa się z następujących elementów: 1. Deklaracja argumentów wejściowych metody interfejsu funkcyjnego oddzielonych przecinkami 2. Operatora -> 3. Ciała wyrażenia zawierającego jedną komendę lub blok kodu zawartego w nawiasach klamrowych { }. Zastosowania wyrażeń prezentują poniższe przykłady (String a, String b, String c) -> () ->
13;
www.sdjournal.pl
+ b + ″ ″ + c;
″Hello ″ + a + ″ ″
(String a, String b) -> (String a, String b) ->
{System.out.println(a+b)}; {return a+b};
Pierwsze wyrażenie przyjmuje 3 argumenty typu String i zwraca ich konkatenację. Drugie wyrażenie nie przyjmuje żadnych argumentów i zwraca typ int Trzecie wyrażenie przyjmuje 2 obiekty typu String i wyświetla ich złożenie w konsoli. Ostanie wyrażenie przyjmuje 2 obiekty typu String i zwraca ich konkatenację. Warto zauważyć, że w składni wyrażenia lambda nie deklarujemy typu interfejsu funkcyjnego, a skoro język Java jest językiem silnie typowanym, powstaje pytanie jaki typ reprezentuje dane wyrażenie. Otóż typ wyrażenia wnioskowany jest z kontekstu. Oczywiście to samo wyrażenie lambda może być reprezentowane przez różne typy, przykład Callable<String> callable = c -> ″Kilroy was here!″;
PrivilegedAction<String> action = c -> ″Kilroy was here!″;
Kompilator sprawdza czy wyrażenie lambda może być reprezentowane przez dany typ następująco: • typ musi być interfejsem funkcyjnym • wyrażenie lambda posiada tę samą ilość parametrów co metoda interfejsu funkcyjnego i są one tego samego typu • typ zwracany przez wyrażenie lambda jest tego samego typu co typ zwracany przez metode interfejsu funkcyjnego • wyjątki rzucane w ciele wyrażenia lambda zdeklarowane są w metodzie interfejsu funkcyjnego Zatem jeśli chcemy uprościć naszą implementację i wykorzystywać wyrażenia lambda – najpierw musimy posiadać interfejs funkcyjny. Niestety nie mamy możliwości zdefiniowania generycznego typu, który przechowywałby po prostu referencję do funkcji. Kolejną konsekwejcją jest to, że wyrażenia lambda możemy deklarować tylko w przypadkach gdy istnieje odpowiedni kontekst dla określenia typu interfejsu funkcyjnego, czyli w następujących sytuacjach: • • • • • • • •
deklaracje zmiennych przypisanie wartości operacje return inicjalizacje tablic argumenty metod i konstruktorów w ciele wyrażeń lambda operator warunkowy ? : rzutowanie 5
Na początku wspomnieliśmy o tym, że wyrażenia lambda pozwalają zastąpić anonimowe klasy wewnętrzne. Warto zatem przypomnieć problem zakresu zmiennych i przesłaniania metod w klasach wewnętrznych, który często trapił programistów. Wyrażenia lambda nie są reprezentowane przez klasy wewnętrzne, nie dziedziczą żadnych metod czy zmiennych z typów nadrzędnych. Dostępna przestrzeń nazw definiuje tylko moment deklaracji. Rzućmy okiem na następujący przykład:
Runnable printThis = () -> { System.out.
przed zmianą implementacji – unikniemy nieprzyjemnych konsekwencji. Podsumowując - wyrażenia lambda oszczędzają czas programisty dając możliwość zastąpienia anonimowych klas wewnętrznych. I na taką rewolucję przyszło nam czekać 10 lat? Na pewno zmiany w składni języka upraszczają implementację, na pewno kod aplikacji będzie bardziej czytelny, jednak musimy nauczyć się korzystać z wyrażeń lambda i konsekwentnie wykorzystywać dostępne nowe interfejsy funkcyjne. Efekty przyjdą z czasem... Jednak to nie wszystko - zobaczmy jakie inne zmiany zostały wprowadzone w Java API i jak współgrają z nową filozofią wyrażeń lambda.
Runnable printToString = () -> { System.out.
Metody domyślne
Runnable printInnerClass = new Runnable() {
public class LambdaTest {
println(this); };
println(toString()); };
@Override
public void run() {
}
System.out.println(toString());
};
public String toString() {
}
public static void main(String... args) {
return «Kilroy was here!»;
new LambdaTest().printThis.run();
new LambdaTest().printInnerClass.run();
}
}
new LambdaTest().printToString.run();
Dzięki deklaracji wyrażeń lambda wewnątrz obiektu LambdaTest, staje się on przestrzenią nazw dla wyrażeń lambda. Po uruchomieniu aplikacji wywołanie printThis oraz printToString wyświetli na konsoli tekst ”Kilroy was hare!”, natomiast wywołanie printInnerClass wyświetli nam coś na kształt LambdaTest$1@17c264. Skoro ograniczna nas tylko moment deklaracji – co ze zmiennymi lokalnymi? Do tej pory dla klas wewnętrznych dostęp ograniczony był do finalnych zmiennych lokalnych. Java SE 8 wprowadza nowe pojęcie effective final local variable. Zmienną możemy określić jako effective final, jeśli jej wartość nie zmienia się od momentu deklaracji. W Java SE 8 dostęp do takich zmiennych lokalnych możliwy jest zarówno z poziomu wyrażeń lambda jak i anonimowych klas wewnętrznych! Powyższy przykład pokazuje, że przejście z klas wewnętrznych na wyrażenia lambda może doprowadzić do trudnych do wykrycia błędów. Jeśli nasz kod nie jest odpowiednio obłożony testami, warto o to zadbać 6
Rzućmy okiem na implementację interfejsu
Iterable<T>
public interface Iterable<T> {
Iterator<T> iterator();
default void forEach(Consumer<? super T> action) { Objects.requireNonNull(action); for (T t : this) {
}
}
}
action.accept(t);
Wzrok nas nie myli – interfejs zawiera implementację metody forEach. Stało się to możliwe, dzięki wprowadzeniu nowego elementu języka – metodami domyślnymi - default methods, określanymi również jako virtual extension methods lub defender methods. Jak zauważyliśmy wcześniej samo wprowadzenie wyrażeń lambda nie przyniesie rewolucji w sposobie programowania w języku Java. Konieczne jest umożliwienie wykorzystania nowych możliwości w istniejących już elementach języka. Jednak zmiana istniejących interfejsów pociągnęłaby za sobą konieczność zmiany implementacji, co praktycznie uniemożliwiałoby przejście ze starszych wersji języka. Metody domyślne umożliwiają rozszerzenie interfejsów bez konieczności zmian klas implementujących je implementacji. A jakie daje nam to możliwości? Zamiast dobrze znanej pętli foreach for (String string : list) { }
System.out.println(string);
Mamy możliwość wykorzystania wyrażeń lambda list.forEach(c -> System.out.println(c));
Przeglądając implementację innych interfejsów – np. interfejs java.util.Comparator nasuwa się wniosek. 1/2014
JAVA SE 8
Zgodnie z określeniem defender method, metody domyślne na daną chwilę największe zastosowanie znajdą przy refaktoryzacji pod kątem wyrażeń lambda i świetnie się w tym celu sprawdzają. W przypadku tworzenia nowej implementacji – bardziej przydatne będzie przemyślane i konsekwentne wykorzystanie interfejsów funkcyjnych. Interfejsy w języku Java rekompensowały brak dziedziczenia wielokrotnego – rekompensowały, ponieważ do tej pory interfejsy nie mogły zawierać implementacji metod. Czyżby Java SE 8 wprowadzała wsparcie dla wielokrotnego dziedziczenia? Nie do końca – dziedziczenie metod domyślnych odbywa się na tych samych zasadach co zwykłych metod, jednak z pewnymi wyjątkami: • Jeśli klasa dziedziczy więcej niż jeden interfejs definiujący metodę default o tym samym deskryptorze, występuje błąd kompilacji • Kolejność w jakiej interfejsy pojawiają się w deklaracji implements lub extends nie mają wpływu na mechanizm dziedziczenia • Metody zdefiniowane w klasach przesłaniają metody domyślne – nawet jeśli są to metody abstrakcyjne, bez względu na kolejność w hierarchii dziedziczenia • Przeładowana metoda domyślna jest pomijana – tracimy do niej dostęp Przyjrzyjmy się następującemu przykładowi public class Mammal {
public void speak() {
}
}
System.out.println(″I can’t speak″);
public interface Human {
default void speak() {
}
System.out.println(″I am a human″);
}
public interface Male {
default void speak() {
}
}
System.out.println(″I am a male″);
public class Person extends Mammal implements Human, }
Male {
Zgodnie z zasadami dziedziczenia dla klas domyślnych wywołanie metody speak() dla obiektu Person spowoduje wyświetlenie I can’t speak, ponieważ zwykłe metody przesłaniają metody domyślne. www.sdjournal.pl
Jeśli klasa Person nie będzie rozszerzać klasy tylko implementować interfejsy Human i Male, otrzymamy błąd kompilacji. Czyli dziedziczenie wielokrotne nie jest możliwe... jednak w takiej sytuacji istnieje możliwość wyboru, z której klasy metodę chcemy dziedziczyć, poprzez przeładowanie metody speak() Mammal,
public class Person implements Human, Male {
public void speak() {
}
}
Male.super.speak();
Zatem Java nadal stricte nie wspiera dziedziczenia wielokrotnego. Jednak tak długo jak deskryptory metod domyślnych będą różne, możemy zamiast rozszerzać mozolnie kolejne klasy, zaimplementować kilka interfejsów z metodami domyślnymi – przy czym będzie to raczej zła praktyka. public interface Human {
default void speak() {
}
}
System.out.println(″I am a human″);
public interface Male {
default void sing() {
}
System.out.println(″I am singing″);
}
public class Person implements Human, Male { }
Referencjonowanie metod
Kolejną nowością w składni języka Java jest możliwość stworzenia referencji do metody. Tworzenie referencji do metody odbywa się na takich samych zasadach jak tworzenie wyrażeń lambda – referencja do metody to instancja interfejsu funkcyjnego. Rzućmy okiem na interfejs Comparator<T>. Możemy przygotować instancję klasy comparator za pomocą wyrażeń lambda. Comparator<Person> comp = (a ,b) -> a.getName(). compareTo(b.getName());
Aby jeszcze uprościć deklarację, wykorzystajmy metodę domyślną Copmarator.comparing Comparator<Person> comp = Comparator.comparing(p -> p.getName());
Wykorzystujące referencje do metody deklaracja wyglądać będzie następująco 7
Comparator<Person> comp = Comparator.
comparing(Person::getName());
Jak widać różnica nie jest duża, jednak kod staje się bardziej czytelny – widzimy, że do porównania wykorzystujemy metodę getName z klasy Person. Możemy tworzyć referencje do następujących metod:
comparing(Human::getAge()); args)
List<Person> list = new ArrayList<>();
Person::getName
• konstruktorów – Person::new Parametry metody interfejsu statycznego stają się parametrami metod referencjonowanych, dzięki czemu możemy je dowolnie rzutować i korzystać z varargsów, np.: Comparator<Person> comp = Comparator. Runnable r = Example::main -
void main(String...
Consumer<Person> cons = Male::speak;
Referencjonowanie metod ułatwia wykorzystanie instniejących metod o deskryptorze identycznym z interfejsem funkcyjnym. public class PersonHelper {
public static int getAgeDifference(Person a,
}
}
Person b) {
return a.getAge() - b.getAge();
Comparator<Person> byAge =
PersonHelper::getAgeDifference;
Comparator<Person> byAgeLambda = (a, b) ->
PersonHelper.getAgeDifference(a, b);
W takich przypadkach referencje metod są zdecydowanie bardziej czytelne niż wyrażenia lambda. Miejmy nadzieję, że nowy element języka przyczyni się do poprawienia jakości kodu aplikacji – do tej pory nazbyt często prosty kod lądował bezpośrednio w ciele anonimowych klas wewnętrznych i powtarzany był w różnych miejscach w aplikacji. Referencje do metod, jako nowy element języka Java zachęca do zaprzestania tej złej praktyki.
Kolekcje w Java SE 8
Opisując metody domyślne wprowadzone w interfejsach w Java SE 8 wspomniałem, że ich głównym zasto8
Stream API
Do tej pory najwygodniejszym sposobem przetwarzania elementów kolekcji w Java były obiekty Iterator oraz pętla foreach – wykorzystująca zresztą iteratory. Z założenia takie przetwarzanie było sekwencyjne – elementy pobierane były jeden po drugim i przetwarzane. Strumienie (Stream) wprowadzają nowy sposób iteracji z wykorzystaniem operacji agregujących (aggregate operations). Ciekawostką jest to, że definiując takie operacje nie wykorzystujemy metody next() do której tak bardzo przyzwyczaiły nas iteratory. Przyjrzyjmy się przykładowi:
• metod statyczne - String::valueOf • metod instancji obiektu - person::getName • metod instancji obiektu określonego typu -
sowaniem jest rozszerzenie istenijących interfejsów i dostosowanie ich implementacji pod kątem wyrażeń lambda. Implementacja kolekcji przeszła największą metamorfozę za sprawą wprowadzenia wyrażeń lambda i metod domyślnych.
listOfPeople.stream()
.filter(p -> p.getAge() > 18)
.filter(p -> p.isUnemployed())
.forEach(p -> storePersonalData());
Powyższy kod z dostępnej listy obiektów typu Person wykona operację storePersonalData dla każdej bezrobotnej osoby powyżej 18 roku życia. Zauważmy, że korzystając ze strumieni i operacji agregujących nie definiujemy w jaki sposób mamy pobierać kolejne elementy, ale jakie operacje mają zostać na nich wykonane. Wykorzystujemy do tego celu wyrażenia lambda i referencje do metod. Sposób iteracji omówimy jednak za chwilę Zwróćmy uwagę na to, że cała logika została zamknięta w jednej „linii” kodu, dzięki wprowadzeniu możliwości łączenia operacji agregujących w potoki (pipelines) – na wzór potoków znanych z systemu UNIX. Potok składa się z następujących elementów: • źródło – może nim być kolekcja, tablica, generator obiektów (np. obiekt Iterator), kanał wejścia/wyjścia (IO channel) – np. zwracany przez metodę Files. lines(Path file)
• operacje pośrednie (intermediate operations)– operacje zwracające strumienie, np. operacja filter • operacja kończąca (terminal operation) – operacja kończąca potok, zwracająca obiekt nie będący strumieniem – np. kolekcję, lub przetwarzające elementy strumienia bez zwracania żadnej wartości – np. operacja forEach 1/2014
JAVA SE 8
Dostępne są następujące operacje pośrednie: •
super T> predicate) – operacja zwracająca strumień będący podzbiorem spełniającym określone kryterium, np.. filter(p ->
filter(Predicate<?
p.getAge() > 18)
•
map(Function<?
•
flatMap(Function<T,Stream<?
•
.sorted()
operacja zwracająca strumień skonwertowanych obiektów, np. map(p -> Unemployed::new) super
T,?
extends
extends
R>
R>>
mapper)
stream())
- operacja zwracająca strumień posortowany za pomocą istniejącej metody compareTo • sorted(Comparator<? super T> comparator) - operacja zwracająca strumień posortowany za pomocą określonego obiektu comparator • distinct() - operacja zwracająca strumień unikalnych obiektów. Do wykrywania duplikatów wykorzystywana jest metoda equals sorted()
Metody pośrednie mogą być dowlonie łączone, np. listOfPeople.stream()
.filter(p -> p.getAge() > 18)
.filter(p -> p.isUnemployed()) .distinct() .sorted()
Co również bardzo istotne, metody pośredie są metodami lazy – będą wywołane dopiero w momencie wywołania metody końcowej. Możemy zatem stworzyć potok bez metody końcowej i uzyskany strumień przetworzyć w późniejszym czasie. Dostępne są następujące operacje końcowe: forEach(Consumer<? super T> consumer) operacja przetwarza elementy strumienia bez zwracania żadnej wartości, np. forEach(p ->
•
void
•
<R> R collect(Collector<? super T,R> collector)
– operacja przetwarzająca strumień i zwracająca pojedynczą wartość lub kolekcję obiektów. Możemy zwrócić listę posortowanych obiektów Person
listOfPeople.stream()
.filter(p -> p.getAge() > 18)
.filter(p -> p.isUnemployed()) .distinct()
www.sdjournal.pl
• Optional<T>
reduce(T identity, BinaryOperator<T>
- operacja przetwarzająca strumień i zwracająca pojedynczą wartość. Możemy np. policzyć sumę wszystkich miesięcznych świadczeń osób bezrobotnych: accumulator)
mapper)
- operacja mapująca relację jeden do wiele na strumień. Wyobraźmy sobie, że obiekt Person posiada metodę zwracającą kolekcję obiektów typu Child, np. Collection<Child> getChildren(). Możemy zatem zwrócić strumień dal takiej kolekcji. W efekcie uzyskamy strumień wszystkich dzieci wejściowych obiektów Person, np. flatMap(p -> p.getChildren().
storePersonalData());
.collect(Collectors.toList())
listOfPeople.stream()
.filter(p -> p.getAge() > 18)
.mapToInt(p -> p.getMonthlyGrants())
.filter(p -> isUnemployed()) .reduce(0, (a,b) -> a + b)
• Iterator<T> iterator() - operacja zwraca iterator obiektów pozostałych po przetworzeniu potoku Zarówno dla operacji collect jak i reduce istnieją gotowe implementacji ciekawych funkcji. Dla operacji reduce, w zależności od typu strumienia, mamy dostępne, np. dla Strean<Integer> operacje arytmetyczne takie jak suma czy średnia. Operacje collect zawarte są w klasie Collectors. Do ciekawszych należą np. funkcje grouppingBy czy partitioning – zachęcam do lektury javadoc. Zobaczmy teraz w jaki sposóþ pobierane są elementy kolekcji. Zamiast jawnej iteracji (external iteration), mamy do czynienia z wewnętrzną iteracją (internal iteration) z wykorzystaniem obiektów Spliterator. Obiekt spliterator – podobnie jak Iterator sekwekncyjnie przetwarza elementy kolekcji, ale równocześnie umożliwia podział elementów kolekcji na mniejsze porcje za pomocą metody trySplit(). Efektem takiej operacji jest stworzenie podrzędnej instancji Spliterator, przy czym główny Spliterator pominie elementy przetwarzane przez obiekty podrzędne. Oczywiście możliwy jest dalszy podział podrzędnych instancji Spliterator, tak aby uzyskać odpowiednio małe porcje i przetwarzać je równolegle. Czyli przetwarzanie sekwencyjne się nie zmienia – Spliterator zastąpił Iterator. Natomiast przetwarzanie równoległe z podziałem Spliteratorów brzmi skomplikowanie – pula obiektów spliterator, pula wątków lub ForkJoinPool, przydział obiektów do przetworzenia, zebranie rezultatów cząstkowych... Nic podobnego! Z Java SE 8 równoległe przetwarzanie otrzymujemy za darmo! listOfPeople.parallelStream()
.filter(p -> p.getAge() > 18)
.filter(p -> p.isUnemployed())
.forEach(p -> storePersonalData());
9
Każdy strumień może być przetworzony równolegle, dzięki czemu w końcu w prosty sposób będziemy mogli wykorzystać potencjał wielordzeniowych maszyn. Jeśli prawo Moorea ma się obronić – rdzeni będzie coraz więcej, więc to bardzo dobra wiadomość. Jednak jeśli przetwarzanie nie wprowadzało prawie żadnych ograniczeń, tak w strumieniach równoległych (parallel stream) obowiązują już pewne reguły: • strumień musi być statyczny – kolekcja nie może być modyfikowana (elementy kolekcji nie mogą być dodawane, usuwane, przemieszczane) podczas przetwarzania. Operacje pośrednie również nie modyfikować kolekcji • po zakończeniu przetwarzania strumień nie może być ponownie wykorzystany • przetwarzanie strumieni z zachowaniem kolejności wymaga użycia specjalnej operacji końcowej forEachOrdered gwarantującej przetworzenie rezultatu dokładnie w kolejności w której znajdował się na wejściu strumienia. W przypadku użycia zwykłej metody forEach podczas przetwarzania równoległego – kolejność zostanie utracona • konieczność użycia metod collect odpowiednich do przetwarzania równoległego. Każdy obiekt Collector opisany jest przez enumerację Characteristics. Wymagane jest stosowanie obiektów Collector z charakterystyką CONCURRENT. Na pewno zmiany w Java Collections API zdecydowanie uproszczą kod naszych aplikacji – zwłaszcza tych wykorzystujących wielowątkowość. Funkcjonalności, które do tej pory wymagały implementacji kilku klas, będziemy mogli zamknąć nawet w kilku linijkach kodu. Jednak zanim zaczniemy wykorzystywać nowe API warto zagłębić się w szczegóły dokumentacji oraz przejrzeć implementację podstawowych obiektów Spliterator – jest duże pole do zwiększenia wydajności naszego kodu. Nie należy ulegać pokusie i wykorzystywać równoległego przetwarzania dla wszystkich strumieni. Zanim nasz kod trafi na docelowe środowisko, warto przeprowadzić porównawcze testy wydajnościowe rozwiązań wielowątkowych i sekwencyjnych.
Powtarzalne adnotacje (Repeating annotations)
Jednym z ciekawszych przykładów adnotacji w Java do tej pory była adnotacja @EJBs – jedyną jej rolą było grupowanie adnotacji @EJB
10
@EJBs({@EJB(name=″name1″,beanInterface=Type1.class),
@EJB(name=″name2″,beanInterface=Type2.class)})
Java SE 8 rozwiązuje ostatecznie ten problem przez prowadzenie powtarzalnych adnotacji – możliwe będzie uzycie jednej adnotacji wiele razy w tym samym miejscu. @EJB(name=″name1″,beanInterface=Type1.class) @EJB(name=″name2″,beanInterface=Type2.class)
Mała rzecz, a cieszy.
Adnotacje typów (Type Annotations)
Java 8 SE wprowadza możliwość dodawania adnotacji dla typów, np. @NotNull String text = ″test″;
@Readonly List<String> users = ...
public String getFullText(@Readonly Paper sheetOfPaper)
Celem wprowadzenia tych adnotacji była poprawa jakości kodu przez umożliwienie bardziej szczegółowej jego kontroli za pomocą narzędzi analizujących kod. Spójrzmy na przykład: Deklaracja metody public class Paper {
public String getText(@Readonly Paper
...
sheetOfPaper) {
Kod wywołujący metodę: @NotNull String text = sheetOfPaper.getText();
Zauważmy, że metoda getText może potencjalnie zwracać wartość null i przypisać ją do zmiennej zadeklarowanej jako @NotNull. Oczywiście kompilacja i wykonanie programu będzie działać prawidłowo. Możliwe jest natomiast wychwycenie potencjalnego problemu przez narzędzia analizujące kod takie jak CheckerFramework, Javarifier czy inne. Możliwość dodawania adnotacji typów na pewno sprawdzi się w zaawansowanych projektach z bardzo restrykcyjnymi normami jakościowymi i popartymi dobra analizą. Na pewno wywrą wpływ już na etapie projektowania klas i interfejsów – konieczne będzie nie tylko zaplanowanie nazw i struktur danych, ale także ich zachowania. Na pewno warto przyjrzeć się dostępnym rozwiązaniom wspierającym analizę kodu. Ciekawym testem byłby również pomiar czasu potrzebnego na analizę średniej wielkości projektu. 1/2014
JAVA SE 8
Java Date - Time API
Na koniec, wisienka na torcie. Istniejąca wersja Date - Time API oparta na klasie java.util.Calendar odchodzi do lamusa. Dostaliśmy dokładnie to o co prosiliśmy od lat. Po pierwsze, Java SE 8 wprowadza pakiet java.time gdzie znjadziemy wszystkie potrzebne klasy. Po drugie API jest przejrzyste, model prosty i pozbawiony wprowadzających zamieszanie metod. Pierwszy z góry przykład.
– czego przykładem są chociażby zmiany w Collections API. Czas pokaże, które z nowości przyjmą się w środowisku Java, a które będą musiały zostać jeszcze dopracowane. Jedno jest pewne – mamy nowe i dobre narzędzia, musimy nauczyć się z nich korzystać, czekamy na reakcję społeczności i na pewno czekamy na więcej!
LocalDateTime dt = LocalDateTime.now(); Calendar cal = Calendar.getInstance();
Metoda
niesie ze sobą jasny przekaz , a metoda hmm… singleton? A co ze strefami czasowymi? Spróbujmy obliczyć godzinę przylotu gdy poruszamy się po różnych strefach czasowych, gdzie lot trwa 8 godzin: now
getInstance
LocalDateTime now = LocalDateTime.now();
ZonedDateTime sydneyTime = dt.atZone(ZoneId. of(″Australia/Sydney″));
ZonedDateTime tokioTime = sydneyZoneTime.
withZoneSameInstant(dt.
atZone(ZoneId.of(″Asia/Tokyo″)));
ZonedDateTime tokioArrivalTime = tokioTime. plusHours(8);
Wykorzystując java.util.Calendar sami musielibyśmy obliczać przesunięcie między strefami tworząc dodatkowe obiekty TimeZone i przekazywać bieżącą datę w postaci wartości long, a wykonując operację przesunięcia czasu musielibyśmy użyć metody cal.add(Calendar. HOUR, 8). I jeszcze jedna dobra informacja. Klasa SimpleDateFormat również doczekała się następcy i tym razem jedną instancję swobodnie możemy używać w wielu wątkach! DateTimeFormatter dtf = DateTimeFormatter. ofPattern(″MM-dd-yyyy
dtf.format(tokioArrivalTime);
HH:mm″);
Geniusz tkwi w prostocie - po wielu latach w końcu doczekaliśmy się biblioteki wspierającej operacje na czasie!
Podsumowanie
Java SE 8 na pewno jest krokiem milowym w rozwoju języka java. Wyrażenia lambda zależne od interfejsów funkcyjnych na pewno nie dają pełnej elastyczności, ale są użyteczne i powinny rozwiązać problem wewnętrznych klas anonimowych. Wprowadzenie metod domyślnych do interfejsów, może nie wygląda zbyt elegancko, ale świetnie realizuje swoje cele www.sdjournal.pl
MARCIN MICHALSKI
Współtwórca i współwłaściciel marki Sagiton. Posiada 7 lat doświadczenia w programowaniu. Obecnie realizuje się jako System Architect w projektach wykonywanych przez ArrowGroup Sp. z o.o., której jest współzałożycielem. Ukończył Informatykę na Wydziale Elektroniki na Politechnice Wrocławskiej. Odbył kursy i szkolenia organizowane przez: Cisco Network Academy, Sun Microsytems, Oracle. Uzyskał certyfikaty eksperckie w zakresie sieci komputerowych, programowania (Java/JEE) oraz baz danych. Jest autorem licznych publikacji naukowych, prowadzi bloga technicznego. Marka: www.sagiton.pl [1] Kontakt: marcin.michalski@sagiton.pl Blog: marcin-michalski.pl [2]
11
Injection po raz kolejny… Open Web Application Security Project (OWASP) jest społecznością skupiającą osoby, instytucje i organizacje zainteresowane poprawą bezpieczeństwa aplikacji webowych. W ramach realizowanych przez OWASP projektów tworzone są narzędzia, dokumenty i procesy wspomagające pracę przy tworzeniu systemów. Dobrze o tym pamiętać, aby w różnych sytuacjach nie wynajdywać koła na nowo, tym bardziej że oferowane zasoby wspomagają pracę nie tylko deweloperów i architektów, lecz również testerów i menadżerów projektów.
D
ziś chciałbym wspomnieć tylko o jednym - choć pewnie najbardziej znanym - projekcie ze stajni OWASP, mianowicie o OWASP Top 10. Lista OWASP Top 10 jest listą dziesięciu najpopularniejszych błędów bezpieczeństwa znajdowanych w aplikacjach webowych. Istnienie listy ma skupić uwagę zespołów programistów na te zagrożenia, których pojawienie w projekcie jest najbardziej prawdopodobne, edukować oraz być punktem startowym do korzystania z narzędzi i projektów OWASP. Lista Top 10 aktualizowana jest przeciętnie co trzy lata, a ostatnia odsłona listy miała miejsce w czerwcu tego roku. Najkrótsza recenzja zmian dokonanych na liście OWASP Top 10 2013 brzmiała by: “nic nowego”. Wszystkie rozpoznane przez OWASP w roku 2010 zagrożenia pozostają nadal aktualne. Najnowsza odsłona listy bardzo dobrze pokazuje, że w pogoni za wypełnianiem wymagań funkcjonalnych nadal zdarza nam się zapomnieć o bezpieczeństwie tworzonej aplikacji. W epoce automatycznych skanerów, przeczesujących internet w poszukiwaniu luk, nie jest to krzepiący wniosek. Listę OWASP Top 10 2013 po raz kolejny otwierają błędy typu injection (z najznamienitszym ich reprezentantem - SQL injection (SQLi)) i to o nich chciałbym dzisiaj opowiedzieć.
Czym są błędy typu injection?
Najkrótsza, obrazowa (i nieoficjalna) definicja - błędy typu injection powstają wtedy, gdy oddajemy w ręce użytkownika aplikacji możliwość oprogramowania np. naszej bazy danych. Robimy to najczęściej nieświadomie poprzez konkatenację elementów naszego kodu z tekstem wprowadzonym do systemu. Rozpatrzmy następujące przykłady. Przykład 1: Runtime runtime = Runtime.getRuntime();
Process proc = runtime.exec(„find . -name „ + args[0]);
12
Z kodu naszej aplikacji próbujemy uruchomić komendę systemową dodatkową parametryzowaną przez użytkownika.
Czego oczekujemy?
Oczekujemy nazwy pliku lub katalogu, który ma zostać odnaleziony. Co może zrobić użytkownik? W zależności od fantazji może na przykład spróbować usunąć całą zawartość dysku doklejając do polecenia tekst “foo; rm -rf /” i uzyskując przez to: find . -name foo; rm -rf /
Nie uruchamiacie serwerów aplikacji z uprawnieniami administratora, prawda? Przykład 2 (ze strony OWASP https://www.owasp.org/index.php/XPATH_Injection): Uwierzytelniamy użytkowników naszej aplikacji na podstawie danych poniższego XMLa: <?xml version=”1.0” encoding=”utf-8”?> <Employees>
<Employee ID=”1”>
<FirstName>Arnold</FirstName> <LastName>Baker</LastName>
<UserName>ABaker</UserName>
<Password>SoSecret</Password> <Type>Admin</Type>
</Employee>
<Employee ID=”2”>
<FirstName>Peter</FirstName> <LastName>Pan</LastName>
<UserName>PPan</UserName>
<Password>NotTelling</Password> <Type>User</Type>
</Employee>
</Employees>
1/2014
INJECTION
OWASP Top 10 2013 (https://www.owasp.org/index.php/Top_10_2013-Top_10) • • • • • • • • • •
Injection Broken authentication and session management (Błędy uwierzytelniania i obsługi sesji) Cross-Site Scripting (XSS) Insecure direct object references (Niezabezpieczone, bezpośrednie linki do obiektów) Security misconfiguration (Błędy konfiguracji) Sensitive data exposure (Błędy obsługi poufnych danych) Missing function level access control (Brak weryfikacji uprawnień dostępu) Cross-Site Request Forgery (CSRF) Using components with known voulnerabilities (Wykorzystanie komponentów z błędami bezpieczeństwa) Unvalidated redirects and forwards (Niewalidowane przekierowania)
budując parametryzowalne zapytanie XPath: “//Employee[UserName/text()=‘“ + name+ “’And
Password/text()=‘“ + password + “‚]”
Następująca parametryzacja pozwala całkowicie ominąć nasze mechanizmy kontroli: name: blah’ or 1=1 or ‚a’=’a password: foo
Z powyższych przykładów wynika parę wniosków. Po pierwsze błędy typu injection nie są jedynie cechą aplikacji webowych i równie dobrze mogą występować w aplikacjach desktopowych oraz mobilnych. To czyni je jeszcze bardziej niebezpiecznymi. Po drugie powodem powstawania błędów jest konkatenacja elementów naszych zapytań z niefiltrowanymi parametrami wprowadzonymi przez użytkownika. To bardzo istotne spostrzeżenie. Powinno uwrażliwić każdego czytającego kod na potencjalne błędy wynikające z faktu łączenia łańcuchów znaków celem parametryzacji zapytań i poleceń.
Czy jest się czego obawiać?
Podstawowe pytania jakie należy sobie zadać myśląc o bezpieczeństwie budowanego systemu brzmią: Co mamy do stracenia? Co stanowi o wartości naszej aplikacji? Chcemy chronić nasze algorytmy, czy też chcemy chronić nasze dane? Co się stanie, jeżeli utracimy całkowicie i jedno i drugie? Przedstawione powyżej przykłady są co prawda krytyczne z punktu widzenia potencjalnych zniszczeń lub innych konsekwencji w naszym systemie, jednak prawdopodobieństwo ich wystąpienia jest znikome. (Kto z nas wywołuje w swojej aplikacji parametryzowalne polecenia systemowe? Kto z nas uwierzytelnia użytkowników na podstawie wpisów w pliku XML?) Co więc sprawiło, że wielcy tego świata (Nokia, Sony Music, Yahoo, FBI, NASA, itd.) padli ofiarą błędów typu injection? www.sdjournal.pl
SQL injection
Większość nietrywialnych systemów i aplikacji wymaga dostępu do bazy danych. Wszędzie tam, gdzie występuje relacyjna baza danych, istnieje również zagrożenie wystąpienia błędów SQL injection. Co może zrobić złośliwy użytkownik mogąc oprogramować naszą bazę? Pojawiają się tutaj trzy zagrożenia: Omijanie kryteriów klauzuli WHERE w zapytaniu SQL
Klasyczny przykład zakłada uwierzytelnianie użytkowników w systemie na podstawie wykonania poniższego zapytania: select * from users where name = ‘<name>’ and password = ‘<password>’;
Niebezpieczna parametryzacja miała by tu postać: name = ″’ or 1=1 or ′a′=′a″ password = ″anything″
Pozyskiwanie dodatkowych informacji z bazy
Przy założeniu, że wykonywane w systemie zapytanie ma postać: select content from data where id = <id>
poniższa parametryzacja sprawi, że udostępnimy więcej informacji niż byśmy tego chcieli: id = ″21 UNION ALL SELECT password from users″
Przekazywanie dodatkowych poleceń do bazy
I tu kolejny przykład. Mając zapytanie:
select name from record where id = <id>
możemy się obawiać wstrzyknięcia parametryzacji typu: id = ″1; DROP table record; DROP table address--″
13
Poza pomysłowością potencjalnego intruza, chcącego wykorzystać błędy w implementacji naszego systemu, ograniczać będzie wykorzystana przez nas technologia oraz biblioteki. Na przykład ataki mające na celu wykonanie w bazie dodatkowych poleceń (punkt 3) są możliwe w niektórych frameworkach wykorzystywanych przez PHP, nie są natomiast możliwe i wspierane przez np. sterownik JDBC w Javie. Podsumowując powyższe przykłady trzeba jednak zauważyć, że konsekwencje błędów typu injection w aplikacji idą bardzo daleko i umożliwiają pozyskanie i nadpisanie wszystkich danych zawartych w bazie (przy jednoczesnym ominięciu mechanizmów kontroli dostępu do tych danych). Konsekwencje utraty informacji na taką skalę mogą doprowadzić niektóre przedsiębiorstwa nawet do bankructwa.
Co nie pomaga?
Rozwiązania wszelki problemów dzielą się na dwie kategorie: na te które działają i na całą resztę. Próbę odpowiedzi na pytanie, jak uniknąć problemów niechcianych wstrzyknięć obcego kodu w naszej aplikacji, zaczniemy od analizy tych drugich. Na pewno rozwiązaniem problemu błędów typu injection nie jest ignorancja. Nie należy oczekiwać, że nikt nie odkryje problemów z formularzami na trzeciorzędnej stronie naszego portalu, gdyż są zbyt głęboko ukryte. Narzędzia do automatyzacji procesu skanowania aplikacji webowych biorą na siebie ciężar takich poszukiwań. Rozwiązaniem naszych problemów nie będzie prawie nigdy blacklisting niechcianych wartości parametryzacji zapytań. Rozpatrzmy następujący przykład: W naszym zapytaniu do bazy select content from data where id = <id> obawiamy się wstrzyknięcia 21 UNION ALL SELECT (...). Tworzymy więc wyrażenie regularne, które sprawdzi, czy elementem naszego parametru nie jest czasem wartość UNION. Jeżeli tak, aplikacja zwróci błąd. Złośliwy użytkownik będzie mógł obejść nasz filtr przekazując zamiast UNION wartość UNIO/**/N (dla bazy danych MySQL). Problem z blacklistingiem jest taki, że rzadko kiedy deweloper zna wszystkie sztuczki możliwe do wykonania
ze składnią zapytań do bazy danych. Stąd zabezpieczenia tego rodzaju dają najczęściej tylko złudne poczucie bezpieczeństwa.
Co pomaga?
Możliwe rozwiązania problemów wstrzyknięć obcego kodu do aplikacji można podzielić na trzy kategorie: • wykorzystanie wbudowanych mechanizmów szablonów • escaping • whitelisting Wykorzystanie wbudowanych mechanizmów szablonów (na przykładzie sterownika JDBC dla Javy) poprawne wykorzystanie szablonów PreparedStatement nie tylko zwiększa wydajność bazy danych (plan zapytania musi być policzony tylko raz dla szablonu), lecz również rozwiązuje problem SQL injection. W poniższym przykładzie wartość zmiennej id nie jest w stanie przeformułować treści zapytania do bazy: String sql = „SELECT firstname, lastname, age FROM Employees where id=?”;
PreparedStatement statement = connection. prepareStatement(sql);
Statement.setString(1, id);
ResultSet rs = statement.executeQuery(sql);
Escaping - czyli unieszkodliwienie wszystkich znaków modyfikujących zapytanie, które przychodzą spoza systemu, poprzez wykorzystanie odpowiedniej biblioteki (np. ESAPI). Często spotykanym przykładem jest escapowanie wszystkich znaków będących częścią kodu HTML przy dynamicznym generowaniu stron internetowych w aplikacji webowej. Whitelisting - w przeciwieństwie do blacklistingu, gdzie szukaliśmy wzorców, które należało wykluczyć jako niebezpieczne, przy whitelistingu sprawdzamy, czy przekazane wartości parametrów spełniają określone wyrażenie do którego bezpieczeństwa jesteśmy pewni, a odrzucamy wszystkie wartości, które wyrażenia nie spełniają.
Tabela 1. SQL-Injection Hall of Shame Lista wybranych błędów SQL Injection, które doprowadziły do kompromitacji systemów. Pełna lista dostępna na stronie http://codecurmudgeon.com/wp/sqlinjection-hall-of-shame/
14
Firma/Instytucja
Data
Utracono
Nasa
2013-11
Dane ponad 100.000 użytkowników
FBI
2012-12
Ponad 1,6 mln adresów e-mail i haseł użytkowników
Yahoo
2012-07
450.000 niezaszyfrowanych haseł
2012-06
6,5 mln haszy haseł
Sony Pictures
2011-06
Dane ponad 1 mln użytkowników
1/2014
INJECTION
Dodatkowe zabezpieczenia
Przestrzeganie powyższych wskazówek daje stuprocentową ochronę przed błędami typu injection. Nadal jednak istnieć będzie ryzyko, że - wskutek błędnej implementacji - luki tego typu zaistnieją w rozwijanym systemie. Ochronę naszej aplikacji powinniśmy dlatego rozwijać wielowarstwowo (tzw. defense in depth), a naszym celem powinno być z jednej strony minimalizowanie ryzyka wystąpienia, a z drugiej - minimalizowanie strat w przypadku zaistnienia błędu. Co więc możemy zrobić, aby się lepiej zabezpieczyć? Edukacja - gdyby istniało szybkie i sprawne rozwiązanie problemów bezpieczeństwa, już dawno byśmy je stosowali. Droga do bezpiecznego systemu jest jednak bardziej wyboista. Po pierwsze nie możemy nigdy zapomnieć o tych, którzy te systemy tworzą. Brak doświadczenia oraz szybkie tempo realizacji projektów wpływają negatywnie na bezpieczeństwo aplikacji. Okresowe szkolenia poszerzają wiedzę, przypominają o priorytetach i redukują ryzyko wystąpienia błędów. Architektura - dobra architektura może redukować straty powstałe w przypadku zaistnienia błędów. Często praktykowanym na poziomie bazy danych podejściem jest oddzielenie zadań administracji bazą od wykorzystywania bazy danych na potrzeby aplikacji. Cel taki można osiągnąć tworząc osobnego użytkownika (resource user) posiadającego uprawnienia do zasobów takich jak tabele, widoki, procedury, linki do innych baz danych, itd. Użytkownik ten udostępnia poprzez granty wybrane widoki użytkownikowi (connect user), przez którego realizowane są połączenia z aplikacji. Efektem takiej architektury jest ograniczenie uprawnień connect usera do niezbędnego minimum i uniemożliwia wykonanie operacji na zasobach administracyjnych bazy danych z jego poziomu. Kryptografia - dobrze wiedzieć, że istnieje również poza stosem protokołów TLS i że można ją wykorzystać do ukrycia wrażliwych danych w systemie. W przypadku przechowywania haseł użytkowników dobrze pamiętać o jednokierunkowych funkcjach skrótu (PBKDF2, bcrypt, scrypt, koniecznie z unikalną solą, a najlepiej solą i pieprzem), a w przypadku numerów kart kredytowych - o szyfrowaniu symetrycznym w którym klucz szyfrowania przechowywany będzie poza bazą danych. Obsługa błędów - jeżeli podczas działania aplikacji wystąpi błąd krytyczny, serwerowi na środowisku produkcyjnym wolno odpowiadać jedynie błędami HTTP (np. 500 - błąd serwera). Pokazywanie listingu stosu jest co prawda bardzo przydatne dla dewelopera, jednocześnie zdradza jednak szczegóły implementacyjne naszego systemu, co niepotrzebnie ułatwia sprawę osobie atakującej naszą aplikację. Monitoring - częste analizowanie stanu naszego systemu na środowisku produkcyjnym jest wskazane. Prowww.sdjournal.pl
ces ten można zautomatyzować integrując aplikację z systemem IDS/IPS, który odpowiednio szybko będzie w stanie zabić na alarm w momencie wykrycia ataku. Procesy - najlepsze systemy IDS/IPS niewiele dadzą, jeżeli ich działanie nie będzie przez nikogo monitorowane. Brak błędów bezpieczeństwa w danej wersji systemu nie gwarantuje, że nie pojawią się one w kolejnej. Bezpieczeństwo to nie stan, to proces, stąd istotną rzeczą jest przedsięwzięcie odpowiednich kroków (quality gates) celem ciągłego dbania o bezpieczeństwo jako element jakości systemu. Dobrym pomysłem jest na przykład audyt krytycznych fragmentów kodu przeprowadzany każdorazowo przez doświadczonych pracowników w ramach budowania kolejnej wersji systemu, lub uwzględnienie testów penetracyjnych w fazie testowania aplikacji.
Marek Puchalski
Od ponad 7 lat specyfikuje, implementuje i wdraża systemy informatyczne dla największych graczy niemieckiego rynku motoryzacyjnego. Pracownik firmy Capgemini, tata siedemnastomiesięcznego Janka, gracz Go, fascynat wszelkiej tematyki związanej z bezpieczeństwem oprogramowania i aplikacji webowych.
15
Wrocławskie Capgemini Software Solutions Center, jako centrum rozwoju oprogramowania i usług informatycznych firmy Capgemini, specjalizuje się w rozwiązaniach IT dla znanych na całym świecie klientów. Centrum to współpracuje ściśle z niemieckimi oddziałami Capgemini. Obecnie Software Solutions Center zatrudnia niemal 600 specjalistów branży IT, którzy zajmują się głównie: · projektowaniem, tworzeniem, testowaniem oraz wdrażaniem indywidualnych rozwiązań IT w oparciu o nowoczesne technologie programistyczne, takie jak Java, .NET, platformy bazodanowe (np. Oracle), Business Intelligence oraz technologie mobilne (np. Android, iOS, Windows Phone); · projektowaniem, tworzeniem i wdrażaniem nowych rozwiązań informatycznych z obszaru SAP; ·
architekturą złożonych systemów IT - projektowanie zaawansowanych rozwiązań klasy enterprise oraz biznesowy konsulting dla wielu branż;
· zarządzaniem projektami informatycznymi w oparciu o metodyki zwinne i klasyczne - stosowane są metodyki stworzone na bazie międzynarodowych trendów (takich jak Scrum, RUP) wzbogacone o nasze doświadczenia; w zarządzaniu projektami opieramy się również na klasycznych standardach i dobrych praktykach (np. PMBOK, ITIL); ·
wsparciem funkcjonowania systemów indywidualnych oraz SAP – wsparcie w zakresie monitoringu systemów SAP; rozwiązywanie incydentów, problemów oraz realizacja zmian w oparciu o ITIL; wspieranie procesów w poszczególnych obszarach SAP; rozbudowywanie systemu SAP o dodatkowe funkcjonalności;
Strefy czasowe w Javie i bazach danych
Jak pamiętamy ze szkoły podstawowej, Ziemia obraca się wokół własnej osi, co powoduje występowanie po sobie pory dnia i pory nocy. Raz na dobę ustawienie promieni słonecznych jest w zenicie (najwyższym punkcie względem horyzontu), co potocznie nazywamy „południem”.
Rysunek. Strefy czasowe na świecie, źródło: Wikipedia.
Z
e względu na wspomniany ruch wokół własnej osi, punkt południa przesuwa się z prędkością 1 stopnia na 4 minuty. Gdyby każdy człowiek na Ziemi chciał mieć na zegarku godzinę 12:00 (z dokładnością co do minuty) wtedy gdy słońce jest u niego nad horyzontem w zenicie, to mielibyśmy 1440 stref czasowych - tyle jest minut w czasie doby. Z oczywistych względów jest to niemożliwe, i w latach 1878 – 1884 zaproponowano i wprowadzono podział na 24 strefy czasowe oddzielone od siebie o 1h (z drobnymi wyjątkami). Ustalono że strefą „0” będzie czas dla południka „0” przebiegającym przez obecną dzielnicę Greenwich w Londynie i nazywa się go zamiennie: UT - Czas uniwersalny (ang. Universal Time), GMT (ang. Greenwich Mean Time) lub UTC
18
- uniwersalny czas koordynowany (ang. Coordinated Universal Time). Ze względów praktycznych strefy czasowe zostały wyznaczone wg granic oceanów i poszczególnych państw tak, aby mniejsze z nich znalazły się w obrębie jednej strefy czasowej. Większe są położone w kilku strefach, np. Rosja (12), USA (7), Kanada (6), chociaż np. Chiny tylko w jednej. Żeby sprawa była jeszcze bardziej skomplikowana, to część krajów ma jeszcze tzw. czas letni, czyli okresowo wprowadzaną zmianę w czasie o 1h. Zostało to wprowadzone ze względów oszczędnościowych, żeby lepiej wykorzystać światło dzienne. Zmiany czasu letniego są organizacyjnie kłopotliwe i wiele krajów już się z niego wycofało. 1/2014
STREFY CZASOWE W JAVIE I BAZACH DANYCH
Kiedy musimy martwić się strefami czasowymi
W świecie „pozainformatycznym” z koniecznością przestawiania zegarków mamy do czynienia gdy podróżujemy, np. na niedaleką Ukrainę czy Litwę. Z kolei w świecie „informatycznym” musimy zainteresować się kwestią stref czasowych wtedy, gdy tworzymy aplikacje z których korzystają klienci w więcej niż jednej strefie czasowej. W dalszej części tego artykułu opiszę sposób rozwiązania tego problemu na realnym przykładzie.
Jak działają strefy czasowe w systemie operacyjnym
Współczesne systemy operacyjne, np. Linux, posiadają dane pozwalające na prezentowanie czasu zegara systemowego w strefie czasowej wybranej przez użytkownika, najczęściej w czasie instalacji systemu operacyjnego, automatycznie uwzględniając w tym czas letni. $ date
Tip
Trzeba pamiętać, że na liście dostępnych stref czasowych są także takie z identyfikatorami trzyliterowymi, ale istnieją one tylko dla zapewnienia zgodności wstecz i nie powinny być używane.
lub zmienną środowiskową TZ=Europe/Warsaw. Możemy też ustawić lub zmienić aktualną strefę metodą setDefault: TimeZone.setDefault(TimeZone.getTimeZone(″Australia/ Darwin″)).
Listę dostępnych identyfikatorów stref czasowych oraz ich nazwy można wyświetlić w prosty sposób: for(String tzId : TimeZone.getAvailableIDs()) { TimeZone tz = TimeZone.getTimeZone(tzId);
System.out.println(String.format(″%35s -> %s″, tzId, tz.getDisplayName()));
pią, 29 lis 2013, 16:09:42 CET
}
„CET” oznacza czas środkowoeuropejski (ang. Central European Time). Ponadto możemy wyświetlić aktualny czas w innej strefie czasowej:
Dalej musimy już pamiętać, że uruchomiony program ma przypisaną strefę czasową, z której korzystają standardowe klasy, takie jak SimpleDateFormat i Calendar. Przykład: jeżeli w naszym programie przy pomocy SimpleDateFormat wyświetlimy czas „0” to otrzymamy:
$ TZ=″America/Chicago″ date
pią, 29 lis 2013, 09:10:09 CST
„CST” oznacza czas centralny (ang. Central Standard Time). Możemy również poprosić o wyświetlenie zadanej daty i w odpowiedzi otrzymamy informacje o obowiązującym wtedy czasie: $ date --date ″2013-09-01 00:00:00″ nie, 1 wrz 2013, 00:00:00 CEST
„CEST” oznacza czas środkowoeuropejski letni (ang. Central European Summer Time). System operacyjny potrafi zwrócić też czas w milisekundach od 1970.1.1 00:00:00 UTC co dalej będzie istotne: $ date +%s%3N
System.out.println(″Strefa czasowa:
" + TimeZone.getDefault().getID());
System.out.println(″Czas ′0’: ″ + new
SimpleDateFormat().format(new Date(0)));
----------------------------------------------------Strefa czasowa: Europe/Warsaw Czas ‚0’: 01.01.70 01:00
Otrzymaliśmy godzinę pierwszą („01”) a nie, jak można by się spodziewać, północ. Wynika to z tego, że metoda klasy SimpleDateFormat wykonała za nas przeliczenie do domyślnej strefy czasowej. Podobnie sytuacja wygląda z klasą Calendar:
1385738304763
Calendar calendar = Calendar.getInstance();
Jak działają strefy czasowe w Javie
System.out.println(″Godzina czasu ′0′:
W javie metoda System.currentTimeMillis() zwraca czas w milisekundach od 1970.1.1 00:00:00 UTC, identycznie jak ostatnia komenda date +%s%3N systemu operacyjnego Linux. Uruchomiony program w JVM automatycznie otrzymuje domyślną strefę czasową z systemu operacyjnego, np. „Europe/Warsaw”. Możemy ją zmienić przez argument przekazywany do JVM -Duser.timezone=Europe/Warsaw www.sdjournal.pl
calendar.setTimeInMillis(0);
″ + calendar.get(Calendar.HOUR_OF_DAY));
----------------------------------------------------Godzina czasu ′0′: 1
Wykonując operacje na czasie należy pamiętać, aby posługiwać się reprezentacją obiektową, np. klasą Calendar, a nie bezpośrednio reprezentacją milisekundową. Wykonanie poniższego kodu ilustruje problem 19
jaki może się pojawić gdy korzystamy z reprezentacji milisekundowej.
• •
Timestamp ts = Timestamp.valueOf(″2013-10-26 12:00:00″);
System.out.println(″Data początkowa: ″ + ts); cal.setTimeInMillis(ts.getTime()); cal.add(Calendar.DAY_OF_MONTH, 1);
System.out.println(″Dzień później (calendar): ″ +
new Timestamp(cal.getTimeInMillis()));
new Timestamp(ts.getTime() + 24 * 60 * 60 *
″ +
1000));
mysql> set time_zone = ″+01:00″;
mysql> insert into field_type_test (datetime_field, timestamp_field) values (″197001-02 01:00:00″, ″1970-01-02 01:00:00″);
-----------------------------------------------------
mysql> select * from field_type_test;
Dzień później (calendar): 2013-10-27 12:00:00.0
| datetime_field
Data początkowa: 2013-10-26 12:00:00.0 Dzień później (millis):
2013-10-27 11:00:00.0
Na tym przykładzie widać że „jeden dzień później” to nie zawsze to samo co „24 godziny później”, ponieważ w nocy z 26 na 27 października 2013 jest zmiana czasu letniego na zimowy i godziny 12:00 obydwu tych dni są oddalone od siebie o 13 a nie 12 godzin. Metody klasy Calendar skutecznie obsługują takie przypadki brzegowe.
Strefy czasowe w bazach danych
Każda baza danych potrafi przechowywać dane typu „data z czasem”, potocznie zwane timestamp’em. Większość baz danych ma też różne typy pól „daty z czasem” w zależności od tego czy mają one obsługiwać strefy czasowe czy nie. Pola bez obsługi stref czasowych działają jak zwykłe napisy, tzn. jeżeli wstawimy do bazy danych wartość „1970-01-02 01:00:00” to niezależnie od tego w jakiej strefie czasowej będzie działać klient bazy danych to zawsze otrzymamy tą samą wartość. Pola z obsługą stref czasowych działają w oparciu o informacje w jakiej strefie czasowej działa program kliencki podłączony to bazy danych, terminal konsolowy lub aplikacja Java. Gdy klient jest połączony w strefie czasowej „Europe/Warsaw” (UTC+1) i zapisze do bazy danych datę „1970-01-02 01:00:00” a następnie zmieni strefę czasową na „America/Chicago” (UTC-6) to odczyta tą samą datę ale, dla nowo wybranej strefy czasowej, czyli „1970-01-01 18:00:00”. W tym przypadku nie ma znaczenia w jakiej strefie czasowej działa silnik bazy danych ani system operacyjny na którym jest zainstalowany. Przyjrzyjmy się szczegółowo jak to wygląda w konkretnych bazach danych. MySQL
MySQL ma dwa typy pól pozwalających na przechowywanie daty z czasem: 20
timestamp
Poniższy przykład ilustruje różnice w działaniu obydwu typów danych:
Calendar cal = Calendar.getInstance();
System.out.println(″Dzień później (millis):
– nie interpretuje strefy czasowej. – przy zapisie czas jest konwertowany do UTC i tak trzymany w bazie, a następnie przy wyświetleniu konwertowany do aktualnej strefy czasowej klienta.
datetime
+---------------------+---------------------+ | timestamp_field
|
+---------------------+---------------------+ | 1970-01-02 01:00:00 | 1970-01-02 01:00:00 | +---------------------+---------------------+ mysql> set time_zone = ″-06:00″; mysql> select * from field_type_test;
+---------------------+---------------------+ | datetime_field
| timestamp_field
|
+---------------------+---------------------+ | 1970-01-02 01:00:00 | 1970-01-01 18:00:00 | +---------------------+---------------------+
Podejmując decyzje co do wyboru typu pola na datę z czasem trzeba też zwrócić uwagę na możliwy do przechowywania zakres dat: – od „1000-01-01 00:00:00” do „9999-1231 23:59:59” • timestamp – od „1970-01-01 00:00:01” UTC do „2038-01-19 03:14:07” UTC •
datetime
I jeszcze jedno związane z tym ostrzeżenie: przy próbie wstawienia daty spoza dopuszczalnego zakresu przez JDBC otrzymamy wyjątek „MysqlDataTruncation: Data truncation: Incorrect datetime value”. Jednak przy próbie wstawienia niepoprawnej wartości z linii komend polecenie się powiedzie, ale zamiast spodziewanej wartości zostanie tam umieszczona wartość „0000-00-00 00:00:00” oznaczająca „błąd”. Na wyjściu konsoli zobaczymy obok standardowego „Query OK, 1 row affected” dodatkowy napis „1 warning”, który łatwo pominąć. PostgreSQL
Podobnie jak MySQL, także PostgreSQL ma dwa typy pól na datę z czasem o analogicznych funkcjach i zastosowaniu tylko o innych nazwach: •
timestamp
without
strefy czasowej
time
zone
– nie interpretuje
1/2014
STREFY CZASOWE W JAVIE I BAZACH DANYCH
•
timestamp with time zone
sowe
– interpretuje strefy cza-
Inne są także zakresy obsługiwanych wartości, ponieważ obydwa pola pozwalają na zapisanie wartości od od „-4713-12-31 23:59:59” UTC do „294276-12-31 23:59:59” UTC, więc zapas jest spory. Oracle
W Oracle jest najwięcej typów danych służących do reprezentowania daty z czasem: – typ uproszczony, z dokładnością tylko do sekund, nie interpretuje strefy czasowej. • timestamp – przechowuje części sekundy z dokładnością do 9 miejsc po przecinku, nie interpretuje strefy czasowej. • timestamp with time zone – jak timestamp, tylko że zawiera informacje o strefie czasowej ale nie dokonuje żadnych przeliczeń. • timestamp with local time zone – interpretuje strefy czasowe, tzn. dokonuje przeliczeń do strefy czasowej klienta. •
Jak widzimy, wszystkie operacje wykonywane przez terminal są zgodne z oczekiwaniami.
Obsługa stref czasowych przez JDBC
Do tego momentu wszystko powinno być zrozumiałe i dosyć spójne, niestety przez różne implementacje sterowników JDBC, dostęp z kodu aplikacji Java do tak zapisanych danych nieco się komplikuje. Zacznijmy od wyjaśnienia działania klasy java.sql.Timestamp do reprezentowania daty z czasem pobranej z bazy. Załóżmy że w bazie danych mamy zapisaną datę „0” bez sprecyzowania strefy czasowej, np.:
date
DB2
DB2 w wersji Express-C 10.5 oraz wersjach komercyjnych do wersji 9.x posiada tylko jeden typ pola timestamp, który nie interpretuje strefy czasowej. W dokumentacji DB2 jest zapowiedź nowego typu pola timestamp with time zone od wersji 10.5 dla systemu z/ OS, ale nie miałem możliwości jej przetestowania. Porównanie zachowania pól timestamp w bazie
Załóżmy, że łączymy się klientem konsolowym w strefie czasowej Europe/Warsaw (UTC+1) i wpisujemy do kolumn każdego typu datę 1970-01-02 01:00:00. Następnie rozłączamy się, łączymy ponownie, ale w strefie America/Chicago (UTC-6) i odczytujemy wynik. Zachowanie oczekiwane jest takie, że w typach z przeliczaniem stref czasowych otrzymamy godzinę 18:00 a bez strefy 1:00 (tak jak zapisaliśmy). Tabela 1 prezentuje typy pól w poszczególnych bazach i otrzymany wynik.
Column |
Table ″public.timestamp_test″ Type
| Modifiers
--------+-----------------------------+----------id
test
| integer
| not null
| timestamp without time zone |
select * from timestamp_test
----------------------------------------------------1 1970-01-01 00:00:00.0
Po jej pobraniu przez JDBC metodą ResultSet. do obiektu Timestamp intuicyjnie wydawałoby się że przechowuje on datę ″0″. I tak właśnie wyświetli się ona po wywołaniu metody getString. Jednakże gdy sprawdzimy „wewnętrzną” reprezentację przy pomocy getTime() to nie otrzymamy spodziewanego ″0″: getTimestamp(...)
Timestamp timestamp = rs.getTimestamp(1);
System.out.println(″Timestamp ′0’ toString(): ″ + timestamp);
System.out.println(″Timestamp ′0’ time: ″ + timestamp.getTime());
System.out.println(″Timestamp ′0’ sformatowany: ″ + DateFormat.getDateTimeInstance( DateFormat.FULL, DateFormat.FULL). format(timestamp));
----------------------------------------------------Timestamp ′0’ toString(): 1970-01-01 00:00:00.0 Timestamp ′0’ time: -3600000
Tabela 1. MySQL
Timestamp bez strefy czasowej
Timestamp ze strefą czasową Inne
datetime
timestamp
1970-01-02 01:00:00
1970-01-01 18:00:00
PostgreSQL timestamp without time zone
timestamp with time zone
Oracle
timestamp
timestamp with local time zone
DB2
timestamp
-
1970-01-02 01:00:00
1970-01-02 01:00:00.000000
1970-01-02-01.00.00
www.sdjournal.pl
1970-01-01 18:00:00-06
1970-01-01 18:00:00.000000
date
1970-01-02 01:00:00
timestamp with time zone 1970-01-02 01:00:00.000000 +01:00
21
Timestamp ′0’ sformatowany: czwartek, 1 styczeń 1970 00:00:00 CET
Co więc się stało? Otóż sterownik JDBC (w tym przypadku do PostgreSQL) po pobraniu daty z bazy „cofnął” nam ją wg aktualnej strefy czasowej, tak aby przy „wyświetleniu” z powrotem reprezentowała dokładnie tą samą wartość co w bazie. Wracając do kwestii komunikacji z poszczególnymi bazami danych: jeżeli chcemy skorzystać z zalet wykorzystania pól przeliczających strefy czasowe to klient Java musi poinformować bazę danych w jakiej strefie czasowej działa – podobnie jak w przypadku testu z bezpośrednim dostępem do bazy. Niestety w przypadku każdej bazy danych działa to nieco inaczej.
• Należy skorzystać z dodatkowej metody specyficz-
nej dla Oracle ustawiającej strefę czasową bezpośrednio na obiekcie Connection:
OracleConnection.setSessionTimeZone(timeZoneName);
DB2
W DB nie ma rozwiązań specyficznych, bo nie ma typu pola w bazie, które by wspierało przeliczanie stref czasowych. Porównanie zachowania pól timestamp w aplikacji Java
Korzystając z PostgreSQL samo ustawienie domyślnej strefy nie wystarczy, trzeba posługiwać się metodami które przy zapisie i odczycie dat z czasami przekazują dodatkową informacje o strefie czasowej:
Tabela 2 porównuje wyniki testu analogicznego do wykonanego poprzednio bezpośrednio na bazie, tylko teraz przy pomocy aplikacji Java. Wpisaliśmy do kolumn każdego typu datę 1970-01-02 01:00:00 w strefie czasowej Europe/Warsaw (UTC+1) a następnie odczytujemy wynik z aplikacji Java w strefie America/Chicago (UTC-6) z zastosowaniem metod opisanych wyżej. Jak widać, baza danych MySQL w przypadku pobierania przez JDBC błędnie aplikuje przesunięcie strefy czasowej w odniesieniu do pola typu które nie powinno mieć takiego przesunięcia. Wiedząc o tym trzeba starannie stosować odpowiednie typy pól i ustawianie domyślnej strefy czasowej w zależności od tego jakiego efektu potrzebujemy. Pozostałe bazy danych nie mają tego błędu i przesunięcia są aplikowane tylko na właściwych typach kolumn.
PreparedStatement.setTimestamp(columnIndex,
Implementacja systemów globalnych
MySQL
Korzystając z MySQL wystarczy że użyjemy polecenia TimeZone.setDefault(...) i data z pola typu ″timestamp″ (to obsługujące strefy) będzie przeliczana. Niestety, to ustawienie skutkuje także przeliczeniem daty z pola ″datetime″, które nie powinno obsługiwać przeliczeń. PostgreSQL
timestamp, calendar)
ResultSet.getTimestamp(columnIndex, calendar)
Oracle
Korzystając z Oracle sytuacja jest najbardziej skomplikowana: • Należy ustawić domyślną strefę czasową polece-
niem TimeZone.setDefault(...)
• Nie wolno korzystać z metod, które przy zapisie i
odczycie dat z czasami przekazują dodatkową informacje o strefie czasowej (inaczej niż w PostgreSQL)
Załóżmy, że mamy do implementacji globalny system aukcyjny, w którym każdy może wystawić przedmiot, np. Kowalski z Warszawy o godzinie 11:00, i każdy może go licytować, np. Kowalsky z Chicago. Funkcjonalnie musi to działać tak, że Kowalsky z Chicago widzi że aukcja rozpoczęła się o 4:00 rano jego czasu lokalnego. Opcjonalnie może widzieć, że była to godzina 11:00 czasu środkowo europejskiego, żeby nie dziwić się dlaczego sprzedawca nie śpi po nocach. Opisane powyżej trudności z korzystaniem przeliczania stref czasowych przy pomocy bazy danych skłaniają do rozwiązania nie polegającego na przeliczaniu
Tabela 2. MySQL
Timestamp bez strefy czasowej
Timestamp ze strefą czasową Inne
Datetime
Timestamp
1970-01-01 18:00:00
PostgreSQL timestamp without time zone
timestamp with time zone
Oracle
timestamp
timestamp with local time zone
DB2
timestamp
-
1970-01-02 01:00
22
1970-01-01 18:00:00
1970-01-02 01:00
1970-01-02 01:00:00.0
1970-01-01 18:00
1970-01-02 18:00:00
date
1970-01-02 01:00:00
timestamp with time zone 1970-01-02 18:00:00
1/2014
STREFY CZASOWE W JAVIE I BAZACH DANYCH
stref przez bazę danych. Szczególnie korzystanie w metody TimeZone.setDefault(...) i OracleConnection. setSessionTimeZone(...) w aplikacjach JEE, czyli wielowątkowych i korzystających z połączeń pobieranych z puli serwera aplikacyjnego jest proszeniem się o problemy. Najprostszym sposobem implementacji jest założenie, że domyślnie aplikacja działa w czasie GMT i tak zapisuje dane do bazy. Żeby użytkownikowi wyświetlić dane w jego strefie czasowej, musimy ją najpierw „zgadnąć”. Określenie to jest nieprzypadkowe, ponieważ nie ma standardowych mechanizmów, które pozwalałyby aplikacji po stronie serwera ustalić w jakiej strefie czasowej pracuje przeglądarka WWW klienta, np. poprzez nagłówki protokołu HTTP. Jednym z rozwiązań jest posłużenie się usługą „IP address geocoding”, która na podstawie adresu IP zwraca dane o położeniu geograficznym i strefie czasowej. Niestety tego typu usługi są płatne. Aby obejść ten problem można posłużyć się prostym kodem JavaScript:
mu strefę czasową ″Europe/Berlin″ zamiast ″Europe/ Warsaw″ - trudno. Taką informacje musimy przesłać z przeglądarki do serwera i zapamiętać w sesji użytkownika. Gdy już znamy strefę czasową klienta, wszystkie daty, które chcemy mu wyświetlić musimy przeliczyć z GMT (tak są zapisane w bazie) na jego czas lokalny: Calendar gmtCalendar = Calendar.getInstance(TimeZone. getTimeZone(″GMT″));
PreparedStatement ps = c.prepareStatement(″select date_gmt from gmt_test″);
ResultSet rs = ps.executeQuery(); if(rs.next()) {
Timestamp timestampGmt = rs.getTimestamp(1, gmtCalendar);
System.out.println(″Czas GMT: ″ + timestampGmt); // konwersja do czasu ″Europe/Warsaw″:
TimeZone tz = TimeZone.getTimeZone(″Europe/ Warsaw″);
var myDate = new Date();
Calendar calendar = Calendar.getInstance(tz);
myDate.getTimezoneOffset();
Zwraca on informacje o przesunięciu aktualnej strefy czasowej systemu operacyjnego klienta względem czasu GMT wyrażony w minutach, np. dla Polski jest to „-60” w czasie zimowym i „-120” w czasie letnim. Żeby poprawnie zinterpretować, z którym czasem mamy aktualnie do czynienia należy dokonać dodatkowych obliczeń na stworzonych dwóch dodatkowych datach: jednej w styczniu (zimowy) i jednej w lipcu (letni) i porównanie przesunięć z datą bieżącą. Ale łatwiej jest skorzystać z małej biblioteki JS pt. „jsTimezoneDetect” (http://pellepim.bitbucket.org/jstz/), w której to już zostało zrobione, a ponadto obsługa konwersji przesunięcia wyrażonego w minutach na identyfikatory stref czasowych rozpoznawanych przez Javę. Niedoskonałość biblioteki polega na tym że jeżeli dla jednego przesunięcia, np. „+1h” istnieje kilka stref czasowych, to ona podpowie tylko jedną z nich. Nie jest to przeszkodą, jeżeli pozwolimy ją użytkownikowi potwierdzić albo ewentualnie zmienić. Przykład działania wygląda tak:
calendar.setTimeInMillis(timestampGmt.getTime()); System.out.format(″Czas lokalny: %tc\n″,
calendar);
// konwersja do czasu ″Europe/Chicago″:
tz = TimeZone.getTimeZone(″America/Chicago″); calendar = Calendar.getInstance(tz);
calendar.setTimeInMillis(timestampGmt.getTime()); System.out.format(″Czas lokalny: %tc\n″, calendar);
}
----------------------------------------------------Czas GMT:
1970-01-02 00:00:00.0
Czas lokalny: Pt sty 02 01:00:00 CET 1970 Czas lokalny: Cz sty 01 18:00:00 CST 1970
Żeby z kolei datę w lokalnej strefie czasowej wprowadzoną przez użytkownika zapisać do bazy danych w strefie GMT należy: Calendar gmtCalendar = Calendar.getInstance(TimeZone. getTimeZone(″GMT″));
PreparedStatement ps = c.prepareStatement(″UPDATE
gmt_test SET date_gmt = ?″);
var timezone = jstz.determine();
SimpleDateFormat df = new SimpleDateFormat(″yyyy-
-----------------------------------------------------
df.setCalendar(Calendar.getInstance(TimeZone.
timezone.name(); ″Europe/Berlin″
Jak widać na tym przykładzie, biblioteka poprawnie zgadła przesuniecie +1h, ale przyporządkowała www.sdjournal.pl
MM-dd HH:mm″);
getTimeZone(″Europe/Warsaw″)));
Date date = df.parse(″1970-01-02 01:00″); // to czas
wprowadzony przez usera
23
System.out.println(″Czas użytkownika: ″ + date. toString());
ps.setTimestamp(1, new Timestamp(date.getTime()), gmtCalendar);
ps.executeUpdate();
----------------------------------------------------Czas użytkownika: Fri Jan 02 00:00:00 GMT 1970
Jak widać, zmienna date jest już w domyślnej strefie GMT.
Ciekawe problemy
Podsumowanie
Jak widać, obsługa stref czasowych w aplikacjach globalnych nie jest taka prosta jak by można początkowo sądzić. Mam nadzieję że niniejszy artykuł wyjaśnił podstawowe kwestie w tym zakresie. W ramach podsumowania warto jeszcze zaznaczyć że użyteczność klas związanych z obsługą dat w JDK (Date, Calendar) jest mało wygodna i powstały biblioteki, które to nieco ułatwiają, np. Joda-Time (http://www.joda.org/jodatime/). Także w JDK 8 zapowiadany jest nowy pakiet java. time, który ma ułatwić operacje na typach daty i czasu.
Niebanalnym problemem do rozwiązania jest kwestia ustalania czasu zdarzeń „systemowych”, czyli nie związanych z sesją konkretnego użytkownika. Przykładami takich zdarzeń mogą być: • publikacja / archiwizowanie aktualności, • zakończenie czasu trwania promocji, • zakończenie terminu opłacenia usługi.
Gdyby uzależnić takie zdarzenia od czasu użytkownika, to on zmieniając strefę czasową mógłby „gonić promocje”. W systemach globalnych najprostszym sposobem uniknięcia takich problemów i nieporozumień z klientami jest wykonywanie zmian statusów takich obiektów przez crona systemowego działającego w strefie GMT i wyraźne informowanie swoich użytkowników, że tak to działa.
Marek berkan
Marek Berkan, Zastępca Dyrektora ds. Realizacji w firmie e-point S.A. Odpowiada za proces implementacji systemów informatycznych, a następnie za ich długofalowy rozwój i utrzymanie. Od 13 lat programuje w J2EE, od 8 lat pracuje nad dynamicznie rozwijającym się projektem w technologii J2EE, koordynując prace zespołu programistów.
Użyteczne komendy Oracle:
• Ustawienie TZ klienta: TZ=America/Chicago sqlplus … • Ustawienie TZ całej bazy: ALTER DATABASE SET TIME _ ZONE = • Sprawdzenie TZ klienta: SELECT SESSIONTIMEZONE FROM DUAL; • Ładne formatowanie pola typu timestamp:
″-06:00″;
ALTER SESSION SET nls _ timestamp _ format = ″yyyy-mm-dd hh24:mi:ss″;
• Ładne formatowanie pola typu timestamp ze strefą czasową:
ALTER SESSION SET nls _ timestamp _ tz _ format = ″yyyy-mm-dd hh24:mi:ss.ff tzh:tzm″;
• Ładne formatowanie pola typu date z czasem:
ALTER SESSION SET nls _ date _ format = ″yyyy-mm-dd hh24:mi:ss″;
MySQL:
• Ustawienie TZ klienta: SET TIME • Sprawdzenie TZ klienta: SELECT
ZONE = ″+01:00″; @@global.time _ zone, @@session.time _ zone;
PostgreSQL:
• Ustawienie TZ klienta: SET TIME ZONE ″America/Chicago″; • Sprawdzenie TZ klienta: SHOW TIMEZONE;
24
1/2014
Wehikuł czasu w komputerze, czyli o systemach kontroli wersji na przykładzie Subversion
Artykuł przybliża Czytelnikowi koncepcje i strategie rozwoju oprogramowania przy wykorzystaniu systemów kontroli wersji. Oprócz zagadnień teoretycznych zaprezentowano podstawowe scenariusze pracy z Subversion. Dowiesz się: • Do czego służą systemy kontroli wersji i jak je dzielimy; • Jak zorganizować pracę nad rozwojem aplikacji wyko-
Powinieneś wiedzieć: • Jak korzystać z wiersza poleceń.
rzystując systemy kontroli wersji; • Jak pracować z Subversion.
W
szyscy popełniają błędy. Kiedy gotując prze- go przy pomocy VCS - raz stworzona galeria raczej się już solimy ulubioną potrawę jest już za późno - nie zmieni. Inaczej mają się sprawy w przypadku tworzenia możemy tylko się skrzywić i przełknąć danie kodu aplikacji - nawet niewielka ingerencja może wywotakie, jakim jest albo je wyrzucić i zacząć cały proces od początku. Dwóch użytkowników Użytkownicy niezależnie Świat wirtualny jest nieco bardziej odczytuje ten sam plik wprowadzają modyfikacje z repozytorium wyrozumiały i w większości aplikacji istnieje opcja ‘cofnij’, dzięki Repozytorium Repozytorium której możemy odwołać ostatnio A A wprowadzone zmiany. Jednak i to może okazać się niewystarczaodczyt odczyt jące w przypadku bardziej skomplikowanych scenariuszy. Co jeśli od wprowadzenia błędu do kodu A A A' A'' programu minęło wiele miesięcy i Użytkownik1 Użytkownik2 Użytkownik1 Użytkownik2 dziesiątki dalszych modyfikacji? Jak mogę eksperymentować i testoUżytkownik1 publikuje Użytkownik2 publikuje wać swoje poprawki nie wpływa(wysyła na repozytorium) swoje zmiany i w efekcie jąc jednocześnie na pracę kolegów swoje zmiany jako pierwszy przypadkowo nadpisuje pracę Użytkownika1 z zespołu? Odpowiedzią na te proRepozytorium Repozytorium blemy jest system kontroli wersji prawdziwa maszyna czasu i kroniA A karz rozwoju naszych aplikacji. System kontroli wersji (ang. verzapis zapis sion/revision control system - VCS) sprawdza się wszędzie tam, gdzie A' A'' A' A'' historia rozwoju ma dla nas znaczenie, a pliki często zmieniają swoUżytkownik1 Użytkownik2 Użytkownik1 Użytkownik2 ją zawartość. Jeśli chcemy podzielić się ze znajomymi zdjęciami z ostatnich wakacji, nie ma sensu robić te- Rysunek 1. Przykładowe nadpisanie zawartości pliku (na podstawie [2]) 26
1/2014
Kontrola wersji na przykładzie Subversion
łać efekt domino i spowodować poważne błędy. W takiej sytuacji chcemy mieć możliwość szybkiego cofnięcia wprowadzonych zmian tak, aby wrócić do ostatniej stabilnej wersji rozwijanego oprogramowania. Jeśli działamy w większym zespole dobrze jest też wiedzieć, kto jest odpowiedzialny za daną zmianę. W przypadku konieczności stworzenia dedykowanej wersji naszej aplikacji dla nowego klienta, która różnić się będzie wyłącznie logo i komunikatem na ekranie powitalnym, nie będziemy przecież pisali wszystkiego od początku. Rozsądnym zdaje się wzięcie gotowego produktu, skopiowanie go w inne miejsce i wprowadzenie koniecznych zmian. Jeśli w przyszłości okaże się, że aplikacja ta zawiera jakiś błąd, prawdopodobnie będzie on widoczny we wszystkich wersjach - system kontroli wersji pozwoli nam na łatwe wprowadzenie poprawki, która obejmie każde wydanie.
Trochę historii i kilka słów o systematyce
Użytkownik1 blokuje dostęp do pliku po czym ściąga go z repozytorium w celu dokonania modyfikacji y
W trakcie edycji pliku A przez Użytkownika1 Użytkownik2 nie może otrzymać dostępu pliku ęp do p
Repozytorium
Repozytorium
A
A
blokada
A
A
A'
A
Użytkownik1
Użytkownik2
Użytkownik1
Użytkownik2
Użytkownik1 po zakończeniu swoich zmian wysyła plik na repozytorium oraz ściąga ąg blokadę ę
Użytkownik2 może teraz odczytać plik oraz edytować jego zawartość
Repozytorium
Repozytorium
A' zapis
A A' odczyt blokada
odblokuj dostęp
A'
A
A
A
Użytkownik1
Użytkownik2
Użytkownik1
Użytkownik2
Rysunek 2. Zasada działania mechanizmu ‘lock-modify-unlock’ (na
Systemy kontroli wersji nie są podstawie [2]) niczym nowym, a ich historia sięga czasów, kiedy komputery osobiste dopiero nieśmiało stawiały pierwsze kroki. Source Code Control System (SCCS) powstał w roku 1972. Oczywiście posiadał on wiele wad i niedogodności w porównaniu do rozwiązań stosowanych w dzisiejszej dobie. Podobnie jak jego dziesięć lat później wydany następca, Revision Control System, mógł pracować jedynie na lokalnych plikach. Krokiem naprzód było stworzenie Concurrent Version System (CVS), który pracuje w architekturze klient-serwer. Skąd w nazwie słówko ‚konkurencyjny’? System ten stworzony został z myślą o pracy zespołowej, dopuszczając jednoczesną modyfikację danego pliku przez wiele osób - domyślnie mechanizm blokowania dostępu (file lock) jest tu wyłączony (więcej o tym problemie mówi kolejny rozdział). Z jakimi problemami boryka się zatem CVS? Po pierwsze tworzenie równolegle rozwijanych wersji plików (tak zwane ‚branchowanie’) jest operacją zajmującą sporo czasu i pochłaniającą dużo miejsca na dysku serwera - literalnie tworzona jest tam kopia całej aplikacji. Po drugie - wysyłanie zmian na serwer (tak zwane ‚commitowanie’ zmian) nie jest operacją atomową. Znaczy to, że jeśli proces ten zowww.sdjournal.pl
odczyt
odczyt
stanie przerwany (system nagle odmówi posłuszeństwa bądź połączenie sieciowe zostanie zerwane), zostaniemy „gdzieś pośrodku”, w sytuacji o nieznanym stanie. CVS nie wspiera także operacji przeniesienia pliku w inne miejsce struktury katalogowej bądź zmiany jego nazwy. Jedynym rozwiązaniem jest skasowanie pliku i stworzenie go na nowo w docelowym miejscu bądź z nową nazwą - wykonując to musimy się pogodzić z utratą historii operacji. Problemy te doprowadziły do powstania Subversion bohatera praktycznej części niniejszego artykułu. Subversion został zaprojektowany jako lepsza wersja CVS, rozwiązująca wyżej wspomniane problemy, a jednocześnie czerpiąca z największych zalet swojego protoplasty - prostoty obsługi oraz wysokiej elastyczności. Prace nad rozwojem Subversion zostały rozpoczęte w roku 2000 przez firmę CollabNet. Po czternastu miesiącach produkt był na tyle dojrzały, by móc samemu przechowywać własny kod źródłowy. Subversion jest projektem wciąż rozwijanym, najnowsza wersja 1.8 została wydana w roku 2013. Innym ważnym kierunkiem rozwoju systemów kontroli wersji są systemy rozproszone. W przeciwieństwie do architektury klient-serwer, systemy rozproszo27
ne (takie jak Git czy Mercurial) nie Dwóch użytkowników Użytkownicy niezależnie odczytuje ten sam plik wprowadzają modyfikacje wykorzystują centralnego repozyz repozytorium torium. Każdy użytkownik posiada Repozytorium Repozytorium własną wersję repozytorium na lokalnym komputerze, dzięki czemu A A może pracować i korzystać z zalet systemu kontroli wersji nawet bez odczyt odczyt podłączenia do sieci. Modyfikacje współdzielonych plików ściągane są bezpośrednio od innych użytkowA A A' A'' ników. Architektura taka powoduje znacznie lepszą skalowalność Użytkownik1 Użytkownik2 Użytkownik1 Użytkownik2 całego systemu, dzięki czemu idealnie nadaje się do rozwijania dużych Użytkownik2 publikuje Przy próbie zapisu Użytkownik1 (wysyła na repozytorium) otrzymuje komunikat błędu projektów open source. Wystarswoje zmiany jako pierwszy ('out-of-date' error) czy tu wspomnieć, że Gita zaprojektował i napisał w 2005 roku sam Repozytorium Repozytorium Linus Torvalds. Obecnie Git wykorzystywany jest do wersjonowania i A'' A'' rozwoju jądra Linuxa. „Rozproszone” podejście nie zapis zapis jest jednak całkowicie pozbawione wad. Ciężko jest w naturalny spoA' A'' A' A'' sób wdrożyć idee ciągłej integracji oprogramowania (ang. Continious Użytkownik1 Użytkownik2 Użytkownik1 Użytkownik2 integration) w oparciu o rozproszone systemy kontroli wersji. By teUżytkownik1 porównuje Użytkownik1 scala obie wersje plików go dokonać należy niejako zerwać własny plik z ostatnią wersją pobraną z repozytorium z zasadą całkowitego rozproszenia i wybrać jedno repozytorium, któRepozytorium Repozytorium re będzie pełniło rolę repozytorium centralnego i do którego napływać A'' A'' będą wszelkie zmiany. Możliwość korzystania z zalet kontroli werodczyt sji na lokalnej maszynie nie zachęca także do częstego wysyłania wproA' A'' A'' A* A'' wadzonych zmian innym użytkownikom, co również stoi w sprzecznoUżytkownik1 Użytkownik2 Użytkownik1 Użytkownik2 ści z zasadą ciągłej integracji. Należy jednak tu podkreślić, że są to proUżytkownik1 publikuje Użytkownik2 odczytuje blemy raczej ludzkie czy społeczne (wysyła na repozytorium) nowe zmiany z repozytorium. niż techniczne i przez ustanowiescaloną wersję pliku Obaj użytkownicy posiadają wersję pliku zawierającą erającą wszystkie zmiany zm nie odpowiednich zasad współpracy Repozytorium Repozytorium można je z powodzeniem przezwyciężyć. A* A'' By nakreślić pełny obraz podziału i rodzajów systemów kontroli werodczyt sji należy wspomnieć również o syszapis temach opartych na (bądź wspierających) strumienie (ang. stream-based A* A* A* A'' version control systems). Rozwiązania Użytkownik1 Użytkownik2 takie jak AccuRev i ClearCase oferują Użytkownik1 Użytkownik2 koncepcję drzewiastej struktury zależności pomiędzy różnymi strumie- Rysunek 3. Zasada działania mechanizmu ‘copy-modify-merge’ (na niami danych i automatycznej replika- podstawie [2]) 28
1/2014
Kontrola wersji na przykładzie Subversion
cji zmian, jeśli dany strumień dziedziczy po innym.
nie poprosić kolegę o zwolnienie dostępu. Sytuacja staje się trudniejsza w przypadku, gdy nasz zapominalski Modele współpracy współpracownik znajduje się po drugiej stronie oceanu. Jeśli tylko pracujemy w zespole, prędzej czy później na- Albo gdy właśnie wyjechał na wakacje. Angażowanie adtrafimy na sytuację, kiedy plik, który właśnie chcemy ministratora systemu za każdym razem nie wydaje się edytować jest modyfikowany przez inną osobę. Może być specjalnie elastycznym wyjściem. Blokowanie dostędoprowadzić to do przypadkowego nadpisania zmian - pu do plików prowadzi także do zbędnej serializacji zailustruje to Rysunek 1. dań. Jeśli ja i mój kolega faktycznie chcemy modyfikoNajprostszym wyjściem z takiej sytuacji jest... niedopusz- wać ten sam plik, ale w innych miejscach (np. edytując czenie do niej. Dokonuje się tego przez blokowanie plików zupełnie inne funkcje) nie ma powodu, żebyśmy czekali, (ang. lock-modify-unlock). Na czas wprowadzania modyfika- aż któryś z nas zakończy swoją pracę. Nasze zmiany z cji osoba odpowiedzialna za zmiany blokuje dostęp do da- powodzeniem mogą zostać wprowadzone równolegle. nego pliku. Po zakończonych poprawkach dostęp ten jest Z pomocą przychodzi tu mechanizm copy-modify-merzwalniany dla innych użytkowników (Rysunek 2). ge. To system kontroli wersji pomaga rozstrzygnąć czy Rozwiązanie to może wydawać się niezwykle efektyw- zmiany, które właśnie chcę wysłać na serwer nie nadpine, prowadzi jednak do kilku poważnych problemów. Po sują innych, nowych modyfikacji. Jeśli ja i mój współprapierwsze - co jeśli użytkownik zapomni zwolnić dostęp cownik właśnie edytowaliśmy tę samą linijkę kodu, VCS do pliku? Jeśli tylko współdzielimy jedną przestrzeń biu- zwróci moją uwagę na ten fakt i wstrzyma wysłanie zmian rową zawsze możemy przejść kilka biurek dalej i grzecz- na serwer. Sytuację taką nazywamy konfliktem. W obliczu konfliktu musimy zdecydować jak ostatecznie powinien wyglądać plik. Jeśli meA) develop on mainline chanizm ten wydaje się być niekończącym koszmarem modyfikacji i integracji commit: commit: commit: zmian to dobra wiadomość brzmi: wcanowa poprawka poprawka le tak nie jest! W istocie jest to bardzo funkcjonalność stabilności defektu efektywna metoda zarządzania zmianami, a prawdziwe problemy pojawiają się nader rzadko (Rysunek 3). Oczywiście nie istnieje jedna złota trunk (mainline) metoda, która działa doskonale w każdej sytuacji i która rozwiązuje wszystkie problemy. Dla przykładu - blokoB) branch for release wanie dostępu do plików może znaleźć swoje zastosowanie, kiedy modyfikacji wydanie 1.0 podlegają pliki binarne, które musimy commit: akceptować bądź odrzucać w całości. poprawka Systemy kontroli wersji oddają w rędefektu wydanie 1.1 ce użytkowników jedynie narzędzia commit: - wciąż największą trudnością jest popoprawka defektu prawne z nich skorzystanie. trunk (mainline)
Odrobina prywatności, czyli branchowanie
C) branch for f feature f nowa funkcjonalność
commit: poprawka defektu
commit: zmiana drzewa plików
trunk (mainline)
Rysunek 4. Przykładowe strategie branchowania (na podstawie [1])
www.sdjournal.pl
Operację powielenia zasobów w obrębie systemu kontroli wersji nazywamy branchowaniem. Istnieje kilka powodów, dla których możemy chcieć stworzyć nową gałąź w naszym VCSie. Podstawową zaletą pracy we własnej branchy jest izolacja - możemy tam swobodnie eksperymentować z kodem aplikacji bez obaw, iż nasze zmiany popsują pracę innych. Podstawową wadą pracy we własnej branchy jest... izolacja. Synchronizacja zmian dokonywanych przez 29
innych programistów czy w końcu udostępnienie naszej pracy innym może okazać się prawdziwym wyzwaniem. Kolejne akapity przedstawiają podstawowe strategie pracy z branchami – dobre nawyki jak i często spotykane błędy. Polityka pracy bez branchowania (ang. develop on mainline)
Oczywiście można wyobrazić sobie projekty, które intensywnie korzystają z systemów kontroli wersji, jednak świadomie nie stosują branchowania przy tworzeniu nowych funkcjonalności. Wszelkie zmiany w kodzie są bezpośrednio zapisywane do głównego strumienia, nazywanego z ang. trunkiem bądź mainlinem. Autorzy [1] przekonują, że rozwiązanie takie niesie za sobą wiele zalet. Po pierwsze - zdecydowanie ułatwia ciągłą integrację oprogramowania. Dokonywane zmiany są natychmiast widziane przez
wszystkich współpracowników, nie istnieje zatem niebezpieczeństwo utraty kompatybilności kodu, nad którym pracują programiści. Należy pamiętać, że utrzymanie każdej gałęzi wiąże się z koniecznością poniesienia dodatkowego kosztu: synchronizacji branchy i różnych poprawek, rozwiązywania ewentualnych konfliktów i problemów z integracją oraz dodatkowym testowaniem kodu znajdującego się w branchy. Z drugiej strony wprowadzenie dużych zmian funkcjonalnych bądź przeprowadzenie refaktoryzacji kodu aplikacji bezpośrednio w trunku może okazać się bardzo trudne (choć nie niemożliwe, jeśli zmiany takie odpowiednio się zaplanuje i podzieli na szereg mniejszych kroków). Niemniej jednak rozwijanie aplikacji bez użycia branchy może doprowadzić do chwilowych niestabilności kodu. Problematyczne też może okazać się wydawanie kolejnych wersji aplikacji - przy takiej polityce niemal zawsze w trunku znajduje się część implementacji jakiejś nowej funkcjonalności. (Rysunek 4 A) Tworzenie branchy stabilizacyjnych (ang. branch for release)
konsolowy klient aplikacji
graficzne klienty aplikacji interfejs klienta biblioteka klienta
biblioteka zarządzająca Working Copy
dostęp do repozytorium DAV
SVN
lokalnie
sieć TCP/IP
Tworzenie branchy dla rozwoju nowych funkcjonalności (ang. branch for feature)
Apache mod_dav mod_dav_svn
svnserve interfejs repozytorium
Repozytorium Subversion
Berkeley DB
FSFS
Rysunek 5. Architektura Subversion (na podstawie [2])
30
Jest to nieco zmodyfikowana wersja poprzedniej strategii. W dalszym ciągu wszystkie nowe funkcjonalności opracowywane są w trunku, jednak tuż przed wydaniem oprogramowania do klienta tworzona jest specjalna gałąź, która służy celom testowym. Naprawiane są także w niej krytyczne defekty tworzonego oprogramowania (poprawki te należy bezwzględnie zintegrować z mainlinem - ilustruje to Rysunek 4 B). Branche takie nie wracają później do trunka; stają się one dostarczanymi do klienta wersjami aplikacji.
Chyba najczęściej stosowanym powodem tworzenia branchy jest rozwijanie nowych funkcjonalności bez ingerencji w trunka (należy pamiętać, że niezależnie od wybranej strategii w trunku powinna znajdować się działająca wersja rozwijanej aplikacji). Inną zaletą jest tu komfort programistów - większość ludzi nie lubi upubliczniania swojej pracy, gdy ta jeszcze nie jest zakończona. Omawiana strategia zachęca do eksperymentowania i daje dużą swobodę. Łatwo jest jednak wpaść w pułapkę zbyt 1/2014
Kontrola wersji na przykładzie Subversion
długo żyjących branchy - odroczenie reintegracji może doprowadzić do ujawnienia się niespodziewanych zależności szczególnie, jeśli nieprzestrzegana była zasada częstej (codziennej) synchronizacji zmian dokonywanych w mainlinie z rozwijaną branchą. Jaskrawo rysują się tu także problemy z utrzymaniem prawdziwej ciągłej integracji oprogramowania (zagadnienie zasygnalizowane przy omawianiu rozproszonych systemów kontroli wersji) oraz dodatkowe nakłady potrzebne na testowanie - zarówno podczas rozwoju branchy jak i stanu aplikacji po reintegracji do trunka. Polityka ta w efekcie może doprowadzić do znacznego opóźnienia wydania oprogramowania. (Rysunek 4 C) Branche dedykowane zespołom, komponentom, dostawcom
Jedną z głównych zalet systemów kontroli wersji jest ich elastyczność. Łatwo możemy przystosować ich działanie do naszych potrzeb i przy pomocy branchy odzwierciedlić różne polityki panujące w naszym zespole czy firmie. Dzięki temu możliwe jest stworzenie niezależnych gałęzi dla logicznie odseparowanych komponentów rozwijanej aplikacji. Możemy także stworzyć branche, które służyć będą testowaniu kompatybilności naszej aplikacji i zewnętrznych bibliotek, dostarczanych przez firmy trzecie. Ważne jest jednak, by polityki tworzenia branchy się nie przenikały. Różne gałęzie powinny być możliwie niezależne od siebie. Należy również jasno określić zasady wprowadzania poprawek i ich dostarczanie pomiędzy branchami. Jak zwykle kluczem do sukcesu okazuje się świadomość zalet i zagrożeń, które niesie ze sobą wprowadzenie danej strategii. Wiele zależy tu od charakteru projektu, nad którym pracujemy. Jeszcze ważniejsze zdają się być umiejętności, doświadczenie i zgranie zespołu. Mimo, iż systemy kontroli wersji niezwykle ułatwiają śledzenie zmian, nic nie jest tak efektywne jak rozmowa i omówienie problemu twarzą w twarz.
Praktyka - pierwsze kroki.
Po teoretycznym wstępie czas na bliższe przyjrzenie się Subversion. Uważny i bardziej wymagający Czytelnik może zadawać sobie pytanie: czemu wybór padł właśnie na ten system kontroli wersji? - odpowiedź jest bardzo prosta. Jest to dojrzały, wciąż rozwijany, darmowy i niezwykle popularny system, który dzięki swojej prostocie idealnie nadaje się, jako przykład dydaktyczny i punkt startowy, pozwalający łatwo wejść w świat VCSów. Częścią Subversion, z której za chwilę zaczniemy korzystać, jest konsolowy klient tego systemu - SVN (od liter SubVersioN). Jego popularność jest na tyle duża, iż cały system przyjęło w skrócie nazywać właśnie SVN. Oczywiście istnieje wiele innych klientów bądź nakładek oferujących graficzny interfejs (chyba najpopularniejszą jest TortoiseSVN), jednak zrozumienie działania systemu najlepiej wytłumaczyć korzystając właśnie z wiersza poleceń. Powww.sdjournal.pl
Listing 1. Założenie repozytorium # przejdź do ścieżki docelowej $ cd ~/Documents/SVN/
# stwórz nowe repozytorium o nazwie myRepo1 $ svnadmin create myRepo1
Listing 2. Struktura nowego repozytorium # przejdź do katalogu myRepo1 $ cd myRepo1/
# sprawdź zawartość katalogu $ ls
README.txt conf
db
format
hooks
locks
Listing 3. Pierwsze working copy # przejdź do ścieżki docelowej $ cd ~/Documents/SVN/workingCopy/ # katalog workingCopy jest pusty $ $
# wykonaj polecenie checkout (skrócona nazwa: # svn co); jako argument # przekazać należy ścieżkę do wcześniej # stworzonego repozytorium $ svn checkout file:///Users/Slawek/Documents/ SVN/myRepo1
Checked out revision 0.
# w katalogu workingCopy pojawił się podkatalog # o nazwie repozytorium: myRepo1 $ ls
myRepo1
$ cd myRepo1/
# repozytorium jest w chwili obecnej puste $ ls $
Listing 4. Podstawowa struktura katalogów # stwórz w working copy nowe katalogi: $ svn mkdir trunk branches tags
A
trunk
A
tags
A
branches
# wyślij nowe katalogi na repozytorium $ svn commit -m „podstawowa struktura katalogow”
Adding
branches
Adding
trunk
Adding
tags
Committed revision 1.
# sprawdź strukturę repozytorium $ svn ls file:////Users/Slawek/Documents/SVN/
branches/
myRepo1/
tags/
trunk/
31
zwoli to na zapoznanie się z poszczególnymi komendami oraz ułatwi orientację użytkownikom różnych systemów operacyjnych (poniższe przykłady zostały wykonane na systemie typu Unix, jednak ich wykonanie pod Windowsem nie powinno nastręczyć żadnych problemów). Pełną architekturę Subversion prezentuje Rysunek 5. W niniejszym tekście nie omówimy wszystkich technicznych szczegółów - na chwilę tylko zanurzymy się w głąb tego diagramu, tworząc lokalne repozytorium, po czym już konsekwentnie znajdziemy się po stronie klienta, odgrywając rolę codziennego użytkownika. Informacją, którą niewątpliwie warto jest jednak zapamiętać z tego akapitu jest fakt, iż do repozytorium Subversion możemy połączyć się na trzy różne sposoby. Jeśli repozytorium znajduje się na naszej lokalnej maszynie, możemy podłączyć się do niego przez operacje klienta na adresach typu file:///ścieżka/ do/repozytorium - właśnie z tej opcji skorzystamy w dalszej części tekstu. Częściej spotykana jest jednak sytuacja, kiedy serwer hostujący repozytorium znajduje się nie lokalnie, a umiejscowiony jest gdzieś w sieci, do której jesteśmy podłączeni. Mamy tu dwie możliwości: możemy skorzystać z rozwiązania WebDAV/Delta-V (co w praktyce znaczy dla użytkownika, iż do klienta poda ścieżkę w formacie http:// host/ścieżka bądź w przypadku połączenia bezpiecznego: https://host/ścieżka). Ostatnią możliwością jest wykorzystanie własnego protokołu dostarczanego przez Subversion (adres w formacie svn://host/ścieżka bądź dla bezpiecznego połączenia svn+ssh://host/ścieżka). Przyszedł czas na pierwsze praktyczne operacje. Oczywiście doskonałym miejscem, by zapoznać się z Subversion jest wykonanie polecenia svn help - lekturę wyników pozostawiamy Czytelnikowi. By zacząć pracę musimy założyć nowe repozytorium (Listing 1). Tym samym założyliśmy repozytorium o nazwie myRepo1. Jeśli do niego zajrzymy okaże się, że nie jest to zwyczajny pusty katalog - znajduje się tam kilka plików i podkatalogów (Listing 2). Zarządzanie i konfiguracja repozytorium jest obszernym tematem, którego nie sposób tu pokryć - na potrzeby tego poradnika wystarczy informacja, że plików wyświetlonych powyżej nie powinniśmy ręcznie edytować. Od tej chwili na założonym repozytorium będziemy wykonywali operacje jedynie przez klienta. Edycja plików będących pod opieką systemu kontroli wersji nie odbywa się zwykle bezpośrednio na serwerze chcemy przecież skorzystać z naszego ulubionego edytora do pisania kodu. Musimy także mieć możliwość przetestowania wprowadzanych zmian. By to umożliwić stworzymy teraz tak zwane working copy - lokalną kopię plików z repozytorium. Warto już na wstępie naświetlić kilka rzeczy: po pierwsze - nie musimy ściągać z repozytorium Subversion wszystkich plików się tam znajdujących. Jeśli pracuję nad jednym tylko plikiem, być może nie potrzebuję setek innych plików rozwijanych przez moich współpracowników. Zwykle jednak do working copy ściąga się (w termi32
nologii svn: checkout) całą zawartość trunka bądź branchę, nad którą właśnie pracujemy. Po drugie - Subversion nie wyraża samo z siebie przesadnego zainteresowania naszymi working copy; liczba mnoga została tu użyta nie przez Listing 5. Polecenie svn status # sprawdź status working copy $ svn status
?
myScript.py
?
svn-book.pdf
# dwa pliki są poza systemem kontroli wersji # spróbuj je wysłać do repozytorium $ svn ci -m „dodanie pierwszych plikow”
# sprawdź status working copy $ svn st
?
myScript.py
?
svn-book.pdf
# pliki nie zostały wysłane # należy najpierw przekazać Subversion, # że pliki te # chcemy objąć kontrolą wersji $ svn add myScript.py svn-book.pdf
A A
myScript.py
(bin)
svn-book.pdf
# pliki zmieniły swój status z ‘?’ na ‘A’ $ svn st
A A
myScript.py
svn-book.pdf
# wyślij pliki do repozytorium $ svn ci -m „dodanie pierwszych plikow”
Adding Adding
myScript.py
(bin)
svn-book.pdf
Transmitting file data .. Committed revision 2.
# operacja się powiodła. Repozytorium zmieniło # numer rewizji # sprawdź status working copy $ svn st $
# wszystkie pliki dodano
Listing 6. modyfikacje istniejących plików # sprawdź status workig copy $ svn st
M
myScript.py
# zawartość pliku została zmodyfikowana # (świadczy o tym litera “M” w pierwszej # kolumnie wyjścia polecenie svn status) # wyślij zmiany na serwer $ svn ci -m „zwiekszenie liczby przebiegow petli”
Sending
myScript.py
Transmitting file data . Committed revision 3.
1/2014
Kontrola wersji na przykładzie Subversion
przypadek - w jednej chwili możemy mieć dowolnie wiele working copy, w różnych miejscach naszej struktury katalogów. Możemy je dowolnie kasować, przenosić, modyfikować. Łączność z repozytorium następuje wyłącznie na nasze wyraźne życzenie przekazane do serwera za pośrednictwem klienta. Listing 3 pokazuje kilka istotnych rzeczy; mimo, iż jak wcześniej dowiedliśmy, w katalogu repozytorium znajdują się pewne automatycznie generowane pliki, użytkownik ściągając zawartość repozytorium ich nie otrzymuje. Ostatecznie są to tylko pliki konfiguracyjne, niezwiązane z rozwijanym projektem; czemu zatem miałby być nimi zainteresowany (tym bardziej, że użytkownik nie powinien mieć możliwości zmiany tych plików). Wprowadzone zostaje tu także kluczowe pojęcie dla Subversion - numer rewizji (ang. revision). Każda operacja zmieniająca zawartość bądź układ plików na repozytorium zwiększa numer jego rewizji. Co istotne - numer ten jest globalny, dotyczy całego repozytorium. Jeśli zatem wprowadzone zmiany w pliku A zostaną wysłane na repozytorium, także niezmieniany ostatnio plik B znajdzie się w nowej rewizji. Jak już zostało wcześniej wspomniane, Subversion jest
systemem pozwalającym na ogromną swobodę. Niemniej jednak zwyczajowo przyjęło się kilka ogólnych zasad - jedną z nich jest stworzenie na repozytorium struktury katalogów „trunk, branches, tags” dla każdego projektu. Pojęcia trunk (inaczej: mainline) oraz wykorzystanie branchy zostały już wcześniej wyjaśnione. Katalog tags to nic innego, jak specjalne branche, które odzwierciedlają jakiś ważny punkt w rozwoju aplikacji - osiągnięcie kamienia milowego projektu bądź wydanie pierwszej klienckiej wersji. Skoro numer rewizji repozytorium jest globalny, można oczywiście skorzystać z funkcji „wehikułu czasu” systemu kontroli wersji i przenieść się do interesującej nas rewizji - łatwiej jednak jest zapamiętać zrozumiałą dla człowieka nazwę taga (np. „Release_1.0”) niż informację, że pierwsza stabilna wersja oprogramowania znajduje się w rewizji 9876545. Niemniej jednak jeszcze raz wartym podkreślenia jest fakt, że to tylko (szeroko stosowana) konwencja, nie zaś obowiązek. Nie kryją się za tym też żadne specjalne zachowania Subversion, więc jeśli Czytelnik uzna, że proponowany układ nie odpowiada jego potrzebom, może swobodnie zdecydować się na inny porządek bądź nawet zmienić go podczas rozwoju swojej aplikacji.
Listing 7. Historia modyfikacji # wykonaj update working copy $ svn up
Updating ‘.’:
At revision 3.
# sprawdź historię commitów # widoczny jest numer rewizji, autor modyfikacji, data oraz komentarz $ svn log
-----------------------------------------------------------------------r3 | Slawek | 2013-12-09 12:59:17 +0100 (pon, 09 gru 2013) | 1 line zwiekszenie liczby przebiegow petli
-----------------------------------------------------------------------r2 | Slawek | 2013-12-09 12:52:18 +0100 (pon, 09 gru 2013) | 1 line dodanie pierwszych plikow
-----------------------------------------------------------------------r1 | Slawek | 2013-12-08 14:36:50 +0100 (ndz, 08 gru 2013) | 1 line podstawowa struktura katalogow
-----------------------------------------------------------------------# historię commitów można także sprawdzić bezpośrednio na repozytorium $ svn log file:///Users/Slawek/Documents/SVN/myRepo1/trunk
-----------------------------------------------------------------------r3 | Slawek | 2013-12-09 12:59:17 +0100 (pon, 09 gru 2013) | 1 line zwiekszenie liczby przebiegow petli
-----------------------------------------------------------------------r2 | Slawek | 2013-12-09 12:52:18 +0100 (pon, 09 gru 2013) | 1 line dodanie pierwszych plikow
-----------------------------------------------------------------------r1 | Slawek | 2013-12-08 14:36:50 +0100 (ndz, 08 gru 2013) | 1 line podstawowa struktura katalogow
------------------------------------------------------------------------
www.sdjournal.pl
33
Stworzenie katalogów zaprezentowane w Listingu 4 odbyło się w dwóch krokach - najpierw dokonaliśmy tego w naszym working copy. Litera ‚A’ w pierwszej kolumnie oznacza, że pliki bądź katalogi są nowymi zasobami, przeznaczonymi do wysłania. W drugim kroku poprosiliśmy klienta o zatwierdzenie naszych zmian i wysłanie ich do repozytorium (polecenie commmit); jak widać na listingu spowodowało to zwiększenie numeru rewizji z 0 do 1. Po przełączniku -m podawany jest komentarz; jest to niezwykle istotne, by wysyłane komentarze dokładnie opisywały wprowadzane zmiany. Pomaga to w późniejszym nawigowaniu po historii.
Praktyka - operacje na plikach
Nasz projekt rozwija się - stworzono nowy skrypt oraz instrukcję w formacie pdf co widać na Listingu 5 (w niniejszym artykule skupiamy się głównie na plikach tekstowych, będących kodem źródłowym aplikacji; podkreślić jednak należy, że Subversion może przechowywać dowolny typ plików). Do sprawdzenia stanu working copy służy polecenie svn status (svn st) Po wykonaniu polecenia svn status w pierwszej kolumnie, pojawił się znak zapytania. Mówi on, iż są to nowe pliki, niebędące jeszcze pod kontrolą VCS. Zanim takie
Listing 8. Wyświetl zawartość pliku # wyświetl zawartość pliku myScript w rewizji numer 2 (przełącznik -r). $ svn cat file:///Users/Slawek/Documents/SVN/myRepo1/trunk/myScript.py -r2
#!/usr/bin/python # to tylko petla
for i in range(10): print i
Listing 9. Wyświetl różnicę zawartości pliku # wyświetl zmiany dokonane w pliku myScript pomiędzy rewizją numer 2 a najnowszą dostępną (HEAD) $ svn diff file:///Users/Slawek/Documents/SVN/myRepo1/trunk/myScript.py -r2:HEAD
Index: myScript.py
=================================================================== --- myScript.py (revision 2) +++ myScript.py (revision 3) @@ -1,5 +1,5 @@
#!/usr/bin/python # to tylko petla
-for i in range(10): +for i in range(13): print i
Listing 10. Tworzenie nowej branchy # sprawdź rozmiar repozytorium $ du -sh /Users/Slawek/Documents/SVN/myRepo1/
1,8M /Users/Slawek/Documents/SVN/myRepo1/
# sprawdź zawartość katalogu branches na repozytorium $ svn ls file:///Users/Slawek/Documents/SVN/myRepo1/branches
# stwórz na podstawie trunka nową gałąź o nazwie mojaGalaz $ svn copy file:///Users/Slawek/Documents/SVN/myRepo1/trunk file:///Users/Slawek/Documents/SVN/myRepo1/branches/ mojaGalaz/ -m ‚stworzenie mojej galezi’
Committed revision 4.
# sprawdź czy mojaGalaz pojawiła się na repozytorium $ svn ls file:///Users/Slawek/Documents/SVN/myRepo1/branches
mojaGalaz/
# ponownie sprawdź rozmiar repozytorium $ du -sh /Users/Slawek/Documents/SVN/myRepo1/
1,8M /Users/Slawek/Documents/SVN/myRepo1/ # wielkość repozytorium nie uległa zmianie
34
1/2014
Kontrola wersji na przykładzie Subversion
pliki będziemy w stanie wysłać do repozytorium, musimy wyraźnie powiedzieć Subversion, że tego chcemy - dokonuje się tego przy pomocy polecenia svn add. Następnie już bez przeszkód pliki zostały przesłane. Wyjście polecenia svn status może być dość skomplikowane - oprócz samego znaku ważna jest też jego pozycja: pierwsza kolumna oznacza modyfikację pliku, kolumna druga wskazuje na modyfikację właściwości (ang. properties - jest to rodzaj specjalnych metadanych; nie będziemy ich omawiali w tym artykule)... i tak aż do kolumny numer siedem. W pierwszej chwili może wydawać się to nieco przytłaczające, jednak lektura svn help st i odrobina praktyki powoduje, że w istocie analiza wyjścia polecenia svn status jest bardzo prosta i wręcz automatyczna. Prace nad projektem posuwają się, w wyniku czego konieczne było wprowadzenie modyfikacji do pliku myScript.py (Listing 6). Jeśli chcemy sprawdzić historię plików możemy dokonać tego przy pomocy polecenia svn log (Listing 7). DoListing 11. Przywracanie starej wersji pliku # wyświetl zawartość pliku myScript.py $ cat myScript.py
#!/usr/bin/python # to tylko petla
for i in range(13): print i
# przełącz plik myScript do postaci,
brze jest wcześniej upewnić się, ze nasze working copy zawiera najnowsze wersje plików - służy do tego polecenie svn update (svn up). Jeśli historia zawarta w komentarzach nie jest dla nas wystarczająca (autor artykułu pragnie jeszcze raz podkreślić, że jakość wysyłanych komentarzy ma często kluczowe znaczenie dla rozwoju projektu i komunikacji w zespole), zawsze możemy podejrzeć zawartość każdego pliku tekstowego w dowolnej rewizji; odpowiada za to polecenie svn cat (Listing 8). Często jednak istotniejszą informację niesie ze sobą podgląd zmian wprowadzonych pomiędzy różnymi rewizjami; w takim wypadku powinniśmy sięgnąć po polecenie svn diff (Listing 9). Znakami ‘-’ wskazano linie, które zostały usunięte. Znakami ‚+’ oznaczono linie, które w ostatniej rewizji zostały dodane. Jak widać w Listingu 9, zwiększona została liczba przebiegów pętli z 10 do 13 razy (co pokrywa się z komentarzem dołączonym do ostatniego commita).
$ svn cat myScript.py
#!/usr/bin/python # to tylko petla
for i in range(13): print i
‘trunk’ Slawek $
# plik nie został zmieniony w najnowszej rewizji
# w której był, kiedy repozytorium
# wykonaj ‘revert merge’ - przywrócenie pliku
# znajdowało się w drugiej rewizji
# do starszej wersji
$ svn up myScript.py -r 2
$ svn merge -r HEAD:2 myScript.py
Updating ‘myScript.py’: U
myScript.py
Updated to revision 2.
# wyświetl zawartość pliku myScript $ cat myScript.py
--- Recording mergeinfo for reverse merge of r4 U
myScript.py
U
myScript.py
through r3 into ‘myScript.py’:
--- Eliding mergeinfo from ‘myScript.py’:
#!/usr/bin/python
# wyświetl zawartość pliku myScript.py
# to tylko petla
#!/usr/bin/python
for i in range(10): print i
# (faktycznie, został on lokalnie zmieniony) # spróbuj wysłać zmianę na serwer
$ cat myScript.py
# to tylko petla
for i in range(10): print i
$ svn ci -m ‚powrot do starszej wersji’
# plik posiada lokalne modyfikacje,
# brak reakcji oraz brak lokalnych modyfikacji
$ svn st
$ svn st
# które możemy wysłać na serwer
# ściągnij najnowsze wersje plików z repozytorium
M
$ svn up
Updating ‘.’: U
myScript.py
Updated to revision 4.
# wyświetl zawartość pliku myScript.py
www.sdjournal.pl
myScript.py
$ svn ci -m „powrot do starszej wersji”
Sending
myScript.py
Transmitting file data . Committed revision 5. # commit się powiódł
35
Praktyka - branchowanie i mergowanie
Podczas przeglądu istniejących systemów kontroli wersji padło stwierdzenie, że Subversion dobrze radzi sobie z tworzeniem nowych branchy. Sprawdźmy jak jest w istocie (Listing 10). Operacje tworzenia nowych branchy w Subversion są „tanie” - nie konsumują dodatkowych zasobów dyskowych. Są także szybkie (jako operacje o stałej złożoności czasowej). Jeśli Czytelnik jest zaznajomiony z systemami operacyjnymi rodziny Unix, być może skojarzy to z dowiązaniami plików. Jeśli jednak pojęcie to brzmi obco należy uświadomić sobie, iż Subversion przetrzymuje jedynie oryginalne pliki oraz ewentualne ich zmiany (deltę) - tworząc kolejne branche nie kopiujemy całego drzewa katalogowego; tym samym nie powielamy zajętego miejsca na dysku. Z operacjami na branchach niemal nierozerwalnie wiąże się mergowanie, czyli proces łączenia zmian powstałych pomiędzy branchami. Jest jednak jeszcze jedno miejsce, kiedy polecenie svn merge znajduje swoje zastosowanie. Jest to sytuacja, w której pragniemy, by starsza wersja pliku stała się na powrót wersją obowiązującą (Listing 11). Częstym błędem jest próba zmiany wersji pliku przy pomocy polecenia svn update ze wskazaniem numeru rewizji, po
czym wywołanie polecenia svn commit - takie działanie się nie powiedzie. Załóżmy, że ktoś uznał, iż 13 przebiegów pętli w pliku Listing 12 Modyfikacja pliku w branchy # stwórz nowe working copy związane # z branchą mojaGalaz $ svn co file:///Users/Slawek/Documents/SVN/
myRepo1/branches/mojaGalaz
A
mojaGalaz/myScript.py
A
mojaGalaz/svn-book.pdf
Checked out revision 5. # ... edycja pliku
# sprawdź status working copy $ svn st
M
myScript.py
# wyślij zmiany na serwer $ svn ci -m „petla teraz wykonuje sie 21 razy”
Sending
myScript.py
Transmitting file data . Committed revision 6.
Listing 13 Mergowanie branchy do trunka (mf) mine-full
# jeśli brancha powraca do gałęzi (trunka) # z której powstała,
(tf) theirs-full
# należy użyć przełącznika --reintegrate $ svn merge --reintegrate file:///Users/Slawek/
Documents/SVN/myRepo1/branches/ mojaGalaz
(p)
postpone
SVN/workingCopy/trunk/trunk/
(l)
launch
Select: (p) postpone, (df) diff-full, (e) edit,
(s)
show all
Conflict discovered in ‘/Users/Slawek/Documents/ myScript.py’.
(mc) mine-conflict, (tc) theirs-conflict,
(s) show all options: s # wykryto konflikt. Pokaż wszystkie możliwości
- accept my version of
entire file (even non-conflicts)
- accept their version of
entire file (same)
- mark the conflict to be
resolved later
- launch external tool to
resolve conflict
- show this list
Select: (p) postpone, (df) diff-full, (e) edit, (mc) mine-conflict, (tc) theirs-conflict, (s) show all options: tf
(wciśnij s)
# wymuś przychodzącą (pochodzącą
(e)
edit
(df) diff-full (r)
resolved
- change merged file in an
--- Merging differences between repository URLs
merged file
U
- show all changes made to - accept merged version
of file
myScript.py
into ‘.’:
--- Recording mergeinfo for merge between U
.
repository URLs into ‘.’:
(dc) display-conflict - show all conflicts
# wyświetl zawartość pliku myScript.py
(mc) mine-conflict
- accept my version for all
#!/usr/bin/python
(tc) theirs-conflict
- accept their version for
(ignoring merged version) conflicts (same)
all conflicts (same)
36
# z branchy mojaGalaz) wersję pliku
editor
$ cat myScript.py
# to tylko petla
1/2014
Kontrola wersji na przykładzie Subversion
Listing 14. Kasowanie zreintegrowanej branchy # sprawdź zawartość katalogu branches # na serwerze $ svn ls file:///Users/Slawek/Documents/SVN/
mojaGalaz/
myRepo1/branches
# skasuj mojaGalaz $ svn delete file:///Users/Slawek/Documents/SVN/
myRepo1/branches/mojaGalaz -m
“brancha poddana reintegracji”
Committed revision 8.
# brancha została z powodzeniem usunięta $ svn ls file:///Users/Slawek/Documents/SVN/ $
myRepo1/branches
myScript to zbyt wiele i chce, by znów 10 iteracji (wersja z rewizji numer 2) znalazło się w trunku. Oczywiście możliwe jest przeprowadzenie ręcznej edycji pliku (podany przykład jest bardzo prosty), jednak jeśli modyfikacje byłyby bardziej skomplikowane, możemy potrzebować asysty Subversion. Jak tego dokonać prezentuje Listing 11. W tym samym czasie inny członek zespołu uznał, że z jakiś przyczyn konieczne jest, by pętla w pliku myScript wykonywała się aż 21 razy. Swoją pracę wykonuje w poprzednio przygotowanej branchy. Po zakończeniu zmian następuje moment, kiedy mojaGalaz przestaje być przydatna, a zmiany w niej wprowadzone powinny zostać wypromowane do trunka. By tego dokonać należy przejść do working copy trunka (oraz wykonać svn update, jeśli to konieczne,) a następnie wskazać adres branchy, którą będziemy reintegrowali (Listing 13). W tym przypadku konflikt został rozwiązany w sposób interaktywny (niemal natychmiast, bez dogłębnego studiowania zmian w plikach czy odwoływania się do zewnętrznych narzędzi). W rzeczywistości proces ten potrafi być nieco trudniejszy i często wymaga osobistej rozmowy pomiędzy programistami, tak by każdy zainteresowany dokładnie dowiedział się, co druga strona chciała osiągnąć przez wprowadzenia swoich zmian. Są to jednak tematy nieco bardziej zaawansowane - zainteresowanych Czytelników odsyłamy do [2]. Raz zreintegrowana brancha nie powinna być więcej wykorzystywana (choć istnieją sposoby, by ograniczenie to obejść). Możemy ją z czystym sumieniem i pełnym spokojem skasować (Listing 14). Nie musimy niczego się obawiać - ostatecznie działamy pod systemem kontroli
wersji. Skasowanie pliku czy całego drzewa usuwa je tylko z ostatniej rewizji repozytorium. W razie potrzeby zawsze możemy wrócić do skasowanych zasobów.
Słowo podsumowania
Systemy kontroli wersji są wspaniałym narzędziem, pozwalającym poczuć się nieco pewniej w dynamicznie zmieniającym się środowisku. Umożliwiają one wydajną współpracę pomiędzy programistami. Z powodzeniem mogą być też użyte do rozwoju małego, hobbistycznego projektu, nad którym będziemy pracowali w pojedynkę. Nic nie stoi na przeszkodzie, by w systemie kontroli wersji trzymać listę zakupów. Zastosowań może być tak wiele, jak okoliczności i pomysłów. Ważne jest tylko, by być świadomym kilku technicznych szczegółów - cała reszta zaawansowanych technik i skomplikowanych poleceń przyjdzie z czasem, wraz z rosnącymi wymaganiami. Niniejszy artykuł jedynie zaznaczył najważniejsze pojęcia. Miał on przybliżyć świat systemów kontroli wersji Czytelnikowi, który nigdy wcześniej z nich nie korzystał. Oczywiście pozostaje wiele tematów, które można jeszcze zgłębić: zaawansowane rozwiązywanie konfliktów, w tym konfliktów struktury plików; mixed i peg revisions; nadawanie propertiesów, organizacja repozytorium czy konfiguracja serwera. Niemniej jednak po przestudiowaniu informacji zawartych na kilku poprzednich stronach Czytelnik powinien być w stanie (lub przynajmniej mieć ochotę) spróbować skorzystać z jednego z wielu systemów kontroli wersji.
Sławomir Andrzejewski
Pracuje we wrocławskim oddziale firmy Nokia Solutions and Networks w dziale weryfikacji oprogramowania stacji bazowych systemu WCDMA. Do jego codziennych zadań należy automatyzacja testów regresyjnych.
Źródła
• [1] Humble J, Farley D: Continuous Delivery: Reliable Software Releases through Build, Test, and Deployment Automation. Addison-Wesley Professional 2010 • [2] Collins-Sussman B, Fitzpatrick BW, Pilato CM: Version Control with Subversion. For Subversion 1.7. (http://svnbook.red-bean.com/en/1.7/svn-book.pdf)
www.sdjournal.pl
37
Sposób na cyberprzestępców czyli jak się wyszkolić z bezpieczeństwa informatycznego Najsłabszym ogniwem bezpieczeństwa jest paradoksalnie człowiek. Nawet najbardziej zaawansowany system informatycznych zabezpieczeń nie sprawdzi się w walce z hakerami, jeśli jego użytkownik sam nie zadba o poufność przetwarzanych danych.
P
rężny rozwój systemów płatności online i archaiczne przepisy prawne, które z trudnością nadążają za rozwojem Internetu, pomagają cyberprzestępcom przeprowadzać zaawansowane ataki na dane pojedynczych użytkowników oraz wielkich firm czy agencji rządowych. Rozpowszechnienie urządzeń mobilnych wraz z możliwością instalacji aplikacji (np. systemu mobilnego Android lub innych) z nieautoryzowanych źródeł powoduje, iż przestępcy, do tej pory zainteresowani dziurami w Windowsie, coraz częściej atakują systemy mobilne. Ofiarami hakerów padają również korporacje i przedsiębiorstwa, które zbyt małą uwagę przykładają do zabezpieczeń kluczowych węzłów komunikacyjnych. Nawet jeśli użytkownicy systemów IT posiądą już świadomość zagrożeń i adekwatne kompetencje w zakresie podstaw ochrony danych i odpowiedzialnego zarządzania bezpieczeństwem informacji, to nadal pozostaje ogromne pole do popisu dla potencjalnych cyberprzestępców i hakerów w obszarze różnych, często podanych na ataki rozwiązań technologicznych zabezpieczeń ICT.
Internauta na celowniku
W ciągu ostatniego roku łącznie około 6 milionów polskich internautów padło ofiarą cyberprzestępców. 25% użytkowników przyznaje, że używa tego samego konta do prywatnych i służbowych celów, znacznie ułatwiając przestępcom kradzież danych osobistych, niezależnie od standardowych środków zabezpieczeń (takich jak chociażby szyfrowanie i certyfikacja SSL). Według doniesień F-Secure polska znalazła się niechlubnej czołówce europejskich krajów, w których hakerzy chętnie wykorzystują błędy w oprogramowaniu i systemach (tzw. exploity). Przyczyną popularności tego typu ataków jest rzadko wykonywana aktualizacja oprogramowania i rozwiązań sprzętowych, co umożliwia wykorzystywanie exploitów w celach przestępczych. Raport Trend Micro „Spear-Phishing Email: Most Favored APT Attack Bait” pokazuje, że tak jak w latach ubiegłych, 38
wielu włamań do sieci korporacji wciąż wykonuje się wykorzystując zainfekowane załączniki do maili. Wystarczy, że wiadomość otworzy jeden pracownik korporacji, aby na celowniku cyberprzestępców znalazły się dane krążące po wewnętrznej sieci całej firmy. Sprzyjają temu proste rozwiązania technologiczne zabezpieczeń (bardzo często bazujące na szyfrowaniu z rzadko wymienianymi kluczami kryptograficznymi). Z powodu fundamentalnych słabości klasycznych metod zabezpieczeń naukowcy starają się opracować nowe metody szyfrowania danych, w sposób jakościowy różniące się odpowiedzią na ataki. Jedną z obiecujących alternatyw klasycznych systemów kryptograficznych (które stanowią podstawę wszelkich rozwiązań bezpieczeństwa IT) okazuje się dziś kryptografia kwantowa. Precyzyjnie Kwantowa Dystrybucja Klucza (QKD) może wkrótce znaleźć szerokie zastosowanie na rynku telekomunikacyjnym, jak również pomóc lepiej zabezpieczyć kluczowe łącza budynków administracji publicznej i wrażliwych instytucji (np. finansowych, czy wojskowych). Do przesyłania danych wykorzystuje ona mikroskopową, zachowującą się w sposób kwantowy wielkość fizyczną układu kwantowo mechanicznego (np. polaryzację fotonu). Dzięki prawom mechaniki kwantowej, symetryczny i zupełnie losowo wygenerowany klucz służy do kodowania i dekodowania informacji, gwarantując teoretycznie absolutny, tj. bezwarunkowy poziom bezpieczeństwa wymiany danych. Wdrożenie takich rozwiązań na szeroką skalę pozwoliłoby choć w pewnym stopniu wyeliminować krytyczny czynnik ludzki w zakresie narażenia na ujawnienie informacji (np. poprzez hasła, umożliwiające do uzyskania dostępu do przechowywanych w systemach informatycznych rzadko zmienianych kluczy szyfrujących).
Nowy poziom bezpieczeństwa
Ignorancja i brak dostatecznej świadomości na temat zagrożeń czyhających w sieci o nowoczesnych rozwiązań technologicznych bezpieczeństwa IT to główne przyczyny problemów z utrzymaniem poufności, wiarygodności 1/2014
BEZPIECZEŃSTWO INTERNETOWE
i integralności danych. Rozwój społeczeństwa informacyjnego i gospodarki opartej na wiedzy, nie tylko oznacza wszechobecną wirtualizację procesów gospodarczoekonomicznych i społecznych, ale także rosnący poziom zagrożeń informatycznych. Międzynarodowy program certyfikacyjno-dydaktyczny Akademii EITCA/IS Bezpieczeństwo Informatyczne pozwala zapoznać się z zagrożeniami, słabymi punktami systemów zabezpieczeń, zdiagnozować ich stan i planować odp. działania. Specjalistyczny i obszerny programowo kurs dostępny jest obecnie w dofinansowaniu aż 80% przez Unię Europejską, pozwalając rozwinąć kompetencje w dziedzinie bezpieczeństwa nowoczesnych systemów elektronicznych i formalnie je potwierdzić certy-
www.sdjournal.pl
fikatem branżowym wydanym w Brukseli, realizując cały program i certyfikację zdalnie w trybie e-learningowym. Zakres merytoryczny Akademii EITCA/IS Bezpieczeństwa Informatycznego obejmuje wiedzę na temat sposobów zapewnienia prawidłowego funkcjonowania systemów informatycznych pod kątem poufności, wiarygodności i integralności przetwarzanych danych (w tym w szczególności istniejących zagrożeń, stosowanych metod kryptograficznych, teorii podstaw bezpieczeństwa informacji, metod zarządzania bezpieczeństwem informacji, aspektów formalno-prawnych, jak również szczegółowych zagadnień technicznych oraz technologii w dziedzinie zabezpieczeń sieci komputerowych i bezpieczeństwa systemów informatycznych).
39
Program kursu przeznaczony jest zarówno dla zawodowych informatyków jak również dla ogółu pracowników zajmujących się przetwarzaniem danych oraz pragnących nabyć lub poszerzyć swoje kompetencje w tej perspektywicznej dziedzinie informatyki. Uzyskaną podczas szkolenia profesjonalną wiedzę uczestnik kursu potwierdzi międzynarodowym certyfikatem ETICA/IS wydawanym w Brukseli, w języku angielskim wraz ze szczegółowym suplementem i odpisem w języku polskim. Certyfikat stanowi formalne, międzynarodowe potwierdzenie zdobytych kompetencji zawodowych w zakresie bezpieczeństwa informatycznego i może otworzyć drogę do rozwoju ciekawej kariery zawodowej w tym obszarze (interesująca jest tu w szczególności zgodność elementów programowych dotyczących formalnych aspektów bezpieczeństwa informatycznego z działaniami na szczeblu Komisji Europejskiej, zmierzających w ramach Cyfrowej Agendy Europejskiej w kierunku normalizacji zagadnień związanych z zarządzaniem bezpieczeństwem IT w organizacjach, jak również w zakresie aspektów technologicznych objęcie najnowszych rozwiązań i technologii zabezpieczeń). Akademia EITCA IS w szczególności dużą wagę przykłada do zastosowań kryptografii i informatyki kwantowej, które to dziedziny w niedalekiej przyszłości staną się wiodącymi aspektami zabezpieczania danych. Krajowy realizator programu EITCA (ICS CompLearn) jest częścią grupy technologicznej CompSecur sp. z o.o., która wraz z siecią naukową LFPPI, grupą laboratoriów NLTK, oraz Politechniką Wrocławską organizuje międzynarodowe V Sympozjum LFPPI “SeQre 2014” poświęcone postępowi w dziedzinie kryptografii kwantowej (http:// seqre.net/seqre2014) - na które to Sympozjum zapraszamy wszystkich zainteresowanych tą tematyką. Ponieważ komputery kwantowe stają się już rzeczywistością (Google i NASA kilka miesięcy temu wdrożyły Kwantowe Laboratorium Sztucznej Inteligencji: http:// www.youtube.com/watch?v=CMdHDHEuOUE w oparciu o drugą generację nadprzewodzących 512 qubitowych komputerów kwantowych DWave Two) następuje zmiana jakościowa w dziedzinie bezpieczeństwa informatycznego. Zabezpieczenia oparte na klasycznej kryptografii stają się wyraźnie zagrożone, a jedyną technologią, która zapewnia odporność zabezpieczenia kryptograficznego komunikacji przed komputerem kwantowym jest kryptografia kwantowa (dzięki oparciu na prawach mechaniki kwantowej oferuje ona także teoretycznie bezwarunkowy, tj. absolutny poziom bezpieczeństwa komunikacji, niemożliwy do złamania w przypadku założenia wyeliminowania tzw. dziur w implementacji). Podsumowując, w przypadku szerszego zainteresowania tymi kwestiami, lub innymi zagadnieniami wchodzącymi w zakres nowoczesnej informatyki stosowanej zachęcamy do zapoznania się z ofertą krajowej edycji Akademii EITCA, która dostępna jest do końca roku przy znacznie obniżonych kosztach dzięki dofinansowaniu unijnemu. 40
Aby skorzystać ze specjalnej oferty dofinansowania aż 80% kosztów nauki, dzięki wsparciu UE (EFRR), należy zarejestrować się w wybranym portalu kierunkowym Akademii EITCA i podać kod dofinansowania: SOKTW (linkuje do http://studia.complearn.pl/kod-obnizki.aspx?k od=SOKTW) Więcej na http://studia.complearn.pl (linkuje do http:// studia.complearn.pl/kod-obnizki.aspx?kod=SOKTW) Liczba miejsc z dofinansowaniem ze środków Unii Europejskiej jest ograniczona (dostępność miejsc można sprawdzić w formularzach rejestracyjnych na stronie kierunkowych EITCA): EITCA/IS Bezpieczeństwo Informatyczne (180h, zobacz program [linkuje do: http://www.bezpieczenstwo-informatyczne.eitca.pl/Informacjeiprogram/Programstudi%C3%B3w/ tabid/89/Default.aspx ]) Całkowity koszt z dofinansowaniem 80%: 880 zł (bez dofinansowania 4400 zł) Poza programem certyfikacyjnym Bezpieczeństwa Informatycznego Akademia EITCA obejmuje także inne kierunku nowoczesnej informatyki stosowanej, w tym: EITCA/KC Kluczowe Kompetencje IT (180h, zobacz program [linkuje do: http://www.kluczowe-kompetencje. eitca.pl/program]) Całkowity koszt z dofinansowaniem 80%: 840 zł (bez dofinansowania 4200 zł) EITCA/CG Grafika Komputerowa (150h, zobacz program [linkuje do: http://www.grafika-komputerowa.eitca. pl/program ]) Całkowity koszt z dofinansowaniem 80%: 880 zł (bez dofinansowania 4400 zł) EITCA/BI Informatyka Biznesowa (180h, zobacz program [linkuje do: http://www.informatyka-biznesowa.eitca.pl/Informacjeiprogram/Programstudi%C3%B3w/tabid/89/ Default.aspx ]) Całkowity koszt z dofinansowaniem 80%: 720 zł (bez dofinansowania 3600 zł) Więcej o Akademii EITCA: cg.eitca.pl kc.eitca.pl is.eitca.pl bi.eitca.pl www.eitca.pl www.eitci.org Facebook [linkuje do: https://www.facebook.com/ICSCompLearn] Zobacz wideo [linkuje do: http://www.youtube.com/watch?v=TZgIB5Rn5E4] --Sekretariat Akademii EITCA czynny pn-pt, w godzinach 10:00 – 17:00 e-mail: info@eitca.pl tel: (71) 722-80-47, (71) 722-80-48 infolinia: 801 011 647 1/2014
kod dla Czytelników: RABATSDJ zniżka na 15% Ważny : do 31.01.2014
http://helion.pl/ksiazki/hello-android-programowanie-na-platforme-google-dla-urzadzen-mobilnych-wydanie-iii-ed-burnette,handro.htm
Tytuł oryginału: Core Java Volume I--Fundamentals (9th Edition) Tłumaczenie: Łukasz Piwko ISBN: 978-83-246-7758-0 Authorized translation from the English language edition, entitled CORE JAVA VOLUME I – FUNDAMENTALS, 9TH EDITION; ISBN 0137081898; by Cay S. Horstmann; and Gary Cornell; published by Pearson Education, Inc, publishing as Prentice Hall. Copyright © 2013 by Oracle and/or its affiliates, 500 Oracle Parkway, Redwood Shores, CA 94065. All rights reserved. No part of this book may be reproduced or transmitted in any form or by any means, electronic or mechanical, including photocopying, recording or by any information storage retrieval system, without permission from Pearson Education Inc. Polish language edition published by HELION S.A. Copyright © 2013. Wszelkie prawa zastrzeżone. Nieautoryzowane rozpowszechnianie całości lub fragmentu niniejszej publikacji w jakiejkolwiek postaci jest zabronione. Wykonywanie kopii metodą kserograficzną, fotograficzną, a także kopiowanie książki na nośniku filmowym, magnetycznym lub innym powoduje naruszenie praw autorskich niniejszej publikacji. Wszystkie znaki występujące w tekście są zastrzeżonymi znakami firmowymi bądź towarowymi ich właścicieli. Wydawnictwo HELION dołożyło wszelkich starań, by zawarte w tej książce informacje były kompletne i rzetelne. Nie bierze jednak żadnej odpowiedzialności ani za ich wykorzystanie, ani za związane z tym ewentualne naruszenie praw patentowych lub autorskich. Wydawnictwo HELION nie ponosi również żadnej odpowiedzialności za ewentualne szkody wynikłe z wykorzystania informacji zawartych w książce. Wydawnictwo HELION ul. Kościuszki 1c, 44-100 GLIWICE tel. 32 231 22 19, 32 230 98 63 e-mail: helion@helion.pl WWW: http://helion.pl (księgarnia internetowa, katalog książek) Pliki z przykładami omawianymi w książce można znaleźć pod adresem: ftp://ftp.helion.pl/przyklady/javpd9.zip
Drogi Czytelniku! Jeżeli chcesz ocenić tę książkę, zajrzyj pod adres http://helion.pl/user/opinie/javpd9 Możesz tam wpisać swoje uwagi, spostrzeżenia, recenzję.
Printed in Poland.
• Kup książkę • Poleć książkę • Oceń książkę
• Księgarnia internetowa • Lubię to! » Nasza społeczność
Spis treÊci WstÂp ........................................................................................................................................................13 PodziÂkowania .........................................................................................................................................19 RozdziaÄ 1. WstÂp do Javy ........................................................................................................................21 1.1. 1.2.
1.3. 1.4. 1.5.
Java jako platforma programistyczna ................................................................... 21 Säowa klucze biaäej ksiögi Javy ............................................................................ 22 1.2.1. Prosty .................................................................................................. 23 1.2.2. Obiektowy ............................................................................................ 24 1.2.3. Sieciowy .............................................................................................. 24 1.2.4. Niezawodny .......................................................................................... 24 1.2.5. Bezpieczny ........................................................................................... 25 1.2.6. NiezaleĔny od architektury ..................................................................... 26 1.2.7. PrzenoĈny ............................................................................................ 26 1.2.8. Interpretowany ..................................................................................... 27 1.2.9. Wysokowydajny ..................................................................................... 27 1.2.10. Wielowñtkowy ....................................................................................... 28 1.2.11. Dynamiczny .......................................................................................... 28 Aplety Javy i internet .......................................................................................... 28 Krótka historia Javy ............................................................................................ 30 Gäówne nieporozumienia dotyczñce Javy .............................................................. 32
RozdziaÄ 2. Érodowisko programistyczne Javy ................................................................................... 37 2.1.
2.2. 2.3. 2.4.
Instalacja oprogramowania Java Development Kit ................................................. 38 2.1.1. Pobieranie pakietu JDK ......................................................................... 38 2.1.2. Ustawianie ĈcieĔki dostöpu ................................................................... 39 2.1.3. Instalacja bibliotek i dokumentacji ......................................................... 41 2.1.4. Instalacja przykäadowych programów ...................................................... 42 2.1.5. Drzewo katalogów Javy .......................................................................... 42 Wybór Ĉrodowiska programistycznego .................................................................. 43 UĔywanie narzödzi wiersza poleceþ ...................................................................... 44 2.3.1. Rozwiñzywanie problemów ..................................................................... 45 Praca w zintegrowanym Ĉrodowisku programistycznym .......................................... 47 2.4.1. Znajdowanie bäödów kompilacji .............................................................. 49
Kup książkę
Poleć książkę
4
Java. Podstawy 2.5. 2.6.
Uruchamianie aplikacji graficznej ......................................................................... 50 Tworzenie i uruchamianie apletów ....................................................................... 53
RozdziaÄ 3. Podstawowe elementy jÂzyka Java .................................................................................... 57 3.1. 3.2. 3.3.
Prosty program w Javie ....................................................................................... 58 Komentarze ....................................................................................................... 61 Typy danych ...................................................................................................... 62 3.3.1. Typy caäkowite ...................................................................................... 62 3.3.2. Typy zmiennoprzecinkowe ...................................................................... 63 3.3.3. Typ char ............................................................................................... 65 3.3.4. Typ boolean ......................................................................................... 66 3.4. Zmienne ........................................................................................................... 66 3.4.1. Inicjacja zmiennych ............................................................................... 68 3.4.2. Staäe ................................................................................................... 68 3.5. Operatory .......................................................................................................... 69 3.5.1. Operatory inkrementacji i dekrementacji ................................................. 71 3.5.2. Operatory relacyjne i logiczne ................................................................. 71 3.5.3. Operatory bitowe .................................................................................. 72 3.5.4. Funkcje i staäe matematyczne ................................................................ 73 3.5.5. Konwersja typów numerycznych ............................................................. 74 3.5.6. Rzutowanie .......................................................................................... 75 3.5.7. Nawiasy i priorytety operatorów .............................................................. 76 3.5.8. Typ wyliczeniowy ................................................................................... 77 3.6. ãaþcuchy .......................................................................................................... 77 3.6.1. Podäaþcuchy ......................................................................................... 78 3.6.2. Konkatenacja ....................................................................................... 78 3.6.3. ãaþcuchów nie moĔna modyfikowaè ....................................................... 79 3.6.4. Porównywanie äaþcuchów ...................................................................... 79 3.6.5. ãaþcuchy puste i äaþcuchy null .............................................................. 81 3.6.6. Wspóärzödne kodowe znaków i jednostki kodowe .................................... 81 3.6.7. API String ............................................................................................. 83 3.6.8. Dokumentacja API w internecie .............................................................. 85 3.6.9. Skäadanie äaþcuchów ............................................................................ 86 3.7. WejĈcie i wyjĈcie ................................................................................................ 89 3.7.1. Odbieranie danych wejĈciowych ............................................................. 89 3.7.2. Formatowanie danych wyjĈciowych ......................................................... 91 3.7.3. Zapis i odczyt plików ............................................................................. 96 3.8. Przepäyw sterowania ........................................................................................... 98 3.8.1. Zasiög blokowy ..................................................................................... 98 3.8.2. Instrukcje warunkowe ............................................................................ 99 3.8.3. Pötle ................................................................................................. 101 3.8.4. Pötle o okreĈlonej liczbie powtórzeþ ..................................................... 106 3.8.5. Wybór wielokierunkowy — instrukcja switch .......................................... 109 3.8.6. Instrukcje przerywajñce przepäyw sterowania ......................................... 111 3.9. Wielkie liczby ................................................................................................... 114 3.10. Tablice ............................................................................................................ 116 3.10.1. Pötla typu for each .............................................................................. 117 3.10.2. Inicjowanie tablic i tworzenie tablic anonimowych .................................. 118 3.10.3. Kopiowanie tablicy .............................................................................. 119 3.10.4. Parametry wiersza poleceþ .................................................................. 120 3.10.5. Sortowanie tablicy .............................................................................. 121
Kup książkę
Poleć książkę
Spis treÊci
5
3.10.6. Tablice wielowymiarowe ...................................................................... 124 3.10.7. Tablice postrzöpione ........................................................................... 127
RozdziaÄ 4. Obiekty i klasy ......................................................................................................................131 4.1.
4.2.
4.3.
4.4.
4.5. 4.6.
4.7.
4.8. 4.9.
Wstöp do programowania obiektowego .............................................................. 132 4.1.1. Klasy ................................................................................................. 132 4.1.2. Obiekty .............................................................................................. 133 4.1.3. Identyfikacja klas ................................................................................ 134 4.1.4. Relacje miödzy klasami ....................................................................... 135 UĔywanie klas predefiniowanych ........................................................................ 137 4.2.1. Obiekty i zmienne obiektów ................................................................. 137 4.2.2. Klasa GregorianCalendar ..................................................................... 139 4.2.3. Metody udostöpniajñce i zmieniajñce wartoĈè elementu ........................ 141 Definiowanie wäasnych klas .............................................................................. 148 4.3.1. Klasa Employee .................................................................................. 148 4.3.2. UĔywanie wielu plików Ēródäowych ........................................................ 151 4.3.3. Analiza klasy Employee ....................................................................... 151 4.3.4. Pierwsze kroki w tworzeniu konstruktorów ............................................. 152 4.3.5. Parametry jawne i niejawne ................................................................. 153 4.3.6. KorzyĈci z hermetyzacji ........................................................................ 155 4.3.7. Przywileje klasowe .............................................................................. 157 4.3.8. Metody prywatne ................................................................................ 157 4.3.9. Staäe jako pola klasy ........................................................................... 158 Pola i metody statyczne .................................................................................... 158 4.4.1. Pola statyczne .................................................................................... 159 4.4.2. Staäe statyczne ................................................................................... 159 4.4.3. Metody statyczne ................................................................................ 160 4.4.4. Metody fabryczne ................................................................................ 161 4.4.5. Metoda main ...................................................................................... 162 Parametry metod ............................................................................................. 164 Konstruowanie obiektów .................................................................................. 171 4.6.1. PrzeciñĔanie ....................................................................................... 171 4.6.2. Inicjacja pól wartoĈciami domyĈlnymi ................................................... 171 4.6.3. Konstruktor bezargumentowy ............................................................... 172 4.6.4. Jawna inicjacja pól .............................................................................. 172 4.6.5. Nazywanie parametrów ....................................................................... 174 4.6.6. Wywoäywanie innego konstruktora ........................................................ 174 4.6.7. Bloki inicjujñce ................................................................................... 175 4.6.8. Niszczenie obiektów i metoda finalize ................................................... 179 Pakiety ............................................................................................................ 180 4.7.1. Importowanie klas .............................................................................. 180 4.7.2. Importy statyczne ............................................................................... 182 4.7.3. Dodawanie klasy do pakietu ................................................................ 182 4.7.4. Zasiög pakietów ................................................................................. 185 ćcieĔka klas .................................................................................................... 187 4.8.1. Ustawianie ĈcieĔki klas ....................................................................... 189 Komentarze dokumentacyjne ............................................................................ 190 4.9.1. Wstawianie komentarzy ....................................................................... 190 4.9.2. Komentarze do klas ............................................................................ 191 4.9.3. Komentarze do metod ......................................................................... 191 4.9.4. Komentarze do pól ............................................................................. 192
Kup książkę
Poleć książkę
6
Java. Podstawy 4.9.5. Komentarze ogólne ............................................................................. 192 4.9.6. Komentarze do pakietów i ogólne ........................................................ 194 4.9.7. Generowanie dokumentacji .................................................................. 194 4.10. Porady dotyczñce projektowania klas ................................................................. 195
RozdziaÄ 5. Dziedziczenie .......................................................................................................................199 5.1.
5.2.
5.3.
5.4. 5.5. 5.6. 5.7.
5.8.
Klasy, nadklasy i podklasy ................................................................................ 200 5.1.1. Hierarchia dziedziczenia ...................................................................... 206 5.1.2. Polimorfizm ........................................................................................ 207 5.1.3. Wiñzanie dynamiczne .......................................................................... 209 5.1.4. Wyäñczanie dziedziczenia — klasy i metody finalne ................................ 211 5.1.5. Rzutowanie ........................................................................................ 212 5.1.6. Klasy abstrakcyjne .............................................................................. 214 5.1.7. Ochrona dostöpu ................................................................................ 219 Klasa bazowa Object ........................................................................................ 220 5.2.1. Metoda equals ................................................................................... 221 5.2.2. Porównywanie a dziedziczenie .............................................................. 222 5.2.3. Metoda hashCode .............................................................................. 225 5.2.4. Metoda toString ................................................................................. 228 Generyczne listy tablicowe ................................................................................ 233 5.3.1. Dostöp do elementów listy tablicowej ................................................... 236 5.3.2. ZgodnoĈè pomiödzy typowanymi a surowymi listami tablicowymi ............. 239 Osäony obiektów i autoboxing ............................................................................ 241 Metody ze zmiennñ liczbñ parametrów ............................................................... 244 Klasy wyliczeniowe ........................................................................................... 245 Refleksja ......................................................................................................... 247 5.7.1. Klasa Class ....................................................................................... 248 5.7.2. Podstawy przechwytywania wyjñtków .................................................... 250 5.7.3. Zastosowanie refleksji w analizie funkcjonalnoĈci klasy ......................... 252 5.7.4. Refleksja w analizie obiektów w czasie dziaäania programu .................... 257 5.7.5. Zastosowanie refleksji w generycznym kodzie tablicowym ...................... 261 5.7.6. Wywoäywanie dowolnych metod ............................................................ 264 Porady projektowe dotyczñce dziedziczenia ........................................................ 268
RozdziaÄ 6. Interfejsy i klasy wewnÂtrzne ...........................................................................................271 6.1.
6.2. 6.3. 6.4.
6.5.
Interfejsy ......................................................................................................... 272 6.1.1. WäasnoĈci interfejsów ......................................................................... 276 6.1.2. Interfejsy a klasy abstrakcyjne ............................................................. 279 Klonowanie obiektów ....................................................................................... 280 Interfejsy a sprzöĔenie zwrotne ......................................................................... 286 Klasy wewnötrzne ............................................................................................ 289 6.4.1. Dostöp do stanu obiektu w klasie wewnötrznej ..................................... 289 6.4.2. Specjalne reguäy skäadniowe dotyczñce klas wewnötrznych ..................... 293 6.4.3. Czy klasy wewnötrzne sñ potrzebne i bezpieczne? ................................. 294 6.4.4. Lokalne klasy wewnötrzne ................................................................... 296 6.4.5. Dostöp do zmiennych finalnych z metod zewnötrznych ........................... 297 6.4.6. Anonimowe klasy wewnötrzne .............................................................. 300 6.4.7. Statyczne klasy wewnötrzne ................................................................ 303 Klasy proxy ...................................................................................................... 306 6.5.1. WäasnoĈci klas proxy .......................................................................... 311
Kup książkę
Poleć książkę
Spis treÊci
7
RozdziaÄ 7. Grafika .................................................................................................................................313 7.1. 7.2. 7.3.
7.4. 7.5. 7.6. 7.7. 7.8.
Wprowadzenie do pakietu Swing ....................................................................... 314 Tworzenie ramki ............................................................................................... 318 Pozycjonowanie ramki ...................................................................................... 321 7.3.1. WäasnoĈci ramek ................................................................................ 322 7.3.2. OkreĈlanie rozmiaru ramki ................................................................... 323 WyĈwietlanie informacji w komponencie ............................................................ 327 Figury 2D ........................................................................................................ 332 Kolory ............................................................................................................. 340 Czcionki .......................................................................................................... 343 WyĈwietlanie obrazów ...................................................................................... 351
RozdziaÄ 8. ObsÄuga zdarzeÆ .................................................................................................................355 8.1.
8.2. 8.3. 8.4.
Podstawy obsäugi zdarzeþ ................................................................................. 355 8.1.1. Przykäad — obsäuga klikniöcia przycisku ............................................... 357 8.1.2. Nabywanie biegäoĈci w posäugiwaniu siö klasami wewnötrznymi .............. 362 8.1.3. Tworzenie säuchaczy zawierajñcych jedno wywoäanie metody ................... 364 8.1.4. Przykäad — zmiana stylu ..................................................................... 366 8.1.5. Klasy adaptacyjne ............................................................................... 369 Akcje .............................................................................................................. 373 Zdarzenia generowane przez mysz ..................................................................... 380 Hierarchia zdarzeþ w bibliotece AWT .................................................................. 387 8.4.1. Zdarzenia semantyczne i niskiego poziomu ........................................... 388
RozdziaÄ 9. Komponenty Swing interfejsu uÑytkownika ......................................................................391 9.1.
9.2.
9.3.
9.4.
9.5.
Swing a wzorzec projektowy Model-View-Controller .............................................. 392 9.1.1. Wzorce projektowe .............................................................................. 392 9.1.2. Wzorzec Model-View-Controller ............................................................. 393 9.1.3. Analiza MVC przycisków Swing ............................................................. 397 Wprowadzenie do zarzñdzania rozkäadem ........................................................... 398 9.2.1. Rozkäad brzegowy ............................................................................... 400 9.2.2. Rozkäad siatkowy ................................................................................ 402 Wprowadzanie tekstu ....................................................................................... 406 9.3.1. Pola tekstowe .................................................................................... 406 9.3.2. Etykiety komponentów ........................................................................ 408 9.3.3. Pola haseä .......................................................................................... 410 9.3.4. Obszary tekstowe ............................................................................... 410 9.3.5. Panele przewijane ............................................................................... 411 Komponenty umoĔliwiajñce wybór opcji .............................................................. 413 9.4.1. Pola wyboru ....................................................................................... 413 9.4.2. Przeäñczniki ........................................................................................ 415 9.4.3. Obramowanie ..................................................................................... 419 9.4.4. Listy rozwijalne ................................................................................... 423 9.4.5. Suwaki .............................................................................................. 426 Menu .............................................................................................................. 432 9.5.1. Tworzenie menu ................................................................................. 432 9.5.2. Ikony w elementach menu ................................................................... 435 9.5.3. Pola wyboru i przeäñczniki jako elementy menu ...................................... 436 9.5.4. Menu podröczne ................................................................................. 437 9.5.5. Mnemoniki i akceleratory .................................................................... 438
Kup książkę
Poleć książkę
8
Java. Podstawy
9.6.
9.7.
9.5.6. Aktywowanie i dezaktywowanie elementów menu .................................. 440 9.5.7. Paski narzödzi .................................................................................... 444 9.5.8. Dymki ................................................................................................ 446 Zaawansowane techniki zarzñdzania rozkäadem .................................................. 448 9.6.1. Rozkäad GridBagLayout ....................................................................... 449 9.6.2. Rozkäad grupowy ................................................................................. 459 9.6.3. NieuĔywanie Ĕadnego zarzñdcy rozkäadu ................................................ 468 9.6.4. Niestandardowi zarzñdcy rozkäadu ........................................................ 469 9.6.5. Kolejka dostöpu ................................................................................. 472 Okna dialogowe ............................................................................................... 474 9.7.1. Okna dialogowe opcji .......................................................................... 474 9.7.2. Tworzenie okien dialogowych ............................................................... 484 9.7.3. Wymiana danych ................................................................................. 489 9.7.4. Okna dialogowe wyboru plików ............................................................. 495 9.7.5. Okna dialogowe wyboru kolorów ........................................................... 505
RozdziaÄ 10. Przygotowywanie apletów i aplikacji do uÑytku ..............................................................511 10.1. Pliki JAR .......................................................................................................... 512 10.1.1. Manifest ............................................................................................ 512 10.1.2. Wykonywalne pliki JAR ........................................................................ 514 10.1.3. Zasoby .............................................................................................. 515 10.1.4. Pieczötowanie pakietów ...................................................................... 518 10.2. Java Web Start ................................................................................................ 519 10.2.1. Piaskownica ....................................................................................... 522 10.2.2. Podpisywanie kodu ............................................................................. 523 10.2.3. API JNLP ............................................................................................ 525 10.3. Aplety ............................................................................................................. 533 10.3.1. Prosty aplet ........................................................................................ 533 10.3.2. Znacznik applet i jego atrybuty ............................................................. 537 10.3.3. Znacznik object .................................................................................. 540 10.3.4. Parametry przekazujñce informacje do apletów ...................................... 541 10.3.5. Dostöp do obrazów i plików audio ........................................................ 546 10.3.6. ćrodowisko dziaäania apletu ................................................................ 547 10.4. Zapisywanie preferencji uĔytkownika .................................................................. 549 10.4.1. Mapy wäasnoĈci .................................................................................. 550 10.4.2. API Preferences .................................................................................. 555
RozdziaÄ 11. Wyj¾tki, dzienniki, asercje i debugowanie .......................................................................563 11.1. Obsäuga bäödów ............................................................................................... 564 11.1.1. Klasyfikacja wyjñtków .......................................................................... 565 11.1.2. Deklarowanie wyjñtków kontrolowanych ................................................ 567 11.1.3. Zgäaszanie wyjñtków ........................................................................... 569 11.1.4. Tworzenie klas wyjñtków ...................................................................... 570 11.2. Przechwytywanie wyjñtków ................................................................................ 571 11.2.1. Przechwytywanie wielu typów wyjñtków ................................................. 574 11.2.2. Powtórne generowanie wyjñtków i budowanie äaþcuchów wyjñtków .......... 575 11.2.3. Klauzula finally ................................................................................... 576 11.2.4. Instrukcja try z zasobami ..................................................................... 580 11.2.5. Analiza danych ze Ĉledzenia stosu ....................................................... 581 11.3. Wskazówki dotyczñce stosowania wyjñtków ....................................................... 584
Kup książkę
Poleć książkę
Spis treÊci
9
11.4. Asercje ........................................................................................................... 587 11.4.1. Wäñczanie i wyäñczanie asercji ............................................................. 588 11.4.2. Zastosowanie asercji do sprawdzania parametrów ................................ 589 11.4.3. Zastosowanie asercji do dokumentowania zaäoĔeþ ................................ 590 11.5. Dzienniki ......................................................................................................... 591 11.5.1. Podstawy zapisu do dziennika .............................................................. 592 11.5.2. Zaawansowane techniki zapisu do dziennika ......................................... 592 11.5.3. Zmiana konfiguracji menedĔera dzienników ........................................... 594 11.5.4. Lokalizacja ......................................................................................... 596 11.5.5. Obiekty typu Handler ........................................................................... 596 11.5.6. Filtry .................................................................................................. 600 11.5.7. Formatery .......................................................................................... 600 11.5.8. Przepis na dziennik ............................................................................. 601 11.6. Wskazówki dotyczñce debugowania ................................................................... 609 11.7. Wskazówki dotyczñce debugowania aplikacji z GUI ............................................. 614 11.7.1. Zaprzöganie robota AWT do pracy ........................................................ 617 11.8. Praca z debugerem .......................................................................................... 621
RozdziaÄ 12. Programowanie ogólne ....................................................................................................627 12.1. Dlaczego programowanie ogólne ....................................................................... 628 12.1.1. Dla kogo programowanie ogólne .......................................................... 629 12.2. Definicja prostej klasy ogólnej ........................................................................... 630 12.3. Metody ogólne ................................................................................................. 632 12.4. Ograniczenia zmiennych typowych ..................................................................... 633 12.5. Kod ogólny a maszyna wirtualna ....................................................................... 635 12.5.1. Translacja wyraĔeþ generycznych ......................................................... 637 12.5.2. Translacja metod ogólnych .................................................................. 637 12.5.3. UĔywanie starego kodu ....................................................................... 639 12.6. Ograniczenia i braki ......................................................................................... 641 12.6.1. Nie moĔna podawaè typów prostych jako parametrów typowych .............. 641 12.6.2. Sprawdzanie typów w czasie dziaäania programu jest moĔliwe tylko dla typów surowych .................................................. 641 12.6.3. Nie moĔna tworzyè tablic typów ogólnych .............................................. 642 12.6.4. OstrzeĔenia dotyczñce zmiennej liczby argumentów ............................... 642 12.6.5. Nie wolno tworzyè egzemplarzy zmiennych typowych .............................. 643 12.6.6. Zmiennych typowych nie moĔna uĔywaè w statycznych kontekstach klas ogólnych ..................................................................................... 645 12.6.7. Obiektów klasy ogólnej nie moĔna generowaè ani przechwytywaè ............ 646 12.6.8. UwaĔaj na konflikty, które mogñ powstaè po wymazaniu typów ............... 648 12.7. Zasady dziedziczenia dla typów ogólnych ........................................................... 649 12.8. Typy wieloznaczne ............................................................................................ 650 12.8.1. Ograniczenia nadtypów typów wieloznacznych ....................................... 652 12.8.2. Typy wieloznaczne bez ograniczeþ ........................................................ 655 12.8.3. Chwytanie typu wieloznacznego ............................................................ 655 12.9. Refleksja a typy ogólne .................................................................................... 658 12.9.1. Zastosowanie parametrów Class<T> do dopasowywania typów .............. 659 12.9.2. Informacje o typach generycznych w maszynie wirtualnej ........................ 659
RozdziaÄ 13. Kolekcje .............................................................................................................................665 13.1. Interfejsy kolekcyjne ......................................................................................... 665 13.1.1. Oddzielenie warstwy interfejsów od warstwy klas konkretnych ................ 666 13.1.2. Interfejsy Collection i Iterator ............................................................... 668
Kup książkę
Poleć książkę
10
Java. Podstawy 13.2. Konkretne klasy kolekcyjne ............................................................................... 674 13.2.1. Listy powiñzane ................................................................................. 674 13.2.2. Listy tablicowe .................................................................................. 684 13.2.3. Zbiór HashSet ................................................................................... 684 13.2.4. Zbiór TreeSet .................................................................................... 688 13.2.5. Porównywanie obiektów ..................................................................... 689 13.2.6. Kolejki Queue i Deque ....................................................................... 694 13.2.7. Kolejki priorytetowe ........................................................................... 696 13.2.8. Mapy ................................................................................................ 697 13.2.9. Specjalne klasy Set i Map .................................................................. 702 13.3. Architektura kolekcji ......................................................................................... 706 13.3.1. Widoki i obiekty opakowujñce ............................................................. 709 13.3.2. Operacje zbiorcze .............................................................................. 717 13.3.3. Konwersja pomiödzy kolekcjami a tablicami ......................................... 718 13.4. Algorytmy ........................................................................................................ 718 13.4.1. Sortowanie i tasowanie ...................................................................... 720 13.4.2. Wyszukiwanie binarne ........................................................................ 722 13.4.3. Proste algorytmy ................................................................................ 723 13.4.4. Pisanie wäasnych algorytmów .............................................................. 725 13.5. Stare kolekcje ................................................................................................. 726 13.5.1. Klasa Hashtable ................................................................................ 726 13.5.2. Wyliczenia ......................................................................................... 727 13.5.3. Mapy wäasnoĈci ................................................................................. 728 13.5.4. Stosy ................................................................................................ 729 13.5.5. Zbiory bitów ...................................................................................... 729
RozdziaÄ 14. Wielow¾tkowoÊÀ ...............................................................................................................735 14.1. Czym sñ wñtki ................................................................................................. 736 14.1.1. Wykonywanie zadaþ w osobnych wñtkach ............................................ 741 14.2. Przerywanie wñtków ......................................................................................... 746 14.3. Stany wñtków .................................................................................................. 749 14.3.1. Wñtki NEW ........................................................................................ 749 14.3.2. Wñtki RUNNABLE ............................................................................... 750 14.3.3. Wñtki BLOCKED i WAITING ................................................................. 750 14.3.4. Zamykanie wñtków ............................................................................ 752 14.4. WäasnoĈci wñtków ........................................................................................... 752 14.4.1. Priorytety wñtków ............................................................................... 752 14.4.2. Wñtki demony ................................................................................... 753 14.4.3. Procedury obsäugi nieprzechwyconych wyjñtków .................................... 754 14.5. Synchronizacja ................................................................................................ 756 14.5.1. Przykäad sytuacji powodujñcej wyĈcig ................................................... 756 14.5.2. WyĈcigi ............................................................................................. 760 14.5.3. Obiekty klasy Lock ............................................................................. 762 14.5.4. Warunki ............................................................................................ 765 14.5.5. Säowo kluczowe synchronized ............................................................. 769 14.5.6. Bloki synchronizowane ....................................................................... 774 14.5.7. Monitor ............................................................................................. 775 14.5.8. Pola ulotne ....................................................................................... 776 14.5.9. Zmienne finalne ................................................................................ 777 14.5.10. Zmienne atomowe ............................................................................. 777 14.5.11. Zakleszczenia .................................................................................... 778
Kup książkę
Poleć książkę
Spis treÊci
11
14.5.12. Zmienne lokalne wñtków .................................................................... 781 14.5.13. Testowanie blokad i odmierzanie czasu ............................................... 782 14.5.14. Blokady odczytu-zapisu ...................................................................... 783 14.5.15. Dlaczego metody stop i suspend sñ wycofywane .................................. 784 14.6. Kolejki blokujñce ............................................................................................. 786 14.7. Kolekcje bezpieczne wñtkowo ........................................................................... 794 14.7.1. Szybkie mapy, zbiory i kolejki ............................................................. 794 14.7.2. Tablice kopiowane przy zapisie ........................................................... 796 14.7.3. Starsze kolekcje bezpieczne wñtkowo ................................................. 796 14.8. Interfejsy Callable i Future ................................................................................ 797 14.9. Klasa Executors ............................................................................................... 802 14.9.1. Pule wñtków ..................................................................................... 803 14.9.2. Planowanie wykonywania ................................................................... 807 14.9.3. Kontrolowanie grup zadaþ .................................................................. 808 14.9.4. Szkielet rozgaäözienie-zäñczenie .......................................................... 809 14.10. Synchronizatory ............................................................................................... 812 14.10.1. Semafory ......................................................................................... 812 14.10.2. Klasa CountDownLatch ..................................................................... 813 14.10.3. Bariery ............................................................................................. 814 14.10.4. Klasa Exchanger ............................................................................... 814 14.10.5. Kolejki synchroniczne ........................................................................ 815 14.11. Wñtki a biblioteka Swing .................................................................................. 815 14.11.1. Uruchamianie czasochäonnych zadaþ .................................................. 816 14.11.2. Klasa SwingWorker ........................................................................... 820 14.11.3. Zasada jednego wñtku ...................................................................... 827
Dodatek A. SÄowa kluczowe Javy .........................................................................................................829 Skorowidz ..............................................................................................................................................831
Kup książkę
Poleć książkę
12
Java. Podstawy
Kup książkę
Poleć książkę
7
Grafika W tym rozdziale: Q
Wprowadzenie do biblioteki Swing
Q
Tworzenie ramek
Q
Pozycjonowanie ramek
Q
WyĞwietlanie informacji w komponencie
Q
Figury 2D
Q
Kolory
Q
Kroje czcionek
Q
WyĞwietlanie obrazów
Do tej pory tworzyliĞmy tylko programy, które pobieraáy dane z klawiatury, przetwarzaáy je i wyĞwietlaáy wyniki w konsoli. WiĊkszoĞü uĪytkowników oczekuje jednak nieco wiĊcej. Ani nowoczesne programy, ani strony internetowe nie dziaáają w ten sposób. W tym rozdziale zaczynamy naukĊ pisania programów z graficznym interfejsem uĪytkownika (GUI). Nauczymy siĊ przede wszystkim ustawiaü rozmiar i poáoĪenie okien na ekranie, wyĞwietlaü tekst pisany róĪnymi krojami czcionki, wyĞwietlaü obrazy itd. Caáy zdobyty tu warsztat przyda nam siĊ w kolejnych rozdziaáach, w których bĊdziemy tworzyü ciekawe projekty. Dwa nastĊpne rozdziaáy opisują przetwarzanie zdarzeĔ, takie jak wciĞniĊcie klawisza na klawiaturze lub klikniĊcie przyciskiem myszy, oraz dodawanie do aplikacji takich elementów interfejsu jak menu i przyciski. Po zapoznaniu siĊ z tymi trzema rozdziaáami bĊdziesz dysponowaü wiedzą, która jest niezbĊdna do pisania aplikacji graficznych. Bardziej zaawansowane techniki związane z programowaniem grafiki zostaáy opisane w drugim tomie. Osoby zainteresowane wyáącznie programowaniem po stronie serwera, które nie mają w planach pisania GUI, mogą bezpiecznie pominąü te rozdziaáy.
Kup książkę
Poleć książkę
314
Java. Podstawy
7.1. Wprowadzenie do pakietu Swing W Java 1.0 udostĊpniono bibliotekĊ klas o nazwie Abstract Window Toolkit (AWT), która dostarczaáa podstawowe narzĊdzia do programowania GUI. Podstawowa biblioteka AWT przerzuca zadania dotyczące tworzenia elementów interfejsu oraz obsáugi ich zachowaĔ na natywne narzĊdzia GUI danej platformy (Windows, Solaris, Mac OS X itd.). JeĞli na przykáad przy uĪyciu oryginalnej biblioteki AWT umieszczono w oknie pole tekstowe, dane wprowadzane do niego byáy w rzeczywistoĞci obsáugiwane przez odpowiednik tego pola w systemie. DziĊki temu program napisany w Javie mógá teoretycznie dziaáaü na dowolnej platformie, a jego styl byá taki sam jak innych programów w danym systemie. Stąd wziąá siĊ slogan firmy Sun: „Napisz raz, uruchamiaj wszĊdzie”. Metoda programowania oparta na odpowiednikach sprawdzaáa siĊ w przypadku prostych aplikacji. Natomiast szybko wyszáo na jaw, Īe napisanie wysokiej jakoĞci przenoĞnej biblioteki graficznej opartej na natywnych elementach interfejsu uĪytkownika jest niezwykle trudnym zadaniem. Elementy interfejsu, jak menu, paski przewijania i pola tekstowe, mogą siĊ nieco róĪniü na róĪnych platformach. Przez to trudno byáo stworzyü program dziaáający identycznie w róĪnych systemach. Ponadto niektóre Ğrodowiska graficzne (jak np. X11/Motif) nie dysponują tak szeroką gamą elementów interfejsu jak systemy Windows czy Mac OS X. Ten fakt ograniczaá zasobnoĞü przenoĞnej biblioteki do tych elementów, które moĪna znaleĨü na wszystkich platformach. W wyniku tego aplikacje GUI budowane na bazie AWT ustĊpowaáy wyglądem i funkcjonalnoĞcią natywnym aplikacjom takich systemów jak Windows czy Mac OS X. Na domiar záego na róĪnych platformach biblioteka AWT zawieraáa róĪne báĊdy. ProgramiĞci narzekali, Īe muszą testowaü swoje aplikacje na wszystkich platformach, co záoĞliwie nazywano „napisz raz, testuj wszĊdzie”. W 1996 roku firma Netscape stworzyáa bibliotekĊ GUI o nazwie IFC (ang. Internet Foundation Classes), w której zastosowano zupeánie inne podejĞcie. Elementy interfejsu uĪytkownika, jak przyciski, menu itd., byáy rysowane w pustym oknie. Rola systemu polegaáa tylko na wyĞwietlaniu okien i rysowaniu w nich. DziĊki temu widgety firmy Netscape wyglądaáy i dziaáaáy zawsze tak samo, bez wzglĊdu na platformĊ. Firma Sun podjĊáa wspóápracĊ z Netscape w celu udoskonalenia tej technologii, czego owocem byáa biblioteka o nazwie kodowej Swing. Biblioteka ta zostaáa udostĊpniona w postaci dodatku w Java 1.1, a do biblioteki standardowej wcielono ją w Java SE 1.2. Zgodnie z myĞlą Duke’a Ellingtona, Īe „Nic nie ma znaczenia, jeĞli jest pozbawione swingu”, Swing staá siĊ oficjalną nazwą zestawu narzĊdzi do tworzenia GUI, niewykorzystującego systemowych odpowiedników elementów. Swing wchodzi w skáad Java Foundation Classes (JFC). Biblioteka JFC jest bardzo duĪa i zawiera wiele innych narzĊdzi poza Swingiem. Zaliczają siĊ do nich interfejsy API dostĊpnoĞci, grafiki dwuwymiarowej oraz obsáugi operacji przeciągania i upuszczania. OczywiĞcie elementy interfejsu oparte na Swingu pojawiają siĊ z pewnym opóĨnieniem w stosunku do komponentów uĪywanych przez AWT. Z naszego doĞwiadczenia wynika, Īe róĪnica ta nie powinna stanowiü problemu na Īadnym w miarĊ niezbyt starym sprzĊcie. Z drugiej strony argumenty przemawiające za uĪyciem Swinga są przytáaczające: Q
Swing udostĊpnia bogaty i wygodny w uĪyciu zestaw elementów interfejsu uĪytkownika.
Kup książkę
Poleć książkę
RozdziaÄ 7.
Q
Grafika
315
Biblioteka Swing nie zastñpiäa AWT, tylko zostaäa zbudowana w oparciu o architekturö swojej poprzedniczki. Komponenty Swing oferujñ znacznie wiöksze moĔliwoĈci. UĔywajñc biblioteki Swing, zawsze korzysta siö z podstawowej biblioteki AWT, zwäaszcza przy obsäudze zdarzeþ. Od tej pory piszñc „Swing”, mamy na myĈli klasy rysujñce interfejs uĔytkownika, a piszñc „AWT”, myĈlimy o podstawowych mechanizmach okien, takich jak obsäuga zdarzeþ. Q
Swing w niewielkim stopniu zaleĪy od platformy, dziĊki czemu jest mniej podatny na báĊdy związane z danym systemem.
Q
Sposób dziaáania i wygląd elementów Swinga jest taki sam na róĪnych platformach.
Niemniej trzecia z wymienionych zalet moĪe byü uwaĪana za wadĊ — jeĞli elementy interfejsu uĪytkownika wyglądają tak samo na wszystkich platformach, to znaczy, Īe wyglądają inaczej niĪ elementy natywne, co z kolei oznacza, Īe bĊdą sáabiej znane uĪytkownikom. W pakiecie Swing problem ten zostaá rozwiązany w bardzo elegancki sposób. Programista piszący program przy uĪyciu klas Swing moĪe nadaü mu specyficzny charakter. Rysunki 7.1 i 7.2 przedstawiają ten sam program w stylu systemu Windows i GTK. Rysunek 7.1. Styl systemu Windows
Dodatkowo firma Sun opracowaáa niezaleĪny od platformy styl o nazwie Metal, który póĨniej przez specjalistów od marketingu przechrzczono na Java look and feel. Jednak wiĊkszoĞü programistów nadal uĪywa okreĞlenia „Metal” i my równieĪ trzymamy siĊ tej konwencji w tej ksiąĪce. Ze wzglĊdu na krytyczne gáosy kierowane pod adresem stylu Metal, który wedáug niektórych wydawaá siĊ zbyt ciĊĪki, w Java SE 5.0 nieco go odĞwieĪono (zobacz rysunek 7.3). Obecnie styl Metal obsáuguje wiele motywów — róĪnych wersji kolorystycznych i zestawów czcionek. Motyw domyĞlny nazywa siĊ Ocean.
Kup książkę
Poleć książkę
316
Java. Podstawy
Rysunek 7.2. Styl GTK
Rysunek 7.3. Motyw Ocean stylu Metal
W Java SE 6 poprawiono obsáugĊ natywnego stylu systemu Windows i GTK. Aktualnie aplikacje Swing obsáugują schematy kolorów i pulsujące przyciski oraz paski przewijania, które staáy siĊ ostatnio modne. W Java 7 dodano nowy styl o nazwie Nimbus (rysunek 7.4), ale nie jest on domyĞlnie dostĊpny. W stylu tym wykorzystywana jest grafika wektorowa zamiast bitmapowej, dziĊki czemu interfejsy tworzone przy jego uĪyciu są niezaleĪne od rozmiaru ekranu. Niektórzy uĪytkownicy wolą, aby aplikacje w Javie wyglądaáy tak jak inne programy na danej platformie, inni wolą styl Metal, a jeszcze inni preferują styl caákiem innego producenta. Jak przekonamy siĊ w rozdziale 8., umoĪliwienie uĪytkownikom wyboru dowolnego stylu jest bardzo áatwe.
Kup książkę
Poleć książkę
RozdziaÄ 7.
Q
Grafika
317
Rysunek 7.4. Styl Nimbus
W Javie moĔliwe jest rozszerzenie istniejñcego stylu, a nawet utworzenie caäkiem nowego. W tej ksiñĔce nie mamy wystarczajñco duĔo miejsca, aby opisaè ten Ĕmudny proces polegajñcy na okreĈleniu sposobu rysowania kaĔdego komponentu. Jednak niektórzy programiĈci pokusili siö o to, zwäaszcza ci, którzy przenosili programy w Javie na nietypowe platformy, jak terminale sklepowe czy urzñdzenia kieszonkowe. Zbiór ciekawych stylów moĔna znaleĒè pod adresem http://www.javootoo.com/. W Java SE 5.0 wprowadzono styl o nazwie Synth, który upraszcza caäy ten proces. W Synth styl moĔna definiowaè poprzez dostarczenie obrazów i deskryptorów XML. Nie trzeba nic programowaè.
Styl Napkin (http://napkinlaf.sourceforge.net) nadaje elementom interfejsu uĔytkownika wyglñd przypominajñcy odröczne rysowanie. Wysyäajñc do klienta utworzony w nim prototyp, dajemy wyraĒny sygnaä, Ĕe nie jest to jeszcze ukoþczony produkt.
Programowanie interfejsu uĔytkownika w Javie opiera siö obecnie w wiökszoĈci na pakiecie Swing. Jest tylko jeden godny uwagi wyjñtek. ćrodowisko zintegrowane Eclipse uĔywa zestawu narzödzi graficznych o nazwie SWT, który podobnie jak AWT odwzorowuje natywne komponenty na róĔnych platformach. Artykuäy na temat SWT moĔna znaleĒè na stronie http://www.eclipse.org/articles/. Firma Oracle pracuje nad alternatywnñ technologiñ o nazwie JavaFX, która moĔe w przyszäoĈci zastñpiè Swing. JeĈli chcesz dowiedzieè siö o niej wiöcej, zajrzyj na stronö http://www.oracle.com/technetwork/java/javafx/overview.
KaĪdy, kto pisaá programy dla systemu Microsoft Windows w jĊzykach Visual Basic lub C#, wie, jak duĪym uáatwieniem są graficzne narzĊdzia do projektowania ukáadu i edytory zasobów. NarzĊdzia te umoĪliwiają zaprojektowanie caáej wizualnej strony aplikacji oraz automatycznie generują wiĊkszoĞü (czĊsto caáoĞü) kodu GUI. Dla Javy równieĪ dostĊpne są narzĊdzia
Kup książkę
Poleć książkę
318
Java. Podstawy wspomagające budowanie GUI, ale naszym zdaniem, aby siĊ nimi sprawnie posáugiwaü, trzeba najpierw nauczyü siĊ robiü to samodzielnie. Pozostaáa czĊĞü tego rozdziaáu zostaáa poĞwiĊcona opisowi technik wyĞwietlania okien i rysowania w nich róĪnych elementów.
7.2. Tworzenie ramki Okno najwyĪszego poziomu, tzn. takie, które nie jest zawarte w Īadnym innym oknie, nazywa siĊ w Javie ramką (ang. frame). W bibliotece AWT dla tego typu okien utworzono klasĊ o nazwie Frame. Wersja Swing tej klasy nosi nazwĊ JFrame i ją rozszerza. Ramka JFrame jest jednym z niewielu komponentów Swinga, które nie są rysowane w obszarze roboczym. W związku z tym elementy dodatkowe (przyciski, pasek tytuáu, ikony itd.) są rysowane przez system operacyjny, a nie klasy Swing. Nazwy wiökszoĈci klas komponentów Swing zaczynajñ siö od litery J, np. JButton, JFrame itd. Istniejñ takĔe klasy Button i Frame, ale sñ to komponenty AWT. JeĈli litera J zostanie przypadkowo pominiöta, program moĔe przejĈè kompilacjö bez problemu, ale mieszanina komponentów AWT i Swing moĔe spowodowaè nietypowe zachowania lub wyglñd aplikacji.
W tym podrozdziale przejrzymy najpopularniejsze metody pracy z komponentem Swing o nazwie JFrame. Listing 7.1 przedstawia prosty program wyĞwietlający na ekranie pustą ramkĊ widoczną na rysunku 7.5. Listing 7.1. simpleFrame/SimpleFrameTest.java package simpleFrame; import java.awt.*; import javax.swing.*; /** * @version 1.32 2007-06-12 * @author Cay Horstmann */ public class SimpleFrameTest { public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { public void run() { SimpleFrame frame = new SimpleFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } }); } }
Kup książkę
Poleć książkę
RozdziaÄ 7.
Q
Grafika
319
Rysunek 7.5. Najprostsza widoczna ramka
class SimpleFrame extends JFrame { private static final int DEFAULT_WIDTH = 300; private static final int DEFAULT_HEIGHT = 200;
}
public SimpleFrame() { setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT); }
Przeanalizujemy powyĪszy program wiersz po wierszu. Klasy Swing znajdują siĊ w pakiecie javax.swing. Nazwa pakietu javax oznacza, Īe jest to pakiet rozszerzający Javy, a nie podstawowy. Swing jest uznawany za rozszerzenie ze wzglĊdów historycznych. Jest jednak dostĊpny w kaĪdej wersji Java SE od 1.2. DomyĞlny rozmiar ramki 0×0 jest raczej maáo atrakcyjny. ZdefiniowaliĞmy podklasĊ o nazwie SimpleFrame, której konstruktor ustawia rozmiar na 300×200 pikseli. Jest to jedyna róĪnica pomiĊdzy klasami SimpleFrame i JFrame. W metodzie main klasy SimpleFrameTest tworzony jest obiekt klasy SimpleFrame, który nastĊpnie zostaá uwidoczniony. W kaĪdym programie opartym na Swingu trzeba poradziü sobie z dwoma zagadnieniami technicznymi. Po pierwsze, konfiguracja kaĪdego komponentu Swing musi siĊ odbywaü w wątku dystrybucji zdarzeĔ (ang. event dispatch thread), który steruje wysyáaniem zdarzeĔ, jak klikniĊcia przyciskiem myszy lub wciĞniĊcie klawisza na klawiaturze, do elementów interfejsu uĪytkownika. PoniĪszy fragment programu wykonuje instrukcje w wątku dystrybucji zdarzeĔ: EventQueue.invokeLater(new Runnable() { public void run() { instrukcje } });
Szczegóáowy opis tego zagadnienia znajduje siĊ w rozdziale 14. Na razie potraktujmy to jako magiczny fragment kodu potrzebny do uruchomienia programu Swing.
Kup książkę
Poleć książkę
320
Java. Podstawy
Wiele programów nie inicjuje interfejsu uĔytkownika w wñtku dystrybucji zdarzeþ. Nie ma Ĕadnych przeszkód, aby operacjö tö przeprowadzaè w wñtku gäównym. Niestety ze wzglödu na to, Ĕe komponenty Swing stawaäy siö coraz bardziej zäoĔone, programiĈci w firmie Sun nie mogli zagwarantowaè bezpieczeþstwa tej metody. Prawdopodobieþstwo wystñpienia bäödu jest niezwykle niskie, ale nikt nie chciaäby byè tym pechowcem, któremu siö to przydarzy. Lepiej pisaè wäaĈciwy kod, nawet jeĈli wyglñda nieco tajemniczo.
Po drugie, okreĞlamy, co ma siĊ staü, kiedy uĪytkownik zamknie ramkĊ aplikacji. W tym przypadku chcemy, aby program zostaá zamkniĊty. Odpowiedzialna jest za to poniĪsza instrukcja: frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
W programach skáadających siĊ z wielu ramek program nie powinien koĔczyü dziaáania w wyniku zamkniĊcia jednej z nich. Przy standardowych ustawieniach, jeĞli uĪytkownik zamknie ramkĊ, zostanie ona ukryta, a program nie zakoĔczy dziaáania (dobrze by byáo, gdyby program byá wyáączany w chwili zamkniĊcia jego ostatniej ramki, ale Swing dziaáa inaczej). Samo utworzenie ramki nie oznacza, Īe zostanie ona wyĞwietlona. Ramki na początku swojego istnienia są niewidoczne. DziĊki temu programista moĪe dodaü do nich wszystkie komponenty, zanim ukaĪą siĊ po raz pierwszy. Aby wyĞwietliü ramkĊ, metoda main wywoáuje na jej rzecz metodĊ setVisible. Przed Java SE 5.0 moĔna byäo uĔywaè metody show dziedziczonej przez klasö JFrame po nadklasie Window. Nadklasñ klasy Window jest Component, która takĔe zawiera metodö show. Stosowanie metody Component.show zaczöto odradzaè w Java SE 1.2. W zamian, aby wyĈwietliè komponent, naleĔy uĔyè metody setVisible(true). Natomiast metoda Window.show nie byäa odradzana aĔ do Java SE 1.4. MoĔliwoĈè uwidocznienia okna i przeniesienia go na przód byäa nawet przydatna. Niestety metoda show dla okien równieĔ jest odradzana od Java SE 5.0.
Po rozplanowaniu instrukcji inicjujących metoda main koĔczy dziaáanie. ZauwaĪmy, Īe zakoĔczenie metody main nie oznacza zamkniĊcia programu, a jedynie gáównego wątku. Wątek dystrybucji zdarzeĔ podtrzymuje dziaáanie programu aĪ do jego zakoĔczenia poprzez zamkniĊcie ramki lub wywoáanie metody System.exit. Uruchomiony program przedstawia rysunek 7.5 — jest to zwykáe szare okno najwyĪszego poziomu. Jak widaü, pasek tytuáu i pozostaáe dodatki, jak zaokrąglone rogi sáuĪące do zmiany rozmiaru okna, zostaáy narysowane przez system operacyjny, a nie klasy Swing. Elementy te bĊdą wyglądaáy inaczej, jeĞli uruchomimy ten program w systemach Windows, GTK czy Mac OS X. Biblioteka Swing rysuje wszystko, co znajduje siĊ wewnątrz ramki. W tym przypadku jej zadanie sprowadza siĊ jedynie do wypeánienia domyĞlnym kolorem táa. Od Java SE 1.4 istnieje moĔliwoĈè wyäñczenia wszelkich dodatków za pomocñ wywoäania metody frame.setUndecorated(true).
Kup książkę
Poleć książkę
RozdziaÄ 7.
Q
Grafika
321
7.3. Pozycjonowanie ramki Klasa JFrame udostĊpnia tylko kilka metod zmieniających wygląd ramek. OczywiĞcie wiĊkszoĞü metod sáuĪących do zmiany wymiarów i poáoĪenia ramki jest w klasie JFrame dziedziczona po róĪnych nadklasach. PoniĪej znajduje siĊ lista najwaĪniejszych z tych metod: Q
setLocation i setBounds — ustawiają poáoĪenie ramki.
Q
setIconImage — okreĞla ikonĊ wyĞwietlaną w pasku tytuáu, w zasobniku systemowym itd.
Q
setTitle — ustawia tekst w pasku tytuáu.
Q
setResizable — pobiera wartoĞü logiczną okreĞlającą, czy uĪytkownik moĪe zmieniaü rozmiar ramki.
Rysunek 7.6 przedstawia hierarchiĊ dziedziczenia klasy JFrame. Rysunek 7.6. Hierarchia dziedziczenia klas ramek i komponentów w pakietach AWT i Swing
Kup książkę
Poleć książkę
322
Java. Podstawy
W wyciñgach z API do tego podrozdziaäu przedstawiamy te metody, które naszym zdaniem majñ najwiöksze znaczenie przy nadawaniu ramkom odpowiedniego stylu. Niektóre z nich sñ udostöpnione w klasie JFrame. Inne z kolei pochodzñ od róĔnych nadklas klasy JFrame. Czasami konieczne moĔe byè przeszukanie dokumentacji API w celu znalezienia metod przeznaczonych do okreĈlonego celu. Niestety jest to doĈè Ĕmudna praca, jeĈli chodzi o metody dziedziczone. Na przykäad metoda toFront ma zastosowanie do obiektów typu JFrame, ale poniewaĔ jest dziedziczona po klasie Window, w dokumentacji JFrame nie ma jej opisu. JeĈli uwaĔasz, Ĕe powinna istnieè metoda wykonujñca okreĈlone dziaäanie, ale nie ma jej w dokumentacji danej klasy, przeszukaj dokumentacjö metod nadklas tej klasy. Na górze kaĔdej strony w dokumentacji API znajdujñ siö odnoĈniki do nadklas, a lista metod dziedziczonych znajduje siö pod zestawieniem nowych i przesäoniötych metod.
Wedáug dokumentacji API metody sáuĪące do zmieniania rozmiaru i ksztaátu ramek znajdują siĊ w klasach Component (bĊdącej przodkiem wszystkich obiektów GUI) i Window (bĊdącej nadklasą klasy Frame). Na przykáad do zmiany poáoĪenia komponentu moĪna uĪyü metody setLocation z klasy Component. Wywoáanie: setLocation(x, y)
umieĞci lewy górny róg komponentu w odlegáoĞci x pikseli od lewej krawĊdzi ekranu i y pikseli od góry. WartoĞci (0, 0) oznaczają lewy górny róg ekranu. Podobnie metoda setBounds w klasie Component umoĪliwia zmianĊ rozmiaru i poáoĪenia komponentu (zwáaszcza ramki JFrame) w jednym wywoáaniu: setBounds(x, y, width, height)
Istnieje teĪ moĪliwoĞü pozostawienia decyzji o poáoĪeniu okna systemowi. Wywoáanie: setLocationByPlatform(true);
przed wyĞwietleniem okna spowoduje, Īe system we wáasnym zakresie okreĞli jego poáoĪenie (ale nie rozmiar). Zazwyczaj nowe okno jest wyĞwietlane z nieznacznym przesuniĊciem wzglĊdem poprzedniego. W przypadku ramki wspóärzödne metod setLocation i setBounds sñ wzglödne do caäego ekranu. W rozdziale 9. dowiemy siö, Ĕe wspóärzödne komponentów znajdujñcych siö w kontenerze odnoszñ siö do tego kontenera.
7.3.1. WÄasnoÊci ramek Wiele metod klas komponentów wystĊpuje w parach get-set, jak poniĪsze metody klasy Frame: public String getTitle() public void setTitle(String title)
Taka para metod typu get-set nazywa siĊ wáasnoĞcią (ang. property). WáasnoĞü ma nazwĊ i typ. Nazwa jest taka sama jak sáowo uzyskane w wyniku opuszczenia czáonu get i zamienienia pierwszej litery powstaáego sáowa na maáą. Na przykáad klasa Frame ma wáasnoĞü o nazwie title i typie String.
Kup książkę
Poleć książkę
RozdziaÄ 7.
Q
Grafika
323
Z zaáoĪenia title jest wáasnoĞcią ramki. Ustawienie (set) niniejszej wáasnoĞci powoduje zmianĊ tytuáu na ekranie uĪytkownika. Pobranie jej (get) zwraca wartoĞü, która zostaáa wczeĞniej ustawiona. Nie wiemy (i nie obchodzi nas to), jak klasa Frame implementuje tĊ wáasnoĞü. Prawdopodobnie wykorzystuje swój odpowiednik ramki do przechowywania tytuáu. MoĪliwe, Īe ma nastĊpujące pole: private String title;
// nie jest wymagane dla wáasnoĞci
JeĞli klasa zawiera pasujące pole, nie wiemy (lub nie obchodzi nas to), jak metody dostĊpowe i ustawiające są zaimplementowane. Prawdopodobnie po prostu odczytują i ustawiają dane pole. MoĪliwe, Īe robią jeszcze coĞ, np. powiadamiają system o kaĪdej zmianie tytuáu. Jest tylko jeden wyjątek od konwencji get-set: metody wáasnoĞci typu logicznego zaczynają siĊ od przedrostka is. Na przykáad dwie przedstawione poniĪej metody definiują wáasnoĞü locationByPlatform: public boolean isLocationByPlatform() public void setLocationByPlatform(boolean b)
Znacznie wiĊcej na temat wáasnoĞci piszemy w rozdziale 8. drugiego tomu. Wiele jözyków programowania, zwäaszcza Visual Basic i C#, standardowo obsäuguje wäasnoĈci. Niewykluczone, Ĕe w przyszäoĈci w Javie równieĔ pojawi siö podobna konstrukcja jözykowa.
7.3.2. OkreÊlanie rozmiaru ramki PamiĊtajmy, Īe jeĞli nie ustawimy wáasnego rozmiaru ramek, wszystkie bĊdą miaáy wymiary 0×0 pikseli. Aby nie komplikowaü naszych przykáadowych programów, ustawiamy ramki na rozmiar do przyjĊcia na wiĊkszoĞci ekranów. Jednak w profesjonalnej aplikacji naleĪy sprawdziü rozdzielczoĞü ekranu uĪytkownika i napisaü podprogram zmieniający rozmiar ramek w zaleĪnoĞci od potrzeby. Na przykáad okno, które wygląda znakomicie na ekranie laptopa, na ekranie o wysokiej rozdzielczoĞci skurczy siĊ do rozmiarów znaczka pocztowego. Aby sprawdziü rozmiar ekranu, naleĪy wykonaü nastĊpujące dziaáania: wywoáaj statyczną metodĊ getDefaultToolkit klasy Toolkit w celu utworzenia obiektu typu Toolkit (klasa Toolkit jest zbiornikiem rozmaitych metod, które wspóápracują z systemem). NastĊpnie wywoáaj metodĊ getScreenSize, która zwraca rozmiar ekranu w postaci obiektu Dimension. Obiekt tego typu przechowuje wysokoĞü i szerokoĞü w zmiennych publicznych (!) o nazwach width i height. PoniĪej przedstawiamy opisywany fragment programu: Toolkit kit = Toolkit.getDefaultToolkit(); Dimension screenSize = kit.getScreenSize(); int screenWidth = screenSize.width; int screenHeight = screenSize.height;
Rozmiar ramki ustawiamy na poáowĊ ekranu i pozwalamy systemowi na ustalenie poáoĪenia ramki:
Kup książkę
Poleć książkę
324
Java. Podstawy setSize(screenWidth / 2, screenHeight / 2); setLocationByPlatform(true);
Dodatkowo dostarczymy ikonĊ. Do wygodnego áadowania obrazów moĪna wykorzystaü klasĊ ImageIcon. PoniĪej przedstawiony jest sposób jej uĪycia: Image img = new ImageIcon("icon.gif").getImage(); setIconImage(img);
Ikona moĪe siĊ pojawiü w róĪnych miejscach, w zaleĪnoĞci od systemu operacyjnego. W systemie Windows pojawi siĊ na przykáad w lewym górnym rogu okna oraz bĊdzie widoczna wĞród aktywnych zadaĔ pojawiających siĊ w wyniku naciĞniĊcia kombinacji klawiszy Alt+Tab. Listing 7.2 przedstawia peány kod omawianego programu. Po jego uruchomieniu zwróü uwagĊ na ikonĊ Core Java. Listing 7.2. sizedFrame/SizedFrameTest.java package sizedFrame; import java.awt.*; import javax.swing.*; /** * @version 1.32 2007-04-14 * @author Cay Horstmann */ public class SizedFrameTest { public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { public void run() { JFrame frame = new SizedFrame(); frame.setTitle("SizedFrame"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true);); } }); } } class SizedFrame extends JFrame { public SizedFrame() { // Sprawdzenie wymiarów ekranu. Toolkit kit = Toolkit.getDefaultToolkit(); Dimension screenSize = kit.getScreenSize(); int screenHeight = screenSize.height; int screenWidth = screenSize.width; // Ustawienie szerokoĞci i wysokoĞci ramki oraz polecenie systemowi, aby ustaliá jej poáoĪenie.
Kup książkę
Poleć książkę
RozdziaÄ 7.
Q
Grafika
325
setSize(screenWidth / 2, screenHeight / 2); setLocationByPlatform(true); // Ustawienie ikony i tytuáu.
}
}
Image img = new ImageIcon("icon.gif").getImage(); setIconImage(img);
Jeszcze kilka dodatkowych wskazówek dotyczących obsáugi ramek: Q
JeĞli ramka zawiera tylko standardowe komponenty, jak przyciski i pola tekstowe, jej rozmiar moĪna ustawiü za pomocą metody pack. Rozmiar zostanie ustawiony na najmniejszy, w którym zmieszczą siĊ wszystkie komponenty. CzĊsto rozmiar gáównej ramki jest ustawiany na najwiĊkszą wartoĞü. Od Java SE 1.4 ramkĊ moĪna zmaksymalizowaü za pomocą nastĊpującego wywoáania: frame.setExtendedState(Frame.MAXIMIZED_BOTH);
Q
Dobrym pomysáem jest zapisanie poáoĪenia i rozmiaru ramki ustawionych przez uĪytkownika i zastosowanie tych ustawieĔ przy ponownym uruchomieniu aplikacji. Jak to zrobiü, dowiemy siĊ w rozdziale 10., przy okazji omawiania API preferencji.
Q
JeĞli aplikacja wykorzystuje kilka ekranów, ich rozmiary moĪna sprawdziü za pomocą metod GraphicsEnvironment i GraphicsDevice.
Q
Ponadto klasa GraphicsDevice umoĪliwia uruchomienie programu w trybie peánoekranowym.
java.awt.Component 1.0 Q
boolean isVisible()
Q
void setVisible(boolean b)
Sprawdza lub ustawia wáasnoĞü widocznoĞci. Komponenty są początkowo widoczne z wyjątkiem komponentów najwyĪszego poziomu, jak JFrame. Q
void setSize(int width, int height) 1.1
Ustawia szerokoĞü i wysokoĞü komponentu. Q
void setLocation(int x, int y) 1.1
Przenosi komponent w inne miejsce. WspóárzĊdne x i y są wzglĊdne do kontenera lub ekranu, jeĞli komponent jest komponentem najwyĪszego poziomu (np. JFrame). Q
void setBounds(int x, int y, int width, int height) 1.1
Przesuwa komponent i zmienia jego rozmiar. Q
Dimension getSize() 1.1
Q
void setSize(Dimension d) 1.1
Pobiera lub ustawia wáasnoĞü size komponentu.
Kup książkę
Poleć książkę
326
Java. Podstawy java.awt.Window 1.0 Q
void toFront()
Przenosi okno przed wszystkie pozostaáe okna. Q
void toBack()
Przenosi okno na sam dóá stosu okien i odpowiednio przestawia pozostaáe widoczne okna. Q
boolean isLocationByPlatform() 5.0
Q
void setLocationByPlatform(boolean b) 5.0
Pobiera lub ustawia wáasnoĞü locationByPlatform. JeĞli zostanie ona ustawiona przed wyĞwietleniem okna, platforma wybierze odpowiednią lokalizacjĊ. java.awt.Frame 1.0 Q
boolean isResizable()
Q
void setResizable(boolean b)
Pobiera lub ustawia wáasnoĞü resizable. JeĞli jest ona ustawiona, uĪytkownik moĪe zmieniaü rozmiar ramki. Q
String getTitle()
Q
void setTitle(String s)
Pobiera lub ustawia wáasnoĞü title okreĞlającą tekst na pasku tytuáu. Q
Image getIconImage()
Q
void setIconImage(Image image)
Pobiera lub ustawia wáasnoĞü iconImage, która okreĞla ikonĊ ramki. System moĪe wyĞwietliü ikonĊ jako dodatek w ramce lub w innym miejscu. Q
boolean isUndecorated() 1.4
Q
void setUndecorated(boolean b) 1.4
Pobiera lub ustawia wáasnoĞü undecorated. JeĞli ta wáasnoĞü jest ustawiona, ramka nie zawiera Īadnych dodatków, jak pasek tytuáu czy przycisk zamykający. Ta metoda musi byü wywoáana przed wyĞwietleniem ramki. Q
int getExtendedState() 1.4
Q
void setExtendedState(int state) 1.4
Pobiera lub ustawia stan rozszerzonego okna. MoĪliwe stany to: Frame.NORMAL Frame.ICONIFIED Frame.MAXIMIZED_HORIZ Frame.MAXIMIZED_VERT Frame.MAXIMIZED_BOTH
Kup książkę
Poleć książkę
RozdziaÄ 7.
Q
Grafika
327
java.awt.Toolkit 1.0 Q
static Toolkit getDefaultToolkit()
Zwraca standardowy zestaw narzĊdzi. Q
Dimension getScreenSize()
Pobiera rozmiar ekranu. javax.swing.ImageIcon 1.2 Q
ImageIcon(String filename)
Tworzy ikonĊ, której obraz jest przechowywany w pliku. Q
Image getImage()
Pobiera obraz ikony.
7.4. WyÊwietlanie informacji w komponencie W tym podrozdziale nauczymy siĊ wyĞwietlaü informacje w ramce. Zamiast przykáadowego programu wyĞwietlającego tekst w konsoli, który widzieliĞmy w rozdziale 3., zaprezentujemy program wyĞwietlający tekst w ramce, jak na rysunku 7.7. Rysunek 7.7. Ramka wyĈwietlajñca tekst
àaĔcuch tekstowy moĪna wydrukowaü bezpoĞrednio na ramce, ale jest to uznawane za záy zwyczaj programistyczny. Ramki w Javie są z zaáoĪenia kontenerami do przechowywania komponentów, takich jak pasek menu i inne elementy interfejsu uĪytkownika. Z reguáy rysowanie odbywa siĊ na innym dodanym do ramki komponencie. Struktura ramki JFrame jest zadziwiająco skomplikowana. Rysunek 7.8 przedstawia schemat budowy takiej ramki. Jak widaü, ramka JFrame skáada siĊ z czterech warstw. Trzy z nich — podstawowa (ang. root pane), warstwowa (ang. layered pane) i przezroczysta (ang. glass pane) — nie są dla nas interesujące. Ich przeznaczeniem jest organizacja paska menu i warstwy z treĞcią oraz implementacja stylu. CzĊĞü interesująca programistów Swing to warstwa treĞci (ang. content pane). Podczas projektowania ramki komponenty dodaje siĊ do warstwy treĞci, stosując kod podobny do poniĪszego: Container contentPane = frame.getContentPane(); Component c = . . .; contentPane.add(c);
Kup książkę
Poleć książkę
328
Java. Podstawy Do Java SE 1.4 metoda add klasy JFrame powodowaáa wyjątek wyĞwietlający komunikat „Do not use JFrame.add(). Use JFrame.getContentPane().add() instead”. W Java SE 5.0 zrezygnowano z takiej edukacji programistów, czego wyrazem jest zezwolenie na wywoáywanie metody JFrame.add na rzecz warstwy z treĞcią. DziĊki temu od Java SE 5.0 moĪna stosowaü krótki zapis: frame.add(c);
Tym razem chcemy dodaü do ramki jeden komponent, na którym narysujemy nasz komunikat. Aby móc rysowaü na komponencie, naleĪy zdefiniowaü klasĊ rozszerzającą klasĊ JComponent i przesáoniü w niej metodĊ paintComponent klasy nadrzĊdnej. Metoda paintComponent przyjmuje jeden parametr typu Graphics. Obiekt typu Graphics zawiera ustawienia dotyczące rysowania obrazów i tekstu, jak czcionka czy aktualny kolor. Rysowanie w Javie zawsze odbywa siĊ za poĞrednictwem obiektu Graphics. UdostĊpnia on metody rysujące wzory, obrazy i tekst. Rysunek 7.8. Wewnötrzna struktura ramki JFrame
Parametr Graphics jest podobny do kontekstu urzñdzeþ (ang. device context) w systemie Windows i kontekstu graficznego (ang. graphics context) w programowaniu dla systemu X11.
PoniĪszy fragment programu tworzy komponent, na którym moĪna rysowaü: class MyComponent extends JComponent { public void paintComponent(Graphics g)
Kup książkę
Poleć książkę
RozdziaÄ 7.
Q
Grafika
329
{ kod rysujæcy } }
Za kaĪdym razem, kiedy okno musi byü ponownie narysowane, metoda obsáugi zdarzeĔ informuje o tym komponent. Powoduje to uruchomienie metod paintComponent wszystkich komponentów. Nigdy nie naleĪy wywoáywaü metody paintComponent samodzielnie. Jest ona wywoáywana automatycznie, gdy trzeba ponownie narysowaü jakąĞ czĊĞü aplikacji, i nie naleĪy zaburzaü tego automatycznego procesu. Jakiego rodzaju czynnoĞci uruchamiają tĊ automatyczną reakcjĊ? Rysowanie jest konieczne, na przykáad kiedy uĪytkownik zwiĊkszy rozmiar okna albo je zminimalizuje, a nastĊpnie zmaksymalizuje. JeĞli zostanie otwarte nowe okno, które czĊĞciowo przykryje stare, to po zamkniĊciu tego nowego okna przykryta czĊĞü starego zostanie zniszczona i trzeba ją bĊdzie ponownie narysowaü (system graficzny nie zapisuje pikseli, które znajdują siĊ pod spodem). OczywiĞcie przy pierwszym uruchomieniu okna musi ono przetworzyü kod okreĞlający sposób i miejsce rysowania początkowych elementów. Aby wymusiè ponowne rysowanie ekranu, naleĔy uĔyè metody repaint. Wywoäa ona metody paintComponent wszystkich komponentów, które majñ prawidäowo skonfigurowany obiekt Graphics.
Z przedstawionego powyĪej fragmentu kodu wnioskujemy, Īe metoda paintComponent przyjmuje tylko jeden parametr typu Graphics. Jednostką miary obiektów Graphics wyĞwietlanych na ekranie są piksele. Para wspóárzĊdnych (0, 0) okreĞla lewy górny róg komponentu, na którego powierzchni odbywa siĊ rysowanie. WyĞwietlanie tekstu jest specjalnym rodzajem rysowania. Klasa Graphics udostĊpnia metodĊ drawString o nastĊpującej skáadni: g.drawString(text, x, y)
Chcemy narysowaü áaĔcuch: To nie jest program „Witaj, Ğwiecie” w oryginalnym oknie w odlegáoĞci okoáo jednej czwartej szerokoĞci od lewej krawĊdzi i poáowy wysokoĞci od krawĊdzi górnej. Mimo Īe nie potrafimy jeszcze mierzyü dáugoĞci áaĔcuchów, zaczniemy rysowanie w punkcie o wspóárzĊdnych (75, 100). Oznacza to, Īe pierwsza litera áaĔcucha jest przesuniĊta w prawo o 75 pikseli i w dóá o 100 pikseli (w rzeczywistoĞci o 100 pikseli w dóá przesuniĊta jest podstawowa linia pisma — wiĊcej na ten temat w dalszej czĊĞci rozdziaáu). Kod opisanej metody paintComponent znajduje siĊ poniĪej: class NotHelloWorldComponent extends JComponent { public static final int MESSAGE_X = 75; public static final int MESSAGE_Y = 100; public void paintComponent(Graphics g) { g.drawString("To nie jest program „Witaj, ħwiecie”", MESSAGE_X, MESSAGE_Y);
Kup książkę
Poleć książkę
330
Java. Podstawy
}
} . . .
W koĔcu komponent powinien informowaü uĪytkownika o tym, jaki ma byü jego rozmiar. Przesáonimy metodĊ getPreferredSize, aby zwracaáa obiekt klasy Dimension z preferowaną szerokoĞcią i wysokoĞcią: class NotHelloWorldComponent extends JComponent { private static final int DEFAULT_WIDTH = 300; private static final int DEFAULT_HEIGHT = 200; . . . public Dimension getPreferredSize() { return new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT); } }
Gdy umieĞcimy w ramce jakieĞ komponenty i bĊdziemy chcieli uĪyü ich preferowanych rozmiarów, to zamiast setSize wywoáamy metodĊ pack: class NotHelloWorldFrame extends JFrame { public NotHelloWorldFrame() { add(new NotHelloWorldComponent()); pack(); } }
Listing 7.3 zawiera peány kod programu. Niektórzy programiĈci wolñ rozszerzaè klasö JPanel zamiast JComponent. Obiekt JPanel jest z zaäoĔenia kontenerem na inne komponenty, ale moĔna takĔe na nim rysowaè. Jest jednak miödzy nimi jedna róĔnica — panel jest nieprzezroczysty, czyli rysuje wszystkie piksele w swoim obröbie. Najprostszym sposobem na zrobienie tego jest narysowanie panelu z kolorowym täem za pomocñ wywoäania metody super.paintCompo ´nent w metodzie paintComponent kaĔdej podklasy panelu: class NotHelloWorldPanel extends JPanel { public void paintComponent(Graphics g) { super.paintComponent(g); }
}
procedury rysujñce
Listing 7.3. notHelloWorld/NotHelloWorld.java package notHelloWorld; import javax.swing.*; import java.awt.*; /** * @version 1.32 2007-06-12
Kup książkę
Poleć książkę
RozdziaÄ 7.
Q
Grafika
* @author Cay Horstmann */ public class NotHelloWorld { public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { public void run() { JFrame frame = new NotHelloWorldFrame(); frame.setTitle("NotHelloWorld"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } }); } } /** * Ramka zawierająca panel z komunikatem. */ class NotHelloWorldFrame extends JFrame { public NotHelloWorldFrame() { add(new NotHelloWorldComponent()); pack(); } } /** * Panel wyĞwietlający komunikat. */ class NotHelloWorldPanel extends JComponent { public static final int MESSAGE_X = 75; public static final int MESSAGE_Y = 100; private static final int DEFAULT_WIDTH = 300; private static final int DEFAULT_HEIGHT = 200; public void paintComponent(Graphics g) { g.drawString("To nie jest program „Witaj, ħwiecie”.", MESSAGE_X, MESSAGE_Y); } public Dimension getPreferredSize() { return new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT); } } javax.swing.JFrame 1.2 Q
Container getContentPane()
Zwraca obiekt ContentPane dla ramki JFrame.
Kup książkę
Poleć książkę
331
332
Java. Podstawy Q
Component add(Component c)
Dodaje i zwraca dany komponent do warstwy treĞci ramki (przed Java SE 5.0 ta metoda powodowaáa wyjątek). java.awt.Component 1.0 Q
void repaint()
Powoduje ponowne jak najszybsze narysowanie komponentu. Q
Dimension getPreferredSize()
Metoda, którą naleĪy przesáoniü, aby zwracaáa preferowany rozmiar komponentu. javax.swing.JComponent 1.2 Q
void paintComponent(Graphics g)
Metoda, którą naleĪy przesáoniü w celu zdefiniowania sposobu rysowania okreĞlonego komponentu. java.awt.Window 1.0 Q
void pack()
Zmienia rozmiar okna, biorąc pod uwagĊ preferowane rozmiary znajdujących siĊ w nim komponentów.
7.5. Figury 2D Od Java 1.0 klasa Graphics udostĊpnia metody rysujące linie, prostokąty, elipsy itd. Ich moĪliwoĞci są jednak bardzo ograniczone. Nie ma na przykáad moĪliwoĞci ustawienia gruboĞci linii ani obracania figur. W Java 1.2 wprowadzono bibliotekĊ Java2D udostĊpniającą szeroki wachlarz metod graficznych. W tym rozdziale opisujemy tylko podstawy tej biblioteki — wiĊcej bardziej zaawansowanych informacji na ten temat znajduje siĊ w rozdziale 7. w drugim tomie. Aby narysowaü figurĊ biblioteki Java2D, trzeba utworzyü obiekt klasy Graphics2D. Klasa ta jest podklasą klasy Graphics. Od Java SE 2 metody takie jak paintComponent automatycznie odbierają obiekty klasy Graphics2D. Wystarczy zastosowaü rzutowanie: public void paintComponent(Graphics g) { Graphics2D g2 = (Graphics2D) g; . . . }
Kup książkę
Poleć książkę
RozdziaÄ 7.
Q
Grafika
333
Figury geometryczne w bibliotece Java2D są obiektami. Istnieją klasy reprezentujące linie, prostokąty i elipsy: Line2D Rectangle2D Ellipse2D
Wszystkie te klasy implementują interfejs Shape. Biblioteka Java2D obsäuguje takĔe bardziej skomplikowane figury, jak äuki, krzywe drugiego i trzeciego stopnia oraz trajektorie. Wiöcej informacji na ten temat znajduje siö w rozdziale 7. drugiego tomu.
Aby narysowaü figurĊ, naleĪy najpierw utworzyü obiekt klasy implementującej interfejs Shape, a nastĊpnie wywoáaü metodĊ draw klasy Graphics2D. Na przykáad: Rectangle2D rect = . . .; g2.draw(rect);
Przed pojawieniem siö biblioteki Java2D do rysowania figur uĔywano metod klasy Graphics, np. drawRectangle. Na pierwszy rzut oka te stare wywoäania wydajñ siö prostsze, ale uĔywajñc biblioteki Java2D, pozostawiamy sobie róĔne moĔliwoĈci do wyboru — moĔna póĒniej ulepszyè rysunki za pomocñ rozmaitych narzödzi dostöpnych w bibliotece Java2D.
Biblioteka Java2D nieco komplikuje programowanie. W przeciwieĔstwie do metod rysujących z wersji 1.0, w których wspóárzĊdne byáy liczbami caákowitymi, figury Java2D uĪywają wspóárzĊdnych zmiennoprzecinkowych. W wielu przypadkach stanowi to duĪe uáatwienie dla programisty, poniewaĪ moĪe on okreĞlaü figury przy uĪyciu lepiej znanych mu jednostek (jak milimetry lub cale), które póĨniej są konwertowane na piksele. Biblioteka Java2D wykonuje obliczenia o pojedynczej precyzji na liczbach typu float w wiĊkszoĞci wykonywanych wewnĊtrznie dziaáaĔ. Pojedyncza precyzja w zupeánoĞci wystarcza — celem obliczeĔ geometrycznych jest przecieĪ ustawienie pikseli na ekranie lub w drukarce. Dopóki báĊdy zaokrąglania mieszczą siĊ w zakresie jednego piksela, rezultat wizualny nie cierpi. Ponadto obliczenia na liczbach typu float są na niektórych platformach szybsze, a dodatkowo wartoĞci tego typu zajmują o poáowĊ mniej miejsca niĪ wartoĞci typu double. Czasami jednak obliczenia na liczbach typu float bywają niewygodne, poniewaĪ Java niewzruszenie wymaga rzutowania, jeĞli niezbĊdna jest konwersja wartoĞci typu double na typ float. Przeanalizujmy na przykáad poniĪszą instrukcjĊ: float f = 1.2;
// báąd
Ta instrukcja spowoduje báąd kompilacji, poniewaĪ staáa 1.2 jest typu double i kompilator obawia siĊ utraty danych. Rozwiązaniem jest dodanie przyrostka F do staáej zmiennoprzecinkowej: float f = 1.2F;
Kup książkę
// OK
Poleć książkę
334
Java. Podstawy Teraz przyjrzyjmy siĊ poniĪszej instrukcji: Rectangle2D r = . . . float f = r.getWidth();
// báąd
Instrukcja ta spowoduje báąd kompilacji z tego samego powodu co poprzednia. Metoda getWidth zwraca wartoĞü typu double. W tym przypadku rozwiązaniem jest rzutowanie: float f = (float) r.getWidth();
// OK
PoniewaĪ stosowanie przyrostków i rzutowania nie jest wygodne, projektanci biblioteki Java2D postanowili utworzyü dwie wersje kaĪdej klasy reprezentującej figurĊ: jedną ze wspóárzĊdnymi typu float dla oszczĊdnych programistów i jedną ze wspóárzĊdnymi typu double dla leniwych (w tej ksiąĪce zaliczamy siĊ do tych drugich, czyli stosujemy wspóárzĊdne typu double, gdzie tylko moĪemy). Projektanci biblioteki zastosowali ciekawą i początkowo wprowadzającą w báąd metodĊ pakowania obu wersji klas. Przyjrzyjmy siĊ klasie Rectangle2D. Jest to abstrakcyjna klasa mająca dwie konkretne podklasy, które są dodatkowo statycznymi klasami wewnĊtrznymi: Rectangle2D.Float Rectangle2D.Double
Rysunek 7.9 przedstawia diagram dziedziczenia. Rysunek 7.9. Klasy prostokñtów 2D
Najlepiej ignorowaü fakt, Īe obie te konkretne klasy są statyczne i wewnĊtrzne — to tylko taki chwyt, który pozwala uniknąü nazw FloatRectangle2D i DoubleRectangle2D (wiĊcej informacji na temat statycznych klas wewnĊtrznych znajduje siĊ w rozdziale 6.). Tworząc obiekt klasy Rectangle2D.Float, wartoĞci okreĞlające wspóárzĊdne naleĪy podawaü jako typu float. W przypadku klasy Rectangle2D.Double wspóárzĊdne muszą byü typu double. Rectangle2D.Float floatRect = new Rectangle2D.Float(10.0F, 25.0F, 22.5F, 20.0F); Rectangle2D.Double doubleRect = new Rectangle2D.Double(10.0, 25.0, 22.5, 20.0);
PoniewaĪ zarówno klasa Rectangle2D.Float, jak i Rectangle2D.Double rozszerzają wspólną klasĊ Rectangle2D, a metody w tych podklasach przesáaniają metody nadklasy, zapamiĊtywanie typu figury nie przynosi wáaĞciwie Īadnych korzyĞci. Referencje do prostokątów moĪna przechowywaü w zmiennych typu Rectangle2D. Rectangle2D floatRect = new Rectangle2D.Float(10.0F, 25.0F, 22.5F, 20.0F); Rectangle2D doubleRect = new Rectangle2D.Double(10.0, 25.0, 22.5, 20.0);
Kup książkę
Poleć książkę
RozdziaÄ 7.
Q
Grafika
335
Oznacza to, Īe uĪycie klas wewnĊtrznych jest konieczne tylko przy tworzeniu obiektów figur. Parametry konstruktora okreĞlają lewy górny róg, szerokoĞü i wysokoĞü prostokąta. Klasa Rectangle2D.Float zawiera jednñ metodö, której nie dziedziczy po klasie Rectangle2D. Jest to metoda setRect(float x, float y, float h, float w). Metody tej nie moĔna uĔyè, jeĈli referencja do obiektu typu Rectangle2D.Float jest przechowywana w zmiennej typu Rectangle2D. Nie jest to jednak duĔa strata — klasa Rectangle2D zawiera metodö setRect z parametrami typu double.
Metody klasy Rectangle2D przyjmują parametry i zwracają wartoĞci typu double. Na przykáad metoda getWidth zwraca wartoĞü typu double, nawet jeĞli szerokoĞü jest zapisana w postaci liczby typu float w obiekcie typu Rectangle2D.Float. Aby caäkowicie pozbyè siö wartoĈci typu float, naleĔy uĔywaè klas typu Double. Jednak w programach tworzñcych wiele tysiöcy figur warto rozwaĔyè uĔycie klas Float ze wzglödu na oszczödnoĈè pamiöci.
Wszystko, co napisaliĞmy do tej pory na temat klas Rectangle2D, dotyczy równieĪ pozostaáych klas reprezentujących figury. Dodatkowo istnieje klasa o nazwie Point2D, której podklasy to Point2D.Float i Point2D.Double. PoniĪszy fragment programu tworzy obiekt takiej klasy: Point2D p = new Point2D.Double(10, 20);
Klasa Point2D jest niezwykle przydatna — zastosowanie obiektów Point2D jest znacznie bliĔsze idei programowania obiektowego niĔ uĔywanie oddzielnych wartoĈci x i y. Wiele konstruktorów przyjmuje parametry typu Point2D. Zalecamy stosowanie obiektów tej klasy, gdzie siö da — dziöki nim obliczenia geometryczne sñ czösto duĔo prostsze.
Klasy Rectangle2D i Ellipse2D dziedziczą po wspólnej nadklasie RectangularShape. Wprawdzie elipsa nie jest prostokątna, ale moĪna na niej opisaü prostokąt (zobacz rysunek 7.10). Rysunek 7.10. Prostokñt opisany na elipsie
Klasa RectangularShape definiuje ponad 20 metod wspólnych dla tych figur. Zaliczają siĊ do nich metody getWidth, getHeight, getCenterX i getCenterY (niestety w czasie pisania tej ksiąĪki nie byáo metody getCenter zwracającej obiekt typu Point2D). Dodatkowo do hierarchii klas reprezentujących figury dodano kilka starszych klas z Java 1.0. Klasy Rectangle i Point, które przechowują prostokąt i punkt przy uĪyciu wspóárzĊdnych caákowitych, rozszerzają klasy Rectangle2D i Point2D.
Kup książkę
Poleć książkę
336
Java. Podstawy Rysunek 7.11 przedstawia relacje pomiĊdzy klasami figur. Klasy Double i Float zostaáy pominiĊte, a klasy spadkowe wyróĪniono szarym táem.
Rysunek 7.11. Relacje miödzy klasami figur
Tworzenie obiektów typu Rectangle2D i Ellipse2D jest prostym zadaniem. NaleĪy podaü: Q
wspóárzĊdne x i y lewego górnego rogu,
Q
wysokoĞü i szerokoĞü.
W przypadku elipsy te wartoĞci dotyczą opisanego na niej prostokąta. Na przykáad instrukcja: Ellipse2D e = new Ellipse2D.Double(150, 200, 100, 50);
utworzy elipsĊ wpisaną w prostokąt, którego lewy górny róg znajduje siĊ w punkcie o wspóárzĊdnych (150, 200) o szerokoĞci 100 i wysokoĞci 50. Czasami jednak wspóárzĊdne lewego górnego rogu nie są od razu dostĊpne. CzĊsto zdarza siĊ, Īe dostĊpne są dwa punkty leĪące naprzeciw siebie, ale nie są to rogi górny lewy i prawy dolny. Nie moĪna utworzyü prostokąta w poniĪszy sposób: Rectangle2D rect = new Rectangle2D.Double(px, py, qx - px, qy - py);
// báąd
JeĞli p nie jest lewym górnym rogiem, jedna lub obie wspóárzĊdne bĊdą miaáy wartoĞci ujemne i prostokąt siĊ nie pojawi. W takim przypadku naleĪy najpierw utworzyü pusty prostokąt i uĪyü metody setFrameFromDiagonal: Rectangle2D rect = new Rectangle2D.Double(); rect.setFrameFromDiagonal(px, py, qx, qy);
Kup książkę
Poleć książkę
RozdziaÄ 7.
Q
Grafika
337
Jeszcze lepiej, jeĞli p i q są punktami rogów reprezentowanymi przez obiekty typu Point2D: rect.setFrameFromDiagonal(p, q);
Przy tworzeniu elipsy zazwyczaj znane są Ğrodek, szerokoĞü i wysokoĞü opisanego na niej prostokąta, a nie jego rogi (które nawet nie leĪą na elipsie). Metoda setFrameFromCenter przyjmuje punkt Ğrodkowy, ale wymaga takĪe jednego z czterech rogów. W związku z tym elipsĊ zazwyczaj tworzy siĊ nastĊpująco: Ellipse2D ellipse = new Ellipse2D.Double(centerX - width / 2, centerY - height / 2, width, height);
Aby utworzyü liniĊ, naleĪy podaü jej punkt początkowy i koĔcowy w postaci obiektów Point2D lub par liczb: Line2D line = new Line2D.Double(start, end);
lub Line2D line = new Line2D.Double(startX, startY, endX, endY);
Program przedstawiony na listingu 7.4 rysuje prostokąt, elipsĊ znajdującą siĊ wewnątrz tego prostokąta, przekątną prostokąta oraz koáo o takim samym Ğrodku jak prostokąt. Rysunek 7.12 przedstawia wynik dziaáania tego programu. Rysunek 7.12. Rysowanie figur geometrycznych
Listing 7.4. draw/DrawTest.java package draw; import java.awt.*; import java.awt.geom.*; import javax.swing.*; /** * @version 1.32 2007-04-14 * @author Cay Horstmann */ public class DrawTest { public static void main(String[] args) {
Kup książkę
Poleć książkę
338
Java. Podstawy EventQueue.invokeLater(new Runnable() { public void run() { JFrame frame = new DrawFrame(); frame.setTitle("DrawTest"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } }); } } /** * Ramka zawierająca panel z rysunkami. */ class DrawFrame extends JFrame { public DrawFrame() { add(new DrawComponent()); pack(); } } /** * Komponent wyĞwietlający prostokąty i elipsy. */ class DrawComponent extends JComponent { private static final int DEFAULT_WIDTH = 400; private static final int DEFAULT_HEIGHT = 400; public void paintComponent(Graphics g) { Graphics2D g2 = (Graphics2D) g; // Rysowanie prostokąta. double double double double
leftX = 100; topY = 100; width = 200; height = 150;
Rectangle2D rect = new Rectangle2D.Double(leftX, topY, width, height); g2.draw(rect); // Rysowanie elipsy. Ellipse2D ellipse = new Ellipse2D.Double(); ellipse.setFrame(rect); g2.draw(ellipse); // Rysowanie przekątnej. g2.draw(new Line2D.Double(leftX, topY, leftX + width, topY + height));
Kup książkę
Poleć książkę
RozdziaÄ 7.
Q
Grafika
// Rysowanie koáa z takim samym Ğrodkiem. double centerX = rect.getCenterX(); double centerY = rect.getCenterY(); double radius = 150; Ellipse2D circle = new Ellipse2D.Double(); circle.setFrameFromCenter(centerX, centerY, centerX + radius, centerY + radius); g2.draw(circle); } public Dimension getPreferredSize() { return new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT); } } java.awt.geom.RectangularShape 1.2 Q
double getCenterX()
Q
double getCenterY()
Q
double getMinX()
Q
double getMinY()
Q
double getMaxX()
Q
double getMaxY()
Zwraca wspóárzĊdną x lub y punktu Ğrodkowego, punktu o najmniejszych lub najwiĊkszych wspóárzĊdnych prostokąta. Q
double getWidth()
Q
double getHeight()
Zwraca szerokoĞü lub wysokoĞü prostokąta. Q
double getX()
Q
double getY()
Zwraca wspóárzĊdną x lub y lewego górnego rogu prostokąta. java.awt.geom.Rectangle2D.Double 1.2 Q
Rectangle2D.Double(double x, double y, double w, double h)
Tworzy prostokąt z lewym górnym rogiem w podanym miejscu i o podanej szerokoĞci i dáugoĞci. java.awt.geom.Rectangle2D.Float 1.2 Q
Rectangle2D.Float(float x, float y, float w, float h)
Tworzy prostokąt z lewym górnym rogiem w podanym miejscu i o podanej szerokoĞci i dáugoĞci.
Kup książkę
Poleć książkę
339
340
Java. Podstawy java.awt.geom.Ellipse2D.Double 1.2 Q
Ellipse2D.Double(double x, double y, double w, double h)
Rysuje elipsĊ wpisaną w prostokąt, którego lewy górny róg znajduje siĊ w podanym miejscu i który ma okreĞlone wysokoĞü oraz szerokoĞü. java.awt.geom.Point2D.Double 1.2 Q
Point2D.Double(double x, double y)
Rysuje punkt o podanych wspóárzĊdnych. java.awt.geom.Line2D.Double 1.2 Q
Line2D.Double(Point2D start, Point2D end)
Q
Line2D.Double(double startX, double startY, double endX, double endY)
Rysuje liniĊ miĊdzy dwoma podanymi punktami.
7.6. Kolory Metoda setPaint z klasy Graphics2D ustawia kolor, który jest stosowany we wszystkich kolejnych rysunkach graficznych. Na przykáad: g2.setPaint(Color.RED); g2.drawString("Uwaga!", 100, 100);
Figury zamkniĊte (np. prostokąt czy elipsa) moĪna w takiej sytuacji wypeániü za pomocą metody fill (zamiast draw): Rectangle2D rect = . . .; g2.setPaint(Color.RED); g2.fill(rect); // Wypeánienie prostokąta rect kolorem czerwonym.
Aby zastosowaü kilka kolorów, naleĪy wybraü kolor, zastosowaü metodĊ draw lub fill, a nastĊpnie wybraü inny kolor i ponownie zastosowaü metodĊ draw lub fill. Metoda fill rysuje o jeden piksel mniej po prawej i na dole. JeĈli na przykäad narysujemy prostokñt new Rectangle2D.Double(0, 0, 10, 20), to rysunek bödzie obejmowaä piksele o wspóärzödnych x = 10 i y = 20. JeĈli wypeänimy ten prostokñt kolorem, piksele te nie zostanñ pokolorowane.
Do definiowania kolorów sáuĪy klasa java.awt.Color. W klasie tej dostĊpnych jest 13 nastĊpujących predefiniowanych staáych reprezentujących kolory: BLACK, BLUE, CYAN, DARK_GRAY, GRAY, GREEN, LIGHT_GRAY, MAGENTA, ORANGE, PINK, RED, ´WHITE, YELLOW
Kup książkę
Poleć książkę
RozdziaÄ 7.
Q
Grafika
341
Przed Java SE 1.4 staäe okreĈlajñce kolory byäy pisane maäymi literami, np. Color.red. Byäo to sprzeczne z przyjötñ konwencjñ pisania staäych wielkimi literami. Obecnie nazwy tych staäych moĔna pisaè wielkimi lub, ze wzglödu na zgodnoĈè wstecznñ, maäymi literami.
Niestandardowy kolor moĪna zdefiniowaü, tworząc obiekt klasy Color i podając wartoĞci trzech skáadowych: czerwonego, zielonego i niebieskiego. WartoĞü kaĪdego ze skáadników (zajmujących po jednym bajcie) musi naleĪeü do zbioru 0 – 255. PoniĪszy kod przedstawia sposób wywoáania konstruktora klasy Color z parametrami okreĞlającymi stopieĔ czerwieni, niebieskiego i zieleni: Color(int redness, int greenness, int blueness)
PoniĪej znajduje siĊ przykáadowa procedura tworząca niestandardowy kolor: g2.setPaint(new Color(0, 128, 128)); g2.drawString("Witaj!", 75, 125);
// niebieskozielony
Poza jednolitymi kolorami moĔna takĔe stosowaè bardziej skomplikowane ustawienia, jak róĔne odcienie czy obrazy. Wiöcej informacji na ten temat znajduje siö w drugim tomie w rozdziale o zaawansowanych technikach AWT. JeĈli zamiast obiektu typu Graphics2D zostanie uĔyty obiekt Graphics, kolory naleĔy ustawiaè za pomocñ metody setColor.
Do ustawiania koloru táa sáuĪy metoda setBackground z klasy Component, bĊdącej nadklasą klasy JComponent. MyComponent p = new MyComponent(); p.setBackground(Color.PINK);
Istnieje teĪ metoda setForeground, która okreĞla kolor elementów rysowanych na komponencie. Metody brighter() i darker() — jak sama nazwa wskazuje — sprawiajñ, Ĕe aktualnie uĔywany kolor staje siö jaĈniejszy bñdĒ ciemniejszy. Ponadto metoda brighter jest dobrym sposobem na wyróĔnienie wybranego elementu. W rzeczywistoĈci metoda ta nieznacznie rozjaĈnia kolor. Aby kolor byä duĔo jaĈniejszy, moĔna tö metodö zastosowaè trzy razy: c.brighter().brighter().brighter().
Znacznie wiĊcej predefiniowanych nazw kolorów znajduje siĊ w klasie SystemColor. Staáe tej klasy okreĞlają kolory stosowane do rozmaitych elementów systemu uĪytkownika. Na przykáad instrukcja: p.setBackground(SystemColor.window)
ustawia kolor táa komponentu na domyĞlny dla wszystkich okien w systemie uĪytkownika (táo jest wstawiane przy kaĪdym rysowaniu okna). Kolory zdefiniowane w klasie SystemColor są szczególnie przydatne, kiedy chcemy narysowaü elementy interfejsu uĪytkownika nieodbiegające kolorystyką od standardowych elementów w systemie. Tabela 7.1 zawiera nazwy kolorów systemowych oraz ich opisy.
Kup książkę
Poleć książkę
342
Java. Podstawy
Tabela 7.1. System kolorów Nazwa
Zastosowanie
desktop
Kolor táa pulpitu
activeCaption
Kolor belki tytuáowej aktywnego okna
activeCaptionText
Kolor tekstu na belce tytuáowej
activeCaptionBorder
Kolor obramowania aktywnej belki
inactiveCaption
Kolor nieaktywnej belki
inactiveCaptionText
Kolor tekstu nieaktywnej belki
inactiveCaptionBorder
Kolor obramowania nieaktywnej belki
window
Táo okna
windowBorder
Kolor obramowania okna
windowText
Kolor tekstu w oknie
menu
Táo menu
menuText
Kolor tekstu w menu
text
Kolor táa tekstu
textText
Kolor tekstu
textInactiveText
Kolor tekstu nieaktywnych elementów sterujących
textHighlight
Kolor táa wyróĪnionego tekstu
textHighlightText
Kolor wyróĪnionego tekstu
control
Kolor táa elementów sterujących
controlText
Kolor tekstu w elementach sterujących
controlLtHighlight
Sáabe wyróĪnienie elementów sterujących
controlHighlight
Silne wyróĪnienie elementów sterujących
controlShadow
Kolor cienia elementów sterujących
controlDkShadow
Ciemniejszy kolor cienia elementów sterujących
scrollbar
Kolor táa dla suwaków
info
Kolor táa dla tekstu pomocy
infoText
Kolor tekstu pomocy
java.awt.Color 1.0 Q
Color(int r, int g, int b)
Tworzy obiekt reprezentujący kolor. Parametry:
Kup książkę
r
WartoĞü barwy czerwonej
g
WartoĞü barwy zielonej
b
WartoĞü barwy niebieskiej
Poleć książkę
RozdziaÄ 7.
Q
Grafika
343
java.awt.Graphics 1.0 Q
Color getColor()
Q
void setColor(Color c)
Pobiera lub ustawia kolor. Wszystkie nastĊpne rysunki bĊdą miaáy ten kolor. Parametry:
c
Nowy kolor
java.awt.Graphics2D 1.2 Q
Paint getPaint()
Q
void setPaint(Paint p)
Pobiera lub ustawia wáasnoĞü paint danego kontekstu graficznego. Klasa Color implementuje interfejs Paint. W związku z tym za pomocą tej metody moĪna ustawiü atrybut paint na jednolity kolor. Q
void fill(shape s)
Wypeánia figurĊ aktualnym kolorem. java.awt.Component 1.0 Q
Color getBackground()
Q
void setBackground(Color c)
Pobiera lub ustawia kolor táa. Parametry:
c
Q
Color getForeground()
Q
void setForeground(Color c)
Nowy kolor táa
Pobiera lub ustawia kolor frontu. Parametry:
c
Nowy kolor frontu
7.7. Czcionki Program przedstawiony na początku tego rozdziaáu wyĞwietlaá áaĔcuch tekstu pisany domyĞlną czcionką. CzĊsto jednak zdarza siĊ, Īe tekst musi byü napisany inną czcionką. Identyfikatorem czcionki jest jej nazwa. Nazwa czcionki skáada siĊ z nazwy rodziny czcionek, np. Helvetica, i opcjonalnego przyrostka, np. Bold. Na przykáad nazwy Helvetica i Helvetica Bold naleĪą do rodziny czcionek o nazwie Helvetica. Aby sprawdziü, jakie czcionki są dostĊpne w danym komputerze, naleĪy wywoáaü metodĊ getAvailableFontFamilyNames z klasy GraphicsEnvironment. Ta metoda zwraca tablicĊ nazw wszystkich dostĊpnych czcionek w postaci áaĔcuchów. Egzemplarz klasy GraphicsEnvi ´ronment reprezentujący Ğrodowisko graficzne systemu uĪytkownika moĪna utworzyü za
Kup książkę
Poleć książkę
344
Java. Podstawy pomocą statycznej metody getLocalGraphicsEnvironment. PoniĪszy program drukuje nazwy wszystkich czcionek znajdujących siĊ w systemie: import java.awt.*; public class ListFonts { public static void main(String[] args) { String[] fontNames = GraphicsEnvironment .getLocalGraphicsEnvironment() .getAvailableFontFamilyNames(); for (String fontName : fontNames) System.out.println(fontName); } }
W jednym z systemów początek tej listy wygląda nastĊpująco: Abadi MT Condensed Light Arial Arial Black Arial Narrow Arioso Baskerville Binner Gothic . . .
Lista ta zawiera ponad 70 pozycji. Nazwy czcionek mogą byü znakami towarowymi, a ich projekty mogą w niektórych jurysdykcjach podlegaü prawom autorskim. W związku z tym dystrybucja czcionek czĊsto wiąĪe siĊ z uiszczaniem opáat licencyjnych ich wáaĞcicielom. OczywiĞcie, podobnie jak są tanie podróbki drogich perfum, istnieją teĪ podróbki czcionek imitujące oryginaáy. Na przykáad imitacja czcionki Helvetica w systemie Windows nosi nazwĊ Arial. Jako wspólny punkt odniesienia w bibliotece AWT zdefiniowano piĊü logicznych nazw czcionek: SansSerif Serif Monospaced Dialog DialogInput
Czcionki te są zawsze zamieniane na czcionki, które znajdują siĊ w danym urządzeniu. Na przykáad w systemie Windows czcionka SansSerif jest zastĊpowana czcionką Arial. Dodatkowo pakiet SDK firmy Sun zawsze zawiera trzy rodziny czcionek: Lucida Sans, Lucida Bright i Lucida Sans Typewriter. Aby narysowaü znak daną czcionką, najpierw trzeba utworzyü obiekt klasy Font. Konieczne jest podanie nazwy i stylu czcionki oraz rozmiaru w punktach drukarskich. PoniĪsza instrukcja tworzy obiekt klasy Font: Font sansbold14 = new Font("SansSerif", Font.BOLD, 14);
Kup książkę
Poleć książkę
RozdziaÄ 7.
Q
Grafika
345
Trzeci argument okreĞla rozmiar w punktach. Jednostka ta jest powszechnie stosowana w typografii do okreĞlania rozmiaru czcionek. Jeden punkt jest równy 1/72 cala, czyli okoáo 0,35 mm. W konstruktorze klasy Font moĪna uĪyü logicznej nazwy czcionki zamiast nazwy fizycznej. Styl (zwykáy, pogrubiony, kursywa lub pogrubiona kursywa) okreĞla drugi argument konstruktora Font, który moĪe mieü jedną z poniĪszych wartoĞci: Font.PLAIN Font.BOLD Font.ITALIC Font.BOLD + Font.ITALIC
Sposób odwzorowania logicznych nazw czcionek na fizyczne jest okreĈlony w pliku fontconfig.properties w katalogu jre/lib znajdujñcym siö w folderze instalacji Javy. Informacje na temat tego pliku znajdujñ siö pod adresem http://docs.oracle.com/ javase/7/docs/technotes/guides/intl/fontconfig.html.
Pliki czcionek moĪna wczytywaü w formatach TrueType lub PostScript type 1. Potrzebny jest do tego strumieĔ wejĞciowy dla danej czcionki — zazwyczaj z pliku lub adresu URL (wiĊcej informacji na temat strumieni znajduje siĊ w rozdziale 1. drugiego tomu). NastĊpnie naleĪy wywoáaü statyczną metodĊ Font.createFont: URL url = new URL("http://www.fonts.com/Wingbats.ttf"); InputStream in = url.openStream(); Font f1 = Font.createFont(Font.TRUETYPE_FONT, in);
Zastosowana zostaáa zwykáa czcionka o rozmiarze 1 punktu. Do okreĞlenia Īądanego rozmiaru czcionki naleĪy uĪyü metody deriveFont: Font f = f1.deriveFont(14.0F);
Istniejñ dwie przeciñĔone wersje metody deriveFont. Jedna z nich (przyjmujñca parametr typu float) ustawia rozmiar czcionki, a druga (przyjmujñca parametr typu int) ustawia styl czcionki. W zwiñzku z tym instrukcja f1.deriveFont(14) ustawia styl, a nie rozmiar czcionki! Styl czcionki bödzie w tym przypadku kursywñ, poniewaĔ binarna reprezentacja liczby 14 ustawia bit ITALIC.
Fonty Javy zawierają symbole i znaki ASCII. Na przykáad znak \u2297 fontu Dialog to znak . DostĊpne są tylko te symbole, które zdefiniowano w zestawie znaków Unicode. PoniĪszy fragment programu wyĞwietla napis Witaj, Ğwiecie! standardową czcionką bezszeryfową systemu z zastosowaniem pogrubienia i o rozmiarze 14 punktów: Font sansbold14 = new Font("SansSerif", Font.BOLD, 14); g2.setFont(sansbold14); String message = "Witaj, ħwiecie!"; g2.drawString(message, 75, 100);
Teraz wypoĞrodkujemy nasz napis w zawierającym go komponencie. Do tego celu potrzebne są informacje o szerokoĞci i wysokoĞci áaĔcucha w pikselach. O wymiarach tych decydują trzy czynniki:
Kup książkę
Poleć książkę
346
Java. Podstawy Q
czcionka (w tym przypadku jest to pogrubiona czcionka bezszeryfowa o rozmiarze 14 punktów),
Q
áaĔcuch (w tym przypadku Witaj, Ğwiecie!),
Q
urządzenie, na którym áaĔcuch bĊdzie wyĞwietlany (w tym przypadku ekran monitora).
Obiekt reprezentujący wáasnoĞci czcionki urządzenia z ekranem tworzymy za pomocą metody getFontRenderContext z klasy Graphics2D. Zwraca ona obiekt klasy FontRenderContext. Obiekt ten naleĪy przekazaü metodzie getStringBounds z klasy Font: FontRenderContext context = g2.getFontRenderContext(); Rectangle2D bounds = f.getStringBounds(message, context);
Metoda getStringBounds zwraca prostokąt, w którym mieĞci siĊ áaĔcuch. Do interpretacji wymiarów tego prostokąta potrzebna jest znajomoĞü podstawowych pojĊü z zakresu skáadu tekstów (zobacz rysunek 7.13). Linia bazowa (ang. baseline) to teoretyczna linia, na której opiera siĊ dolna czĊĞü litery, np. e. WydáuĪenie górne (ang. ascent) to odstĊp dzielący liniĊ bazową i liniĊ górną pisma (ang. ascender), która okreĞla górną granicĊ liter, takich jak b lub k czy teĪ wielkich liter. WydáuĪenie dolne (ang. descent) to odlegáoĞü pomiĊdzy linią bazową a linią dolną pisma (ang. descender), która stanowi granicĊ dolnej czĊĞci takich liter jak p lub g.
Rysunek 7.13. Pojöcia z zakresu skäadu tekstów
Interlinia (ang. leading) to odstĊp pomiĊdzy wydáuĪeniem dolnym jednej linii a wydáuĪeniem górnym nastĊpnej linii (termin pochodzi od pasków oáowiu uĪywanych przez zecerów do oddzielania linii). WysokoĞü (ang. height) czcionki to odlegáoĞü pomiĊdzy nastĊpującymi po sobie liniami bazowymi i jest równa sumie wydáuĪenia dolnego, leadingu i wydáuĪenia górnego. SzerokoĞü prostokąta zwracanego przez metodĊ getStringBounds okreĞla szerokoĞü tekstu. WysokoĞü natomiast jest równa sumie wydáuĪenia dolnego, leadingu i wydáuĪenia górnego. Prostokąt ma swój początek na linii bazowej áaĔcucha. Górna wspóárzĊdna y prostokąta ma wartoĞü ujemną. W związku z tym szerokoĞü, wysokoĞü i wydáuĪenie górne áaĔcucha moĪna sprawdziü nastĊpująco: double stringWidth = bounds.getWidth(); double stringHeight = bounds.getHeight(); double ascent = -bounds.getY();
Aby sprawdziü wydáuĪenie dolne lub leading, naleĪy uĪyü metody getLineMetrics klasy Font. Zwraca ona obiekt klasy LineMetrics, dysponujący metodami do sprawdzania wydáuĪenia dolnego i leadingu:
Kup książkę
Poleć książkę
RozdziaÄ 7.
Q
Grafika
347
LineMetrics metrics = f.getLineMetrics(message, context); float descent = metrics.getDescent(); float leading = metrics.getLeading();
W poniĪszym fragmencie programu wykorzystano wszystkie opisane powyĪej informacje do umieszczenia áaĔcucha na Ğrodku zawierającego go komponentu: FontRenderContext context = g2.getFontRenderContext(); Rectangle2D bounds = f.getStringBounds(message, context); // (x, y) = lewy górny róg tekstu double x = (getWidth() - bounds.getWidth()) / 2; double y = (getHeight() - bounds.getHeight()) / 2; // Dodanie wydáuĪenia górnego do y w celu siĊgniĊcia do linii bazowej. double ascent = -bounds.getY(); double baseY = y + ascent; g2.drawString(message, (int) x, (int) baseY);
Aby uáatwiü sobie zrozumienie techniki wyĞrodkowywania tekstu, warto sobie uzmysáowiü, Īe metoda getWidth() zwraca szerokoĞü komponentu. Pewna czĊĞü tej przestrzeni, bounds. ´getWidth(), jest zajmowana przez tekst. Reszta powinna byü podzielona na dwie równe czĊĞci, rozmieszczone po obu stronach tekstu. Ten sam sposób rozumowania dotyczy wysokoĞci. Kiedy konieczne jest obliczenie wymiarów ukäadu bez uĔycia metody paintCom ´ponent, nie moĔna uzyskaè obiektu obrazowania czcionki typu Graphics2D. W zamian naleĔy wywoäaè metodö getFontMetrics klasy JComponent, a nastöpnie metodö getFontRenderContext. FontRenderContext context = getFontMetrics(f).getFontRenderContext();
Przykáadowy program przedstawiony poniĪej nie tylko drukuje napis, ale takĪe liniĊ bazową i prostokąt otaczający napis. Rysunek 7.14 przedstawia wynik dziaáania tego programu. Listing 7.5 zawiera jego kod. Rysunek 7.14. Linia bazowa i prostokñt otaczajñcy äaþcuch
Listing 7.5. font/FontTest.java package font; import import import import
java.awt.*; java.awt.font.*; java.awt.geom.*; javax.swing.*;
/** * @version 1.33 2007-04-14
Kup książkę
Poleć książkę
348
Java. Podstawy * @author Cay Horstmann */ public class FontTest { public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { public void run() { JFrame frame = new FontFrame(); frame.setTitle("FontTest"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } }); } } /** * Ramka z komponentem zawierającym tekst. */ class FontFrame extends JFrame { public FontFrame() { add(new FontComponent()); pack(); } } /** * Komponent z tekstem w ramce na Ğrodku. */ class FontComponent extends JComponent { private static final int DEFAULT_WIDTH = 300; private static final int DEFAULT_HEIGHT = 200; public void paintComponent(Graphics g) { Graphics2D g2 = (Graphics2D) g; String message = "Witaj, ħwiecie!"; Font f = new Font("Serif", Font.BOLD, 36); g2.setFont(f); // Sprawdzenie rozmiaru tekstu. FontRenderContext context = g2.getFontRenderContext(); Rectangle2D bounds = f.getStringBounds(message, context); // set (x, y) = lewy górny róg tekstu double x = (getWidth() - bounds.getWidth()) / 2; double y = (getHeight() - bounds.getHeight()) / 2;
Kup książkę
Poleć książkę
RozdziaÄ 7.
Q
Grafika
349
// Dodanie wydáuĪenia górnego do y w celu siĊgniĊcia do linii bazowej. double ascent = -bounds.getY(); double baseY = y + ascent; // Rysowanie komunikatu. g2.drawString(message, (int) x, (int) baseY); g2.setPaint(Color.LIGHT_GRAY); // Rysowanie linii bazowej. g2.draw(new Line2D.Double(x, baseY, x + bounds.getWidth(), baseY)); // Rysowanie otaczającego tekst prostokąta. Rectangle2D rect = new Rectangle2D.Double(x, y, bounds.getWidth(), ´bounds.getHeight()); g2.draw(rect); } public Dimension getPreferredSize() { return new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT); } } java.awt.Font 1.0 Q
Font(String name, int style, int size)
Tworzy obiekt reprezentujący czcionkĊ. Parametry:
name
Nazwa czcionki — moĪe byü nazwa typu Helvetica Bold lub logiczna nazwa typu Serif lub SansSerif
style
Styl: Font.PLAIN, Font.BOLD, Font.ITALIC lub Font.BOLD + Font.ITALIC
size Q
Rozmiar w punktach (na przykáad 12)
String getFontName()
Pobiera nazwĊ czcionki (typu Helvetica Bold). Q
String getFamily()
Pobiera nazwĊ rodziny czcionek (np. Helvetica). Q
String getName()
Pobiera nazwĊ logiczną (np. SansSerif), jeĞli czcionka zostaáa utworzona z nazwy logicznej. W przeciwnym przypadku zwraca nazwĊ czcionki. Q
Rectangle 2D getStringBounds(String s, FontRenderContext context) 1.2
Zwraca prostokąt otaczający áaĔcuch. Prostokąt ma swój początek na linii bazowej áaĔcucha. Górna wspóárzĊdna y prostokąta ma wartoĞü równą odwrotnoĞci wydáuĪenia górnego. WysokoĞü prostokąta jest równa sumie wydáuĪenia górnego, dolnego i leadingu. SzerokoĞü jest równa szerokoĞci tekstu.
Kup książkę
Poleć książkę
350
Java. Podstawy Q
LineMetrics getLineMetrics(String s, FontRenderContext context) 1.2
Zwraca ona obiekt klasy LineMetrics dysponujący metodami do sprawdzania wydáuĪenia dolnego i leadingu. Q
Font deriveFont(int style) 1.2
Q
Font deriveFont(float size) 1.2
Q
Font deriveFont(int style, float size) 1.2
Zwraca nową czcionkĊ róĪniącą siĊ od aktualnej tylko rozmiarem podanym jako argument. java.awt.font.LineMetrics 1.2 Q
float getAscent()
Pobiera wydáuĪenie górne czcionki — odlegáoĞü linii bazowej od wierzchoáków wielkich liter. Q
float getDescent()
Pobiera wydáuĪenie dolne czcionki — odlegáoĞü linii bazowej od podstaw liter siĊgających dolnej linii pisma. Q
float getLeading()
Pobiera leading czcionki — odstĊp pomiĊdzy spodem jednej linii tekstu a wierzchoákiem nastĊpnej. Q
float getHeight()
Pobiera caákowitą wysokoĞü czcionki — odlegáoĞü pomiĊdzy dwiema liniami bazowymi tekstu (wydáuĪenie dolne + leading + wydáuĪenie górne). java.awt.Graphics 1.0 Q
Font getFont()
Q
void setFont(Font font)
Pobiera lub ustawia czcionkĊ. Czcionka ta bĊdzie stosowana w kolejnych operacjach rysowania tekstu. Parametry: Q
font
Czcionka
void drawString(String str, int x, int y)
Rysuje áaĔcuch przy uĪyciu aktualnej czcionki i koloru. Parametry:
Kup książkę
str
àaĔcuch
x
WspóárzĊdna x początku áaĔcucha
y
WspóárzĊdna y linii bazowej áaĔcucha
Poleć książkę
RozdziaÄ 7.
Q
Grafika
351
java.awt.Graphics2D 1.2 Q
FontRenderContext getFontRenderContext()
Pobiera kontekst wizualizacji czcionki, który okreĞla cechy czcionki w kontekĞcie graficznym. Q
void drawString(String str, float x, float y)
Rysuje áaĔcuch przy zastosowaniu aktualnej czcionki i koloru. Parametry:
str
àaĔcuch
x
WspóárzĊdna x początku áaĔcucha
y
WspóárzĊdna y linii bazowej áaĔcucha
javax.swing.JComponent 1.2 Q
FontMetrics getFontMetrics(Font f) 5.0
Pobiera cechy czcionki. Klasa FontMetrics jest prekursorem klasy LineMetrics. java.awt.FontMetrics 1.0 Q
FontRenderContext getFontRenderContext() 1.2
Pobiera kontekst wizualizacji czcionki.
7.8. WyÊwietlanie obrazów PoznaliĞmy techniki tworzenia prostych rysunków skáadających siĊ z linii i figur geometrycznych. Bardziej záoĪone obrazy, jak zdjĊcia, mają zazwyczaj inne pochodzenie, np. przenosi siĊ je do komputera za pomocą skanera lub wytwarza w wyspecjalizowanym do tego celu oprogramowaniu. W drugim tomie nauczymy siĊ tworzyü obrazy záoĪone z pojedynczych pikseli zapisanych w tablicy — technika ta jest czĊsto uĪywana na przykáad podczas tworzenia obrazów fraktalnych. Obrazy zapisane w postaci plików na dysku lub w internecie moĪna wczytaü do aplikacji w Javie i wyĞwietliü na obiektach Graphics. Obrazy moĪna wczytywaü na wiele sposobów. W poniĪszym przykáadzie uĪyta jest znana nam juĪ klasa ImageIcon: Image image = new ImageIcon(filename).getImage();
Zmienna image zawiera referencjĊ do obiektu opakowującego obraz. MoĪna go wyĞwietliü za pomocą metody drawImage z klasy Graphics: public void paintComponent(Graphics g) { . . . g.drawImage(image, x, y, null); }
Kup książkę
Poleć książkę
352
Java. Podstawy Program z listingu 7.6 robi nawet wiĊcej, poniewaĪ wypeánia caáe okno wieloma obrazami. Rezultat tego widaü na rysunku 7.15. Za to kaskadowe wypeánienie odpowiedzialna jest metoda paintComponent. Najpierw rysujemy jeden obraz w lewym górnym rogu, a nastĊpnie zapeániamy caáe okno za pomocą metody copyArea: for (int i = 0; i * imageWidth <= getWidth(); i++) for (int j = 0; j * imageHeight <= getHeight(); j++) if (i + j > 0) g.copyArea(0, 0, imageWidth, imageHeight, i * imageWidth, j * imageHeight);
Rysunek 7.15. Okno wypeänione kopiami jednego obrazu
Listing 7.6 przedstawia peány kod Ĩródáowy opisywanego program. Listing 7.6. image/ImageTest.java package image; import java.awt.*; import javax.swing.*; /** * @version 1.33 2007-04-14 * @author Cay Horstmann */ public class ImageTest { public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { public void run() { JFrame frame = new ImageFrame(); frame.setTitle("ImageTest"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } }); } } /** * Ramka zawierająca komponent obrazu. */ class ImageFrame extends JFrame { public ImageFrame() { add(new ImageComponent());
Kup książkę
Poleć książkę
RozdziaÄ 7.
Q
Grafika
pack(); } } /** * Komponent wyĞwietlający powielony obraz. */ class ImageComponent extends JComponent { private static final int DEFAULT_WIDTH = 300; private static final int DEFAULT_HEIGHT = 200; private Image image; public ImageComponent() { image = new ImageIcon("blue-ball.gif").getImage(); } public void paintComponent(Graphics g) { if (image == null) return; int imageWidth = image.getWidth(this); int imageHeight = image.getHeight(this); // Rysowanie obrazu w lewym górnym rogu. g.drawImage(image, 0, 0, null); // Powielenie obrazu w obrĊbie komponentu. for (int i = 0; i * imageWidth <= getWidth(); i++) for (int j = 0; j * imageHeight <= getHeight(); j++) if (i + j > 0) g.copyArea(0, 0, imageWidth, imageHeight, i * imageWidth, j * imageHeight); } public Dimension getPreferredSize() { return new Dimension(DEFAULT_WIDTH, ´DEFAULT_HEIGHT); } } java.awt.Graphics 1.0 Q
boolean drawImage(Image img, int x, int y, ImageObserver observer)
Rysuje obraz w naturalnym rozmiarze. Uwaga: to wywoáanie moĪe zwróciü wartoĞü przed narysowaniem obrazu. Parametry:
Kup książkę
img
Obraz do narysowania
x
WspóárzĊdna x lewego górnego rogu
y
WspóárzĊdna y lewego górnego rogu
observer
Obiekt powiadamiający o postĊpie procesu wizualizacji (moĪe byü wartoĞü null)
Poleć książkę
353
354
Java. Podstawy Q
boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer)
Rysuje obraz o zmienionych wymiarach. System dopasowuje rozmiar obrazu do obszaru o podanej szerokoĞci i wysokoĞci. Uwaga: to wywoáanie moĪe zwróciü wartoĞü przed narysowaniem obrazu. Parametry:
Q
img
Obraz do narysowania
x
WspóárzĊdna x lewego górnego rogu
y
WspóárzĊdna y lewego górnego rogu
width
SzerokoĞü obrazu
height
WysokoĞü obrazu
observer
Obiekt powiadamiający o postĊpie procesu wizualizacji (moĪe byü wartoĞü null)
void copyArea(int x, int y, int width, int height, int dx, int dy)
Kopiuje obszar ekranu. Parametry:
x
WspóárzĊdna x lewego górnego rogu obszaru Ĩródáowego
y
WspóárzĊdna y lewego górnego rogu obszaru Ĩródáowego
width
SzerokoĞü obszaru Ĩródáowego
height
WysokoĞü obszaru Ĩródáowego
dx
OdlegáoĞü w poziomie od obszaru Ĩródáowego do obszaru docelowego
dy
OdlegáoĞü w pionie od obszaru Ĩródáowego do obszaru docelowego
Na tym zakoĔczymy wprowadzenie do grafiki w Javie. Bardziej zaawansowane techniki, takie jak grafika 2D i obróbka obrazów, zostaáy opisane w drugim tomie. W kolejnym rozdziale dowiemy siĊ, jak programy reagują na dane wprowadzane przez uĪytkownika.
Kup książkę
Poleć książkę
Skorowidz A abstrakcja, 214 ActiveX, 26, 35, 540 adnotacja, 111, 640 @SafeVarargs, 643 @SuppressWarnings, 643, 648 adres URL, 527, 546 agregacja, 135 akceleratory, 439 akcesorium podglądu, 499 akcesory, 142 akcje, 355, 373 aktualizacje, updates, 39 aktualizowanie preferencji, 558 aktywnoĞü komponentu, 375 algorytm, 132, 718 binarySearch, 723 obliczania kodu mieszającego, 226 QuickSort, 121, 721 znajdujący najwiĊkszy element, 718 algorytmy sortujące, 720 w klasie Collections, 724 alokacja listy tablicowej, 235 analiza funkcjonalnoĞci klasy, 252 MVC, 397 obiektów w czasie dziaáania programu, 257 animacja piáki, 736–742 animowane gify, 546 anonimowe klasy wewnĊtrzne, 289, 300, 363 API Javy, 33 JNLP, 525 Logging, 591
Kup książkę
Preferences, 555, 595 String, 83 aplet, 28, 34, 53, 54 aplet, 511, 533 Jmol, 29 WelcomeApplet, 53 aplety implementacja, 533 komunikacja, 547 konwersja programów, 536 obrazy, 546 pliki audio, 546 Ğrodowisko dziaáania, 547 uruchamianie, 535 aplikacja ImageViewer, 51 Java Web Start, 519 WebStartCalculator, 528 aplikacje graficzne, 50 serwerowe, 29 architektura, framework, 706 kolekcji, 706, 710 model-widok-kontroler, 396 argument, 61 ASCII, 65 asercje, 587 wyáączanie, 588 zastosowania, 589, 590 asocjacja, 135 atak, 25 atrybut classid, 540 codebase, 541 codetype, 540
Poleć książkę
832
Java. Podstawy
atrybuty pozycjonujące, 540 znacznika applet, 537–540 znacznika param, 541, 542 autoboxing, 32 automatyczna konwersja typów, 32 automatyczne opakowywanie, 241 AWT, Abstract Window Toolkit, 314
B bariera cykliczna, 814 bariery, 814 bazowy katalog drzewa pakietu, 187 bezpieczeĔstwo, 25, 35 typów, 639, 649 wątków, 775 biaáa ksiĊga Javy, 22 biblioteka, 33 AWT, 314, 387 fdlibm, 74 IFC, 314 Java2D, 332, 333 JFC, 314 kolekcji, 666, 707 refleksyjna, 247 STL, 666 Swing, 315, 815 biblioteki struktur danych, 666 zabezpieczeĔ, 25 bit, 729 blok, 98 inicjujący, 175 try-catch, 250, 578, 585 try-finally, 578 blokada, 762, 769 jawna, 770 odczytu, 783 uczciwa, 764 wewnĊtrzna, 770 zapisu, 784 bloki synchronizowane, 774 blokowanie po stronie klienta, 774, 775 báąd AssertionError, 587 pomyáki o jeden, 719 ThreadDeath, 752 typu, 650 typu cannot read, 46 báĊdy danych wejĞciowych, 564 kompilacji, 49, 153, 181, 629, 646 programisty, 568
Kup książkę
przydzielania pamiĊci, 25 urządzeĔ, 564 w Eclipse, 49 w kodzie, 565 wejĞcia-wyjĞcia, 565 wewnĊtrzne, 568 wykonawcze, 644 zabezpieczeĔ, 25 zaokrąglania, 64, 333
C catch, 250 cechy jĊzyka, 22, 33 komponentu, 393 certyfikat bezpieczeĔstwa, 524 niebezpieczny, 525 wáasny, 524 chwytanie typu wieloznacznego, 655 ciaáo metody, 60 czasocháonne zadania, 816 czcionki, 343 bezszeryfowe, 346 nazwy, 343 nazwy logiczne, 344 PostScript type 1, 345 styl, 345 TrueType, 345 wysokoĞü, 346
D dane, 195 binarne, 26 wejĞciowe, 89 wyjĞciowe, 91 debuger, 28, 621 debuger JSwat, 623 debugowanie, 609 debugowanie aplikacji z GUI, 614 definiowanie klasy, 148 klasy ogólnej, 630 kolorów, 340 sáuchacza, 356 staáej klasowej, 69 wątku, 745 wyjątków kontrolowanych, 567 zmiennej, 66, 68 zmiennej obiektowej, 138 zmiennej tablicowej, 117
Poleć książkę
Skorowidz dekompilowanie pliku, 761 dekrementacja, 71 delegacja, 265 delegacja zdarzeĔ, 356 demony, 753 dezaktywacja elementów menu, 441 diagram dziedziczenia klasy, 215, 534 dziedziczenia zdarzeĔ AWT, 387 hierarchii wyjątków, 565 klas, 136 przepáywu sterowania, 100–106, 110 dodawanie akcji do menu, 375 elementu do listy powiązanej, 678 elementu do mapy, 702 ikony, 435 klasy do pakietu, 182 klauzuli throws, 96 komponentów, 401 dokumentacja, 194 API, 85–87 JSR, 627 zaáoĪeĔ, 590 dopasowywanie typów, 659 dopeánienie, 459 wewnĊtrzne, 452 zewnĊtrzne, 452 dostĊp chroniony, 219 do apletu, 539 do elementów kolekcji, 672, 708 do elementów listy tablicowej, 236 do elementu tablicy, 117 do formatera, 781 do komponentów, 473 do pakietów, 518 do plików lokalizacyjnych, 516 do pliku, 96 do pliku JNLP, 521 do pól, 155 do pól generycznych, 637 do prywatnych pól nadklasy, 202 do sekcji krytycznej, 762 do stanu obiektu, 289 do usáugi, 526 do wartoĞci, 243 do wĊzáa drzewa, 555 do zasobów lokalnych, 525 do zmiennej warunkowej, 775 do zmiennych finalnych, 297 jednoczesny wątków, 761 swobodny, 719, 723 wątków do struktury danych, 757
Kup książkę
drukowanie, 31 drukowanie informacji o klasie, 252 drzewo katalogów, 42 duĪe liczby, big numbers, 62 dymki, tooltips, 446 dyrektywa #include, 182 import, 90 dziaáanie kontrolera, 395 metody transfer, 761 dziedziczenia klasy Applet, 534 dziedziczenie, inheritance, 133, 199, 268 hierarchia, 206 klasy abstrakcyjne, 214 klasy finalne, 211 metody finalne, 211 ochrona dostĊpu, 219 polimorfizm, 207 pomiĊdzy klasami par, 649 rzutowanie, 212 typów ogólnych, 649 wiązanie dynamiczne, 209 wielokrotne, 279 dzielenie caákowitoliczbowe, 69 modulo, 69 zmiennoprzecinkowe, 69 dzienniki, 591 dzienniki rotacyjne, 599
E Eclipse, 44, 47 edycja kodu Ĩródáowego, 48 ĞcieĪki dostĊpu, 39 edytor tekstowy Emacs, 44 JEdit, 44 TextPad, 44 edytowalna lista rozwijalna, 423 EE, Enterprise Edition, 38 egzemplarz klasy, 132 elementy menu, 432 aktywowanie, 440 dezaktywowanie, 440 ikony, 435 pola wyboru, 436 przeáączniki, 436 elementy tablicy, 116 eliminacja wywoáaĔ funkcji, 27 elipsa, 335
Poleć książkę
833
834
Java. Podstawy
H
etykiety, 459 HTML, 409 komponentów, 408 ewolucja Javy, 32
F figury 2D, 332 geometryczne, 333 filtr plików, 496, 497, 505 rekordów, 600 firma Oracle, 32, 34 Sun Fellow, 30 Sun Microsystems, 25, 34 format binarny liczby, 63 JNLP, 519 Unicode, 26 XML, 556 formatery, 600 formatowanie danych wyjĞciowych, 91 daty, 95 funkcja unexpected, 569 funkcje czysto wirtualne, 216 matematyczne, 73 sieciowe, 24 skáadowe, 60
G GC, Garbage Collector, 702 generowanie dokumentacji, 194 obiektów klas ogólnych, 646 generyczne klasy, 629 listy tablicowe, 233 generyczny kod tablicowy, 261 graficzny interfejs uĪytkownika, GUI, 28, 57, 313, 391, 614 grafika, 313 grupa, 754 przycisków radiowych, 416 wątków, 755 zadaĔ, 808 GTK, 316
Kup książkę
harmonogram wykonywania wątków, 750 zadaĔ, 696 hasáo, 90, 410 hermetyzacja, 133, 155 hierarchia dziedziczenia, 206 dziedziczenia interfejsu Type, 660 dziedziczenia klasy Component, 400 dziedziczenia klasy JFrame, 321 interfejsów, 278 wyjątków, 566, 586 zdarzeĔ, 387 historia Javy, 30 HTML, 33
I IDE, 39, 47 identyfikacja klas, 134 IFC, Internet Foundation Classes, 314 ikony, 435 ikony komunikatów, 475 implementacja apletów, 533 ArrayList, 644 interfejsu, 271, 273 klasy Bank, 770 klasy ogólnej, 629 kolejki, 667 import klas, 180 statyczny, 182 indeks, 123 indeks argumentu, 95 informacje o klasie, 252 o typach, 28 o typach czasu wykonywania, 248 o typach generycznych, 659 o typach obiektów, 248 o uruchomionym programie, 613 o zdarzeniach, 602 inicjalizacja pól, 172 pól statycznych, 176 pól wartoĞciami domyĞlnymi, 171 tablic, 118 z podwójną klamrą, 302 zmiennej obiektowej, 138 zmiennych, 68
Poleć książkę
Skorowidz inkrementacja, 71 instalacja bibliotek, 41 dokumentacji, 41 filtru, 600 JDK, 38, 39 programów, 42 instrukcja break, 111–114 break z etykietą, 112 case, 111 continue, 113 do-while, 104 for, 77 goto, 111 if, 100, 113 if-else, 100 if-else if, 102 import, 180, 182 lock, 762 return, 578 switch, 109–111 try, 580, 581 while, 103 instrukcje sterujące, 98 warunkowe, 98, 109, 113 záoĪone, 99 interfejs Action, 373, 379, 433 ActionListener, 286, 300, 357, 364, 373, 389 AdjustmentListener, 389 AppletContext, 547 AutoCloseable, 580 BasicService, 527 BlockingDeque<E>, 793 BlockingQueue<E>, 792 ButtonModel, 397, 398, 417 Callable, 797 Callable<V>, 801 Cloneable, 282 Collection, 668–672, 679, 707, 711 Collection<E>, 672 Comparable, 272, 279, 308, 634, 654, 689 Comparator<T>, 690, 693 Condition, 769–771 Delayed, 792 Deque<E>, 695 Enumeration, 670, 727 ExecutorService, 803, 808 FileFilter, 497 Filter, 600 FocusListener, 389 Formattable, 92
Kup książkę
Future, 798 Future<V>, 801 GenericArrayType, 660, 664 InvocationHandler, 307, 311 ItemListener, 389 Iterable, 117, 669 Iterator, 669, 677, 680 Iterator<E>, 674 klasy, 146 LayoutManager, 469 LayoutManager2, 469 LinkedList<E>, 683 List, 684, 708, 711 List<E>, 682 ListIterator, 677, 708 ListIterator<E>, 683 Lock, 764, 769, 771, 783 KeyListener, 389 Map, 707 Map<K, V>, 700 MenuListener, 441 MouseListener, 381, 383, 389 MouseMotionListener, 381, 383, 389 MouseWheelListener, 389 nasáuchu, 356 NavigableMap, 709 NavigableMap<K, V>, 716 NavigableSet, 709, 712 NavigableSet<E>, 694, 716 ParameterizedType, 660, 664 PersistenceService, 527 PersistentService, 528 Powered, 278 Queue, 666, 667 Queue<E>, 695 RandomAccess, 708, 721 Runnable, 797 ScheduledExecutorService, 807 Set, 708 Shape, 333 SortedMap, 709 SortedMap<K, V>, 716 SortedSet, 709, 712 SortedSet<E>, 693, 716 SwingConstants, 278, 408 Thread.UncaughtExceptionHandler, 754 TransferQueue, 788 TransferQueue<E>, 793 Type, 660 TypeVariable, 660, 664 WildcardType, 660, 664 WindowFocusListener, 389 WindowListener, 369, 372, 389 WindowStateListener, 372, 389
Poleć książkę
835
836
Java. Podstawy
interfejsu, 219, 265 hierarchia, 278 implementacja, 271, 273 metody, 278 sprzĊĪenie zwrotne, 286 zmienne, 277 interfejsy architektury kolekcji, 707 kolekcyjne, 665, 707, 719 nasáuchowe, 389 nasáuchujące AWT, 389 przenoĞne, 27 uĪytkownika, 34, 391 znacznikowe, 282 interlinia, 346 interpreter, 27, 184 iterator jako parametr, 727 iteratory, 669, 670
J JAR, Java Archive, 512 Java look and feel, 315 Java Micro Edition, 23 Java Plug-in, 540 Java Runtime System, 26 Java Web Start, 511, 519 JavaBeans, 247 JavaFX, 317 jawna inicjalizacja pól, 172 JDK, Java Development Kit, 37 jednostki kodowe, 66, 81 jĊzyk Algol, 165 C, 25 C#, 28, 34 C++, 23, 24 HTML, 33 J#, 28 J++, 28 Java, 22 JavaScript, 35 UML, 136 Visual Basic, 23, 137 jĊzyki interpretowane, 34 obiektowe, 24 proceduralne, 24 JFC, Java Foundation Classes, 314 JIT, just-in-time compiler, 27 JNLP, Java Network Launch Protocol, 519 JRE, Java Runtime Environment, 38 JSR, Java Specification Requests, 627
Kup książkę
K kalendarz, 139 kalkulator, 403, 521 karta HSB, 506 RGB, 506 Swatches, 506 katalog bazowy drzewa pakietu, 187 bin, 39 com, 183 gutenberg, 820 src, 43 klas coupling, 135 diagramy, 136 dziedziczenie, 133, 200 identyfikacja, 134 implementacja interfejsu, 271 komentarze, 191 konstruktory, 137, 152 metody, 133 metody prywatne, 157 metody statyczne, 160 nadklasy, 200 plik Ĩródáowy, 189 podklasy, 200 pola statyczne, 159 predefiniowanie, 137 projektowanie, 195 relacje, 135 rozszerzanie, 133 pola staáe, 158 ĞcieĪka, 187 klasa, 58, 132 ExampleFileView, 499 AbstractAction, 374, 377 AbstractButton, 419, 434–436, 440 AbstractCollection, 672 AbstractList, 726 AbstractQueue, 668 AbstractSequentialList, 723 AbstractSet, 223 AccessibleObject, 257, 261 ActionMap, 376 AnonymousInnerClassTest, 301 Applet, 533, 537, 545, 549 AppletContext, 540, 548, 549 Array, 262 ArrayAlg, 663 ArrayBlockingQueue<E>, 791 ArrayDeque, 694 ArrayDeque<E>, 696
Poleć książkę
Skorowidz ArrayDequeue, 668 ArrayList, 234–236, 240, 628, 642, 674, 684 ArrayList<T>, 650 ArrayListTest, 238 Arrays, 118, 121, 123 AtomicInteger, 777 AWTEvent, 387 BallRunnable, 742 BasicButtonUI, 398 BasicService, 528, 531 bazowa Object, 133, 220 BigDecimal, 64, 114, 116 BigInteger, 114, 115 BigIntegerTest, 115 BitSet, 726, 729 BlockingQueueTest, 789 BorderFactory, 419, 421 BorderLayout, 401, 402 BounceFrame, 737 BuggyButtonTest, 622 ButtonFrame, 360 ButtonGroup, 417, 418 ButtonModel, 417, 418 ButtonUIListener, 398 Calendar, 140 CalendarTest, 145 CheckBoxTest, 415 CircularArrayQueue, 668 Class, 233, 248–251, 255, 261, 658 Class<T>, 658, 663 CloneTest, 284 Collections, 679, 711, 715, 724 Color, 340, 342, 343 ColorAction, 360, 362 Component, 322, 325, 332, 343, 399, 408 ConcurrentHashMap, 794 ConcurrentHashMap<K, V> 5.0, 795 ConcurrentLinkedQueue<E>, 795 ConcurrentSkipListMap, 794 ConcurrentSkipListSet<E>, 795 Console, 90, 91 ConsoleHandler, 600, 607 Constructor, 250–252, 256, 658 ConstructorTest, 177 Container, 362, 399 CopyOfTest, 263 CountDownLatch, 813 Cursor, 381 CyclicBarrier, 814 Date, 139, 140 DateFormatSymbols, 144, 148 DateInterval, 638 Dimension, 330 Double, 276
Kup książkę
DrawTest, 337 Ellipse2D, 335 Ellipse2D.Double, 340 Employee, 148, 151, 163, 184, 639 EmployeeSortTest, 275 EmployeeTest, 149 Enum, 246 EnumMap, 704 EnumMap<K extends Enum<K>, V>, 706 EnumSet, 704 EnumSet<E extends Enum<E>>, 706 EnumTest, 246 EOFException, 570 EqualsTest, 230 Error, 565 EventHandler, 364, 365 EventObject, 363, 387 EventTracer, 616 Exception, 251, 565, 583 Exchanger, 814 Executors, 802 ExtendedService, 527 Field, 252, 256, 258, 261, 265 File, 497 FileContents, 531 FileFilter, 504 FileHandler, 600, 607 FileInputStream, 567 FileNameExtensionFilter, 505 FileOpenService, 526, 532 FileSaveService, 532 FileView, 497, 505 Filter, 609 FlowLayout, 400 Font, 345, 349 FontMetrics, 351 FontParamApplet, 541 FontRenderContext, 346 FontTest, 348 ForkJoinTest, 811 Formatter, 600, 609 Frame, 318, 326 FutureTask<V>, 802 FutureTest, 799 GenericReflectionTest, 661 Graphics, 332, 343, 350, 353 Graphics2D, 332, 333, 343, 351 GraphicsDevice, 325, 617 GraphicsEnvironment, 344, 620 GregorianCalendar, 139–143, 146, 654 GridBagConstraints, 454, 458 GridLayout, 399, 405 GroupLayout, 459, 463, 466 Handler, 598, 607
Poleć książkę
837
838
Java. Podstawy
klasa HashMap<K, V>, 701 HashSet, 684, 686 HashSet<E>, 687 Hashtable, 709, 726 IdentityHashMap, 705 IdentityHashMap<K, V>, 706 ImageIcon, 327, 351 ImagePreviewer, 499 ImageTest, 352 InnerClassTest, 292 InputEvent, 386 InputMap, 376 Integer, 242, 276, 308 Iterator, 290 JApplet, 533 JButton, 361, 397 JCheckBox, 415 JCheckBoxMenuItem, 436 JColorChooser, 505, 509 JComboBox, 425, 725 JComponent, 328, 347, 351, 379, 408, 419, 438 JDialog, 484, 488 JEditorPane, 412 JFileChooser, 495, 503 JFrame, 318, 321, 331, 434, 484 klasa JLabel, 408, 499 klasa JList, 425 JMenu, 433 JMenuBar, 432 JMenuItem, 434, 440 JOptionPane, 288, 474, 481, 484 JPanel, 330 JPasswordField, 406, 410 JPopupMenu, 437 JRadioButton, 418 JRadioButtonMenuItem, 436 JScrollPane, 413 JSlider, 426, 431, 640 JTextArea, 406, 410, 412 JTextComponent, 406 JTextField, 406, 408 JToolBar, 445, 447 KeyStroke, 375, 379 LayoutManager, 472 Line2D.Double, 340 LineBorder, 422 LineMetrics, 347, 350 LinkedBlockingQueue<E>, 792 LinkedHashMap, 702, 704 LinkedHashMap<K, V>, 705 LinkedHashSet, 702 LinkedHashSet<E>, 705 LinkedList, 290, 668, 675, 684, 694, 713
Kup książkę
LinkedListQueue, 668 LinkedListTest, 681 LinkedTransferQueue, 788 ListIterator, 679 Lock, 762 Logger, 605 LogManager, 595 LogRecord, 609 LookAndFeelInfo, 368 Manager, 232 ManagerTest, 205 MapTest, 699 Math, 73, 74 MenuListener, 441 Method, 252, 265, 663 MethodTableTest, 266 Modifier, 252, 256 MouseEvent, 380, 386 MouseHandler, 383 MouseMotionHandler, 383 MouseMotionListener, 381 Object, 220 ObjectAnalyzer, 258 ObjectAnalyzerTest, 259 PackageTest, 183, 184 Pair, 303, 637, 641, 648, 655 Pair<T>, 659 PairTest1, 631 PairTest2, 635 PairTest3, 656 ParallelGroup, 468 ParamTest, 169 PasswordChooser, 490 Paths, 97 PersistenceService, 532 PersonTest, 217 PlafFrame, 368 Point2D, 335 Point2D.Double, 340 Preferences, 556, 560 PreferencesFrame, 558 PrintWriter, 97 PriorityBlockingQueue<E>, 792 PriorityQueue, 697 PriorityQueueTest, 697 Properties, 550–555, 709, 728 PropertiesTest, 551 Proxy, 307, 311 ProxyTest, 309 Rectangle2D, 334, 335 Rectangle2D.Double, 334, 339 Rectangle2D.Float, 334, 339 RectangularShape, 335, 339 RecursiveTask<T>, 810
Poleć książkę
Skorowidz ReentrantLock, 762–764, 783 ReentrantReadWriteLock, 783 ReflectionTest, 253 ResourceBundle, 596 ResourceTest, 517 Robot, 617, 618 Runnable, 746 RuntimeException, 566–568, 583 Scanner, 89, 90, 97 SequentialGroup, 468 ServiceManager, 531 SetTest, 686 ShuffleTest, 721 SimpleDateFormat, 781 SimpleFrame, 319 SimpleFrameTest, 318 Singleton, 645 SizedFrameTest, 324 SoftBevelBorder, 421, 422 SortedMap<K, V>, 701 SQLException, 576 Stack, 709, 729 StackTraceElement, 581, 583 StackTraceTest, 582 StaticInnerClassTest, 305 StaticTest, 162 StreamHandler, 598 StrictMath, 74 String, 77, 83, 86, 211 StringBuilder, 86, 88 SwingThreadTest, 818 SwingUtilities, 494 SwingWorker, 820, 824, 826 SwingWorkerTest, 821 SynchronousQueue, 815 System, 43, 554 SystemColor, 341 TalkingClock, 289, 295–297 Thread, 647, 746, 749–753 ThreadGroup, 754, 755 ThreadLocal, 781 ThreadLocal<T>, 782 ThreadPoolTest, 804 Throwable, 251, 565, 570, 581, 583 TimePrinter, 291–295 Timer, 286–288 TimerTest, 287 ToolBarTest, 447 Toolkit, 288, 323, 327, 386 TraceHandler, 307 TransferRunnable, 780 TreeMap<K, V>, 701 TreeSet, 688, 691
Kup książkę
TreeSet<E>, 688, 694 TreeSetTest, 691 UIManager, 368 Vector, 234, 684, 709, 726 WeakHashMap, 702 WeakHashMap<K, V>, 705 Window, 322, 326 WindowAdapter, 370 WindowEvent, 372 klasy abstrakcyjne, 214, 216, 279 adaptacyjne, adapter class, 369 anonimowe, 300 bazowe, 200, 279 blokad, 783 finalne, 211 generyczne, 234 graniczne, 636 kolekcyjne, 627, 672, 674, 709, 726 kontenerowe, 709 macierzyste, 200 modelowe, 397 niezmienne, 158 ogólne, generic class, 629 osáonowe, 241 pochodne, 200 podpisywane cyfrowo, 25 pomocnicze, 453, 781 potomne, 200 proxy, 306, 311 publiczne, 180 specjalne, 702 statyczne, 303 surowe, 237 szablonowe, 632 w architekturze kolekcji, 710 wewnĊtrzne, 271, 289 anonimowe, 300 bezpieczeĔstwo, 296 dostĊp do stanu obiektu, 289 dostĊp do zmiennych finalnych, 297 lokalne, 296 obsáuga zdarzeĔ, 362 prawa dostĊpu, 296 referencja do klasy zewnĊtrznej, 293 referencja do obiektu zewnĊtrznego, 291 reguáy skáadniowe, 293 skáadnia, 289 statyczne, 303 wyjątków, 570 wyliczeniowe, 245 zagnieĪdĪone, 290 zdarzeniowe AWT, 387 klasyfikacja wyjątków, 565
Poleć książkę
839
840
Java. Podstawy
klauzula catch, 572, 748 finally, 576, 578 throws, 96, 567 try, 572 klawiatura, 375 klawisze specjalne, 380 klonowanie obiektów, 280, 285 klucz URL, 528 klucze, 698 klucze naleĪące do wĊzáa, 560 kod bajtowy, 26 báĊdu, 570 kod generyczny, 630 kod maszynowy, 26 kod mieszający, hash code, 225, 684, 687 kod ogólny, 635 kod wyjĞcia, exit code, 60 kodowanie Unicode, 65, 67 UTF-16, 66, 82 kolejka, queue, 666 ArrayBlockingQueue, 788 DelayQueue, 788 Deque, 694 LinkedBlockingQueue, 787 PriorityBlockingQueue, 788 Queue, 694 kolejki blokujące, 786 dostĊpu, 472 priorytetowe, 696 synchroniczne, 815 kolejnoĞü dostĊpu, 703 dostĊpu do komponentów, 473 ograniczeĔ, 637 kolekcja, 117, 665 par, 698 wątków, 754 kolekcje bezpieczne wątkowo, 794, 796 ograniczone, 668 uporządkowane, 677, 708 w bibliotece, 675 kolizja nazw, 180 kolizje, 685 kolor, 340 kolor táa, 341, 507 komentarze, 61 do klas, 191 do metod, 191 do pakietów, 194 do pól, 192
Kup książkę
dokumentacyjne, 190 ogólne, 192 komparator, 690 kompilacja programu, 44 w czasie rzeczywistym, 26 kompilator, 25, 45, 776 czasu rzeczywistego, 34 javac, 188 JIT, 27, 212 komponenty Swing, 391–510 tekstowe, 411 kompresja ZIP, 512 komunikacja miĊdzy apletami, 540, 547 miĊdzyprocesowa, 736 komunikat, 592 o báĊdzie, 46, 50, 569 o wyjątkach, 816 konektor UML, 136 konfiguracja komponentów, 319 menedĪera dzienników, 598 projektu, 48 konflikt metod, 648 konkatenacja, 78 konsola, 44 konstruktor, 137, 152 bezargumentowy, 172 domyĞlny, 172 kopiujący, 140 przeciąĪony, 172 wirtualny, 250 konstruktory klasy FileHandler, 607 klasy HashSet<E>, 687 klasy TreeMap<K, V>, 701 klasy TreeSet<E>, 694 kontekst graficzny, 328 urządzenia, 328 kontener, 330, 399 kontrola dostĊpu, 290 nazw, 290 typów, 627 kontroler, controller, 394 konwersja áaĔcucha na liczbĊ, 242 pomiĊdzy kolekcjami a tablicami, 718 programów na aplety, 536 tablic, 718 typów, 650 typów numerycznych, 74
Poleć książkę
Skorowidz koĔczenie dziaáania programu, 60 kopie áaĔcucha, 80 obrazu, 352 kopiowanie gáĊbokie, 281 obiektów, 280 páytkie, 281 tablicy, 119 zmiennej tablicowej, 119 koszty uzyskania certyfikatu, 524 kowariantne typy zwrotne, 209, 639 kubeáek, bucket, 685 kursory, 382 kwalifikator .this, 294
L licencja GPL, 34 liczba klikniĊü, 381 parametrów, 244 liczby caákowite, 62 zmiennoprzecinkowe, 64 linia bazowa, 346, 347 dolna pisma, 346 górna pisma, 346 lista ArrayList, 117 kluczy, 556, 698 modyfikowalna, 721 rozwijalna, combo box, 423 wątków, 779 listy cykliczne, 666, 668 dwukierunkowe, 25, 238, 674 powiązane, 668, 674, 680 tablicowe, 234, 236, 684 surowe, 239 z typem, 240 lokalizacja, 143, 596 komunikatów, 596 pliku, 546 lokalne klasy wewnĊtrzne, 289, 296
à áadowanie klas, 307 pliku w osobnym wątku, 821 zasobów, 516
Kup książkę
841
áaĔcuch _blank, 548 dziedziczenia, 206 null, 81 prompt, 91 pusty, 81 testowy, 407 wyjątków, 575 áaĔcuchy, 77 áączenie, 78 modyfikowanie, 79 porównywanie, 79 skáadanie, 86 wspóádzielenie, 79 zmienialne, mutable, 80 áączenie narastające, 27
M makro assert, 588 manifest, 512 mapa, 697 akcji, 376 HashMap, 698 haszowa, 795 wejĞcia, 376 wáasnoĞci, property map, 550, 553, 728 mapy klawiaturowe, 376 maska bitowa, 380 maszyna wirtualna, JVM, 26, 514 opcja -verbose, 612 opcja -Xlint, 612 opcja -Xprof, 614 ME, Micro Edition, 38 menedĪer dzienników, 595 zabezpieczeĔ, 522 menu, 432 menu podrĊczne, pop-up menu, 437 metadane, 32 metoda, 133 accept, 504 acquire, 812 actionPerformed, 286, 291, 357, 368, 414, 433 add, 142, 237, 399, 433, 629, 677 addActionListener, 364 addAll, 629, 672, 682 addBall, 737, 742 addChangeListener, 426 addChoosableFileFilter, 504 addComponent, 467 addContainerGap, 468 addFirst, 683 addGap, 467
Poleć książkę
842
Java. Podstawy
metoda addGroup, 467 addItem, 423, 426 addLast, 683 addPropertyChangeListener, 373 addSeparator, 434, 447 addSuppressed, 583 addWindowListener, 370 akcesora get, 141 and, 730 andNot, 730 append, 87, 413 appendCodePoint, 88 Arrays.hashCode, 227 Arrays.toString, 230 asList, 711 await, 766, 769, 783, 814 awaitUninterruptibly, 783 beep, 289 binarySearch, 123, 308, 722 BorderFactory, 421 brighter, 341 call, 801 cancel, 802 canRead, 532 canWrite, 532 cast, 658 ceiling, 694 charAt, 83 checkedCollection, 713 clear, 672, 730 clone, 280–284 close, 179, 580, 600, 607, 762 codePointAt, 83 codePointCount, 84 compare, 276, 690, 693 compareTo, 83, 246, 272–274, 299, 634, 653, 693, 720 Component.show, 320 config, 605 console, 91 contains, 672, 680, 686 containsAll, 672, 673 containsKey, 700 containsValue, 700 copy, 724 copyArea, 352, 354 copyOf, 123 countdown, 813 create, 365 createCompoundBorder, 422 createCustomCursor, 382, 386 createEmptyBorder, 421 createEtchedBorder, 421
Kup książkę
createFont, 345 createLineBorder, 421 createLoweredBevelBorder, 421 createMatteBorder, 421 createParallelGroup, 467 createRaisedBevelBorder, 421 createScreenCapture, 618 createTitledBorder, 422 darker, 341 decrementAndGet, 777 metoda delay, 621 metoda delete, 88 deriveFont, 345, 350 destroy, 537 disjoint, 725 divide, 115 doInBackground, 824–826 draw, 333, 340 drawImage, 353 drawString, 329, 341, 347, 351 elements, 728 endsWith, 83 ensureCapacity, 236 entering, 600, 605 entrySet, 700 equals, 79, 83, 124, 221, 242, 648, 705 equalsIgnoreCase, 83 execute, 827 exiting, 600, 605 fill, 340, 343, 724 fillMenu, 725 finalize, 179 fine, 605 finer, 605 finest, 605 firstKey, 701 floor, 694 flush, 600, 607 Font.createFont, 345 format, 609 formatMessage, 609 formatTo, 92 forName, 248, 251 frame.setUndecorated, 320 frequency, 725 get, 142, 236, 261, 264, 628, 682 getActionCommand, 363, 388, 417 getActionMap, 379 getActualTypeArguments, 664 getAllItems, 726 getAncestorOfClass, 494 getApplet, 540 getAppletContext, 547, 549 getAppletInfo, 545
Poleć książkę
Skorowidz getApplets, 548, 549 getAudioClip, 547 getAutoCreateContainerGaps, 467 getAutoCreateGaps, 467 getAvailableFontFamilyNames, 344 getBackground, 343 getBounds, 664 getCause, 583 getCenterX, 339 getClass, 222, 248, 641 getClassName, 368, 584 getClickCount, 380, 386 getCodeBase, 528, 531 getColor, 343, 510 getColumns, 408 getComponentPopupMenu, 438 getConstructor, 658, 659 getConstructors, 252, 255 getContentPane, 327, 331 getDeclardeFields, 261 getDeclaredConstructor, 658 getDeclaredConstructors, 252, 256 getDeclaredField, 261 getDeclaredFields, 252, 255, 258 getDeclaredMethods, 252, 255 getDeclaringClass, 256 getDefaultScreenDevice, 621 getDefaultToolkit, 288, 323, 327 getDelay, 788, 792 getDescent, 350 getDescription, 505 getDocumentBase, 546 getDouble, 258, 610 getEnumConstants, 658 getExceptionTypes, 256 getExtendedState, 326 getFamily, 349 getField, 261 getFields, 252, 255, 261 getFileName, 583 getFilter, 607 getFirst, 637, 652, 683 getFirstDayOfWeek, 143 getFont, 350, 408 getFontMetrics, 347, 351 getFontName, 349 getFontRenderContext, 346, 351 getForeground, 343 getFormatter, 607 getGenericComponentType, 664 getGenericInterfaces, 663 getGenericParameterTypes, 663 getGenericReturnType, 663 getGenericSuperclass, 663
Kup książkę
getHandlers, 606 getHead, 609 getHeight, 347 getHonorsVisibility, 467 getIcon, 409, 505 getIconImage, 326 getImage, 327, 547 getInheritsPopupMenu, 438 getInputMap, 376, 379 getInputStream, 526, 531 getInstalledLookAndFeels, 368 getKey, 701 getKeyStroke, 375 getLast, 683 getLeading, 350 getLength, 262, 264 getLevel, 606, 607 getLineMetrics, 347, 350 getLineNumber, 584 getLocalGraphicsEnvironment, 344 getLogger, 605 getLoggerName, 608 getLowerBounds, 664 getMaxX, 339 getMessage, 571, 608 getMethodName, 584 getMethods, 255 getMethodsi, 252 getMillis, 608 getMinX, 339 getModifiers, 252, 256 getModifiersEx, 381, 386 getModifiersExText, 386 getMonths, 148 getName, 150, 249, 349, 505, 664 getNewState, 372 getOldState, 372 getOutputStream, 526, 532 getOwnerType, 664 getPaint, 343 getParameter, 541, 545 getParameterInfo, 546 getParameters, 608 getParameterTypes, 256 getParent, 606 getPassword, 410 getPoint, 386 getPredefinedCursor, 381 getPreferredSize, 330 getProperties, 550, 554 getProperty, 553, 728 getProxyClass, 311 getRawType, 664 getResource, 516
Poleć książkę
843
844
Java. Podstawy
metoda getResourceBundle, 608 getResourceBundleName, 608 getReturnType, 256 getRootPane, 494 getSalary, 214, 265 getScreenSize, 323, 327 getSelectedFile, 504 getSelectedItem, 423–426 getSelectedObjects, 417 getSelection, 417, 418 getSequenceNumber, 609 getServiceNames, 531 getShortMonths, 148 getShortWeekdays, 144, 148 getSource, 388, 424 getSourceClassName, 608 getSourceMethodName, 608 getStackTrace, 581, 583 getState, 752 getStringBounds, 346 getSuperclass, 659 getSuppressed, 581 getTail, 609 getText, 406, 409 getThreadID, 609 getThrown, 608 getTitle, 322, 326 getTotalBalance, 764 getType, 252 getTypeDescription, 505 getTypeParameters, 663 getUpperBounds, 664 getUseParentHandlers, 607 getValue, 373, 379, 701 getWeekdays, 148 getWidth, 334, 335, 339, 346 getX, 339, 386 getY, 386 hashCode, 225, 684, 706 hasMoreElements, 670, 727 hasNext, 91, 669, 674, 677 hasNextDouble, 91 hasNextInt, 91 headMap, 712, 716 headSet, 712, 716 higher, 694 IconImage, 522 in.close, 580 incrementAndGet, 777 indexOf, 84 indexOfSubList, 724 info, 605 init, 536
Kup książkę
initCause, 583 initialize, 782 initialValue, 781 insert, 88, 434 insertItemAt, 426 InsertItemAt, 424 insertSeparator, 434 interrupt, 746, 749 interrupted, 748, 749 intValue, 243 invoke, 265–267, 311 invokeAll, 808, 810 invokeAndWait, 820 invokeAny, 808 invokeLater, 817, 820 isAbstract, 256 isAccessible, 261 isDispatchThread, 820 isDone, 777 isEditable, 406, 425 isEmpty, 672, 673 isEnabled, 373, 379 isFinal, 252, 256 isInterface, 256 isInterrupted, 746–749 isJavaIdentifierPart, 67 isJavaIdentifierStart, 67 isLocationByPlatform, 323, 326 isLoggable, 600, 609 isNative, 256 isNativeMethod, 584 isPopupTrigger, 438 isPrivate, 252, 256 isProtected, 256 isProxyClass, 311, 312 isPublic, 252, 256 isResizable, 326 isSelected, 415, 436 isStatic, 256 isStrict, 257 isSynchronized, 257 isTraversable, 498, 505 isUndecorated, 326 isVisible, 325 isVolatile, 257 isWebBrowserSupported, 531 itemComparator, 720 iterator, 668, 672 join, 752, 810 JTextField, 406 keyPress, 621 keyRelease, 621 keySet, 700 KeyStroke, 379
Poleć książkę
Skorowidz lastIndexOf, 84 lastIndexOfSubList, 724 lastKey, 701 layoutContainer, 472 length, 84, 730 linkSize, 466 listFiles, 497 listIterator, 677, 682 load, 554, 728 lock, 762, 764, 782 lockInterruptibly, 783 log, 593, 606 logp, 606 logrb, 606 lookup, 531 lower, 694 main, 59, 148, 162, 249 makeButton, 362 makePair, 644 Math.random, 122 Math.round, 75 menuCanceled, 441 menuDeselected, 441 menuSelected, 441 minimumLayoutSize, 472 mod, 115 modifiers, 256 mouseClicked, 380, 381 mouseDragged, 382 mouseEntered, 383 mouseExited, 383 mouseMove, 621 mouseMoved, 381, 382 mousePress, 621 mousePressed, 380, 381 mouseRelease, 621 mouseReleased, 380 move, 736 multiply, 115, 116 mutatora set, 142 newCondition, 765, 769 newFixedThreadPool, 803 newInstance, 249–251, 262, 658 newProxyInstance, 307, 311 newScheduledThreadPool, 807 newSingleThreadScheduledExecutor, 807 next, 669, 679 nextDouble, 89, 91, 610 nextElement, 670, 727 nextInt, 89, 91 nextLine, 89, 91 node, 560 notify, 773 notifyAll, 773
Kup książkę
Object.clone, 282 Objects.hashCode, 227 offer, 787, 793 offerFirst, 793 offerLast, 793 offsetByCodePoints, 83 openFileDialog, 526, 532 openMultiFileDialog, 532 or, 730 ordinal, 247 pack, 330, 332 paintComponent, 328, 347, 475, 569 parse, 244 parseInt, 242, 243 peek, 729, 787 play, 546 poll, 787, 793, 809 pollFirst, 694, 793 pollLast, 694, 793 pop, 729 preferredLayoutSize, 472 previous, 677–680 previousIndex, 680 print, 96 printBuddies, 651 printf, 92, 244 println, 60, 96, 229, 310 printStack, 251 printStackTrace, 251, 581, 611 process, 826 publish, 599, 607, 825 push, 729 put, 556, 787, 792 putFirst, 793 putIfAbsent, 794 putLast, 793 putValue, 373, 379 raiseSalary, 284 readConfiguration, 595 readLine, 91 readLock, 784 readPassword, 91 release, 812 remove, 434, 669–673, 678, 682 removeAll, 672, 673, 681 removeAllItems, 426 removeEldestEntry, 705 removeFirst, 683 removeHandler, 607 removeItem, 424, 426 removeItemAt, 424, 426 removeLast, 683 removeLayoutComponent, 472 removePropertyChangeListener, 373
Poleć książkę
845
846
Java. Podstawy
metoda repaint, 329, 332, 827 replace, 84, 796 replaceAll, 724 res.close, 580 resetChoosableFileFilters, 504 resize, 537 resume, 752 retainAll, 672, 717 revalidate, 407, 408 reverse, 724 reverseOrder, 722 rotate, 724 run, 647, 754 Runtime.addShutdownHook, 179 saveAsFileDialog, 532 saveFileDialog, 526 schedule, 807 scheduleAtFixedRate, 807 scheduleWithFixedDelay, 808 ServiceManager, 526 set, 142, 236, 261, 679, 682 setAccelerator, 440 setAccessible, 257, 261 setAccessory, 504 setAction, 434 setActionCommand, 363, 417, 419 setAutoCreateContainerGaps, 467 setAutoCreateGaps, 467 setBackground, 341, 343 setBorder, 419, 423 setBounds, 321, 322, 325, 468 setCharAt, 88 setColor, 343, 510, 625 setColumns, 408, 410, 413 setComponentPopupMenu, 438 setCursor, 386 setDaemon, 754 setDebugGraphicsOptions, 615 setDefaultButton, 494 setDefaultCloseOperation, 320, 536 setDefaultUncaughtExceptionHandler, 611 setDone, 777 setEditable, 406, 423, 425 setEnabled, 373, 379, 441 setExtendedState, 325, 326 setFileFilter, 497, 504 setFileSelectionMode, 503 setFileView, 499, 504 setFilter, 600, 607 setFirst, 652 setFont, 350, 408 setForeground, 341, 343 setFormatter, 601, 607
Kup książkę
setFrameFromCenter, 337 setFrameFromDiagonal, 336 setHonorsVisibility, 467 setHorizontalGroup, 466 setHorizontalTextPosition, 435 setIcon, 409, 435 setIconImage, 321, 326 setInheritsPopupMenu, 438 setJMenuBar, 432, 434 setLabelTable, 428, 431, 640 setLayout, 399 setLevel, 606, 607 setLineWrap, 411, 413 setLocation, 321, 325 setLocationByPlatform, 322, 326 setLookAndFeel, 368 setMajorTickSpacing, 431 setMinorTickSpacing, 431 setMnemonic, 440 setModel, 424 setMultiSelectionEnabled, 503 setPaint, 340, 341, 343 setPaintLabels, 428, 431 setPaintTicks, 428, 431 setPaintTrack, 432 setParent, 606 setPriority, 753 setRect, 335 setResizable, 321, 326 setRows, 410, 413 setSecond, 638 setSelected, 414, 436 setSelectedFiles, 503 setSize, 325 setSnapToTicks, 432 setSource, 363 setText, 406, 407, 409 setTitle, 321, 326, 537 setToolTip, 446 setToolTipText, 447 setUncaughtExceptionHandler, 754 setUndecorated, 326 setUseParentHandlers, 607 setValue, 701 setVerticalGroup, 466 setVisible, 320, 325, 489, 537, 827 setWrapStyleWord, 413 severe, 605 show, 320, 437 showConfirmDialog, 474, 476, 482 showDialog, 490 showDocument, 531, 548, 549 showInputDialog, 475, 476, 483 showInternalConfirmDialog, 482
Poleć książkę
Skorowidz showInternalInputDialog, 484 showInternalMessageDialog, 482 showMessageDialog, 288, 474, 481, 530 showOptionDialog, 474, 476 showSaveDialog, 495 showStatus, 548, 549 shuffle, 721, 722 shutdown, 803 shutdownNow, 804 signal, 769, 780 signalAll, 766–769 size, 236, 672, 673 sleep, 737, 742 sort, 121, 274, 720 start, 288 startsWith, 84 stateChanged, 426 stop, 288, 752, 784 store, 550, 554, 728 subList, 716 subMap, 712, 716 submit, 803, 809 subSet, 712, 716 substring, 78, 84, 711 subtract, 115, 116 super.clone, 282 super.paintComponent, 330 suspend, 752, 785 swap, 168, 724 swapHelper, 656 SwingUtilities.updateComponentTreeUI, 366 synchronizedCollection, 713, 797 synchronizedList, 797 synchronizedMap, 713, 797 synchronizedSet, 797 synchronizedSortedMap, 797 synchronizedSortedSet, 797 System.exit, 60, 320 System.out.println, 89 System.runFinalizersOnExit, 179 systemNodeForPackage, 560 systemRoot, 560 tailMap, 712, 716 tailSet, 712, 716 take, 793 takeFirst, 793 takeLast, 793 text, 91 Thread.getAllStackTraces, 581 ThreadLocalRandom.current, 781 throwing, 594, 606 toArray, 237, 645, 672, 718 toBack, 326 toFront, 322, 326
Kup książkę
847
toString, 88, 118, 228, 259, 310, 424, 584, 610 toUpperCase, 84 transfer, 756, 761, 770, 793 trim, 85, 407 trimToSize, 235, 236 tryLock, 782, 783 tryTransfer, 793 UIManager.setLookAndFeel, 366 uncaughtException, 754, 755 unlock, 762, 764 unmodifiableCollection, 713 unmodifiableList, 713 unmodifiableSet, 713 update, 240 userNodeForPackage, 560 userRoot, 560 validate, 407, 408 valueOf, 114, 243, 246 wait, 773 warning, 605 windowActivated, 369, 372 windowClosed, 369, 372 windowClosing, 369, 370, 372 windowDeactivated, 369, 372 windowDeiconified, 369, 372 windowIconified, 369, 372 windowOpened, 369, 372 windowStateChanged, 372 writeLock, 784 xor, 730 metody abstrakcyjne, 215 akcesora, 155 fabryczne, 161, 704, 803 finalne, 211, 770 graficzne, 332 interfejsu Action, 373 BlockingDeque<E>, 793 BlockingQueue<E>, 792 Collection, 672 Collection<E>, 672 Deque<E>, 695 Future<V>, 801 GenericArrayType, 664 Iterator<E>, 674 LinkedList<E>, 683 List<E>, 682 ListIterator<E>, 683 Map<K, V>, 700 NavigableSet<E>, 694 ParameterizedType, 664 Queue<E>, 695 SortedSet, 712
Poleć książkę
848
Java. Podstawy
metody interfejsu TypeVariable, 664 WildcardType, 664 WindowListener, 369, 372 klas wewnĊtrznych, 289 klasy AccessibleObject, 261 Applet, 537, 545, 546 Array, 264 Arrays, 123 BigDecimal, 116 BigInteger, 115 BitSet, 730 BorderFactory, 421 Class, 252, 255 Class<T>, 658 Collections, 712, 715, 722, 724 Component, 325 Console, 91 Constructor, 256 Date, 141 Employee, 151 Executors, 803 FileView, 498, 505 Font, 349 Frame, 326 Graphics, 350 Graphics2D, 351 GregorianCalendar, 147 GroupLayout, 466 Integer, 243 JComboBox, 425 JFileChooser, 503 JFrame, 321 JMenu, 433 JOptionPane, 481 JSlider, 431 JTextArea, 412 JTextComponent, 406 LayoutManager, 472 LineMetrics, 350 Logger, 605 Modifier, 256 Object, 773 Preferences, 560 Properties, 553 RectangularShape, 335, 339 Robot, 621 Scanner, 90 String, 83, 87 StringBuilder, 88 Thread, 749–755
Kup książkę
ThreadLocal<T>, 782 Throwable, 583 Timer, 288 Toolkit, 327 Window, 326 kolejek blokujących, 787, 788 komentarze, 191 monitorowe, 775 o zmiennej liczbie parametrów, 244 odradzane, 141 ogólne, 632 pomostowe, 638, 649 prywatne, 157 przeciąĪanie, 171 przesáaniające, 201 publiczne, 59 rejestrujące, 594 rodzime, 160 statyczne, 73, 160, 645 statyczne ze zmiennymi typowymi, 645 sygnatura, 171, 209 synchronizowane, 771 tworzące niemodyfikowalne widoki, 712 udostĊpniające, 141 uogólnione, 671 wstawiane, 154 z parametrami typowymi, 632 zmieniające wartoĞü elementu, 141 mieszanie wspóárzĊdnych, 691 mnemoniki, 438 modalnoĞü, 485 model, 394, 395 pola tekstowego, 394 wskaĨnikowy, 24 moduá áadujący klasy, 588 modyfikacja parametru obiektowego, 167 zbioru EnumSet, 704 modyfikator dostĊpu, 58, 220 dostĊpu private, 186 dostĊpu public, 185 final, 158, 211, 777 volatile, 777 zdarzenia, 386 modyfikowanie elementów zbioru, 687 monitor, 775 motyw Ocean, 316 mutatory, 142 MVC, Model-View-Controller, 392 mysz, 380
Poleć książkę
Skorowidz
N nadklasa, superclass, 200 nadtypy, 652, 654 NaN, 64, 70 narzĊdzia graficzne, 317 wiersza poleceĔ, 44 narzĊdzie appletviewer, 53, 535 ButtonTest, 618 ImageViewer, 51, 500 jar, 512, 514 Jar Bundler, 515 javac, 45 javadoc, 190–195 javap, 294 jconsole, 595, 613, 779 jmap, 614 Matisse, 460, 461 OptionDialogTest, 477 ReflectionTest, 295, 296 Swing graphics debugger, 614 natywna biblioteka interfejsowa, 33 nawiasy klamrowe, 59, 300 kwadratowe, 116 ostre, 632 puste, 234 nazwa akcji, 377 klasy, 45, 58, 134, 197 konstruktora, 137 parametru, 174 pliku, 45 pliku dziennika, 598 rejestratora, 595 zasobu, 516 zmiennej, 67 zmiennej typowej, 630 nazwy klas komponentów Swing, 318 klas proxy, 311 logiczne czcionek, 344 metod, 197 rodziny czcionek, 343 NetBeans, 38, 44, 459 niezaleĪnoĞü od architektury, 26 niezawodnoĞü, 24 niezmienialnoĞü áaĔcuchów, 79 niszczenie obiektów, 179 notacja wielbáądzia, 58
Kup książkę
849
O obiekt, 24, 132 Action, 446 ActionEvent, 357 AssertionError, 587 BasicButtonUI, 398 builder, 86 ButtonGroup, 415 Callable, 803 ColorAction, 360 Comparator, 693 Console, 90 Date, 138 DefaultButtonModel, 398 ExecutorCompletionService, 808 FutureTask, 798 Graphics, 328, 341 GridLayout, 406 Handler, 595, 598, 608 Iterator, 672 JButton, 397 JPanel, 402 JRadioButton, 415 PaintEvent, 388 Path, 97 PrintWriter, 96, 97 Properties, 553 Runnable, 759, 803 Scanner, 96 System.out, 60 WeakReference, 702 obiektów, 133 autoboxing, 241 hermetyzacja, 133 klonowanie, 280 kopiowanie, 280 metody, 133 metody prywatne, 157 niszczenie, 179 polimorfizm, 204 porównywanie, 221 skáadowe, 133, 155 stan, 133, 134 toĪsamoĞü, 134 wáaĞciwoĞci, 133 zachowanie, 133 obiekty blokady, 762 funkcyjne, 690 klasy Class, 249 klasy Lock, 762 klasy ogólnej, 646 nasáuchujące zdarzeĔ, listener objects, 287, 371
Poleć książkę
850
Java. Podstawy
obiekty obsáugujące wywoáanie, 307 opakowujące kolekcje, 711 proxy, 308 typu wyliczeniowego, 548 warunków, 765 zdarzeĔ, event objects, 356 obliczanie kodu mieszającego, 226 obramowanie, 419 obrazy, 351 obsáuga apletów, 533 báĊdów, 564 klikniĊcia przycisku, 357 nieprzechwyconych wyjątków, 754 przycisku OK, 486 ramek, 325 wyjątków, 249, 564, 646 zdarzeĔ, 329, 355 zdarzeĔ AWT, 389, 390 zdarzeĔ myszy, 380, 383 obszar surogatów, surrogates area, 66 tekstowy, text area, 406, 410 ochrona bloku kodu, 762 odczyt plików, 96 odmierzanie czasu, 782 odpakowywanie, 242 odradzane metody, 141 odwoáanie, 193 odwzorowanie nazw czcionek, 345 ograniczenia blokad wewnĊtrznych, 771 nadtypów, 652, 653 typów generycznych, 240 widocznoĞci metody, 219 widoków, 714 zmiennych typowych, 633 okna dialogowe modalne, 474 niemodalne, 474 okno, 369, 372 dialogowe opcji, 474, 483 potwierdzenia, 482 przyjmowania danych, 484 typu O programie, 485 wyboru kolorów, 505 wyboru plików, 495 z komunikatem, 482 z polem hasáa, 489 dokumentacji API, 85 konsoli, 44 przeglądarki apletów, 53 wyboru plików, 498, 558
Kup książkę
OOP, Object Oriented Programming, 132 opakowywanie, autoboxing, 241 opakowywanie wyjątków, 648 opcja Step Into, 623 Step Over, 623 Terminate, 625 opcje debugera, 623 narzĊdzia jar, 513 operacje niepodzielne, 760 opcjonalne, 714 zbiorcze, 717 operator ::, 202 [], 120 ==, 705 dekrementacji, 71 inkrementacji, 71 instanceof, 213, 222, 278 new, 86, 137, 153, 276 przecinka, 77 operatory arytmetyczne, 69 bitowe, 72 logiczne, 71 relacyjne, 71 opis danych, 33 elementu, 692 klasy, 86, 192 metod, 87 struktury stron, 33 zmiennej, 192 optymalizacja, 27 osáona obiektów, 241 ostrzeĪenie, 643 otwieranie menu, 438 overloading resolution, 171 oznaczenia relacji, 136
P pakiet com.horstmann.corejava, 183 com.mycompany.mylib, 588 com.mycompany.util, 518 com.sun.java, 366 domyĞlny, 183 java.awt, 186 java.awt.event, 286, 388 java.lang, 83, 90 java.lang.reflect, 252, 660 java.math, 114
Poleć książkę
Skorowidz java.sql, 181 java.util, 90, 181, 387 java.util.concurrent, 762, 771, 797 java.util.concurrent.atomic, 777 java.util.concurrent.locks, 783 javax.swing, 286, 319 javax.swing.event, 390 JDK, 38 org.omg.CORBA, 243 Swing, 314 pakiety, packages, 180 dodawanie klasy, 182 komentarze, 194 lokalizacyjne, 596 zasiĊg, 185 panel JPanel, 398 przewijany, scroll pane, 411, 413 z przyciskami, 359, 398 para klucz – wartoĞü, 556, 561, 697 parametr, 61 anchor, 452 fill, 452 gridheight, 451, 452 gridwidth, 451, 452 gridx, 451, 452 gridy, 451, 452 parametry jawne, 153 konfiguracyjne obiektu Handler, 598 áaĔcuchowe, 96 metod, 164 niejawne, 153, 174 obiektowe, 167 okreĞlające cel, 549 typowe, 628, 641 wiersza poleceĔ, 120 pasek menu, 432 narzĊdzi, toolbar, 444 pĊtla do-while, 102 for, 98, 106–108 for each, 32, 98, 117, 126 w stylu for each, 669 while, 101, 102 piaskownica, sandbox, 519, 522 pieczĊtowanie pakietów, 186, 518 plik AboutDialog.java, 487 ActionFrame.java, 377 AnonymousInnerClassTest.java, 301 ArrayListTest.java, 238 Ball.java, 739
Kup książkę
BallComponent.java, 740 Bank.class, 761 Bank.java, 758, 767, 772 BigIntegerTest.java, 115 BlockingQueueTest.java, 789 BorderFrame.java, 420 Bounce.java, 737 BounceThread.java, 743 BuggyButtonTest.java, 622 ButtonFrame.java, 360 ButtonPanel.java, 481 Calculator.jnlp, 519 CalculatorFrame.java, 528 CalculatorPanel.java, 403 CalendarTest.java, 144 Chart.java, 543 CheckBoxTest.java, 414 CircleLayout.java, 469 CircleLayoutFrame.java, 472 CloneTest.java, 284 ColorChooserPanel.java, 508 ComboBoxFrame.java, 424 CompoundInterest.java, 125 ConstructorTest.java, 177 CopyOfTest.java, 263 DataExchangeFrame.java, 491 deskryptora, 519 DialogFrame.java, 486 doc-files, 191 DrawTest.java, 337 Employee.java, 151, 184, 205, 231, 275, 284 EmployeeSortTest.java, 275 EmployeeTest.java, 149, 151 en.properties, 596 EnumTest.java, 246 EqualsTest.java, 230 EventTracer.java, 615 FileIconView.java, 503 fontconfig.properties, 345 FontFrame.java, 454, 463 FontTest.java, 347 forkJoinTest.java, 810 FutureTest.java, 799 GBC.java, 456 GenericReflectionTest.java, 661 ImagePreviewer.java, 502 ImageTest.java, 352 ImageViewer.java, 51 ImageViewerFrame.java, 500 InnerClassTest.java, 292 InputTest.java, 89 Item.java, 692 javan.log, 597 javaws.jar, 526
Poleć książkę
851
852
Java. Podstawy
plik jogging.properties, 594 LinkedListTest.java, 681 LoggingImageViewer.java, 602 LotteryArray.java, 128 LotteryDrawing.java, 121 LotteryOdds.java, 108 Manager.java, 206, 232 ManagerTest.java, 204 MANIFEST.MF, 512 manifestu klasa gáówna, 514 sekcja gáówna, 512 wstawianie sekcji, 518 zmienianie zawartoĞci, 513 MapTest.java, 699 MenuFrame.java, 442 MethodTableTest.java, 266 MouseComponent.java, 383 MouseFrame.java, 383 NotHelloWorld.java, 330, 534 ObjectAnalyzerTest.java, 259 OptionDialogFrame.java, 477 overview.html, 194 PackageTest.java, 184 PairTest1.java, 631 PairTest2.java, 634 PairTest3.java, 656 ParamTest.java, 169 PasswordChooser.java, 492 Person.java, 217 PersonTest.java, 217 PlafFrame.java, 367 PreferencesTest.java, 557 PriorityQueueTest.java, 696 program.properties, 551 PropertiesTest.java, 551 ProxyTest.java, 309 RadioButtonFrame.java, 417 ReflectionTest.java, 253 ResourceTest.java, 517 Retirement.java, 103 Retirement2.java, 105 RobotTest.java, 618 rt.jar, 187 SetTest.java, 686 ShuffleTest.java, 721 Sieve.cpp, 731 Sieve.java, 731 SimpleFrameTest.java, 318 SizedFrameTest.java, 324 SliderFrame.java, 428 src.zip, 41, 42 StackTraceTest.java, 582
Kup książkę
StaticInnerClassTest.java, 305 StaticTest.java, 162 Student.java, 218 swing.properties, 366 SwingThreadTest.java, 817 SwingWorkerTest.java, 821 System.java, 43 TalkingClock$TimePrinter.class, 294 TextComponentFrame.java, 411 ThreadPoolTest.java, 804 TimerTest.java, 287 ToolBarTest.java, 446 TransferRunnable.java, 759 TreeSetTest.java, 691 UnsynchBankTest.java, 757 Welcome.java, 45 WelcomeApplet.class, 53 WelcomeApplet.html, 53 WelcomeApplet.java, 55 pliki .class, 514 .exe, 514 .java, 58 .jnlp, 519 audio, 546 cookie, 527 graficzne, 546 JAR, 187, 512, 514 obrazów, 515 podpisane cyfrowo, 523 tekstowe, 515 XML, 600 z danymi binarnymi, 515 zasobów, 516 Ĩródáowe, 151, 189 pobieranie hasáa, 90 wáaĞciwoĞci systemowych, 554 podklasa, subclass, 200 Properties, 726 Stack, 726 podklasa, subclass, 200 podkradanie pracy, 812 podáaĔcuchy, 78 podmenu, 432 podpakiety, 180 podpis cyfrowy, 26, 523 podpisywanie kodu, 523 podtyp typu granicznego, 634 podziaáka, 427 pola finalne, 211 haseá, 406, 410 klasowe, 159
Poleć książkę
Skorowidz niestatyczne, 159 prywatne, 155 publiczne, 155 statyczne, 159, 176 tekstowe, 394, 406 ulotne, 776 weight, 451 wyboru, 413 pole value, 243 polecenie cmd, 41 dir, 46 jcontrol, 536 polimorfizm, 204, 207, 269 poáączenie na poziomie gniazd, 24 poáoĪenie przycisków, 402 porównywanie elementów tablic, 225 áaĔcuchów, 79, 81 obiektów, 221, 689 obiektów osáonowych, 242 w pĊtli, 107 w podklasach, 277 powiadamianie o zdarzeniach, 358 powiązana tablica mieszająca, 703 poziom FINE, 595, 597, 601 rejestracji obiektu Handler, 597 poziomy rejestracji, 595 waĪnoĞci komunikatów, 592 pozycjonowanie bezwzglĊdne, 468 ramki, 321 preferencje uĪytkownika, 549, 555 wĊzáa, 561 priorytet informacji, 592 wątków, 750 wątku, 752, 753 operatorów, 76 procedura obsáugi báĊdów, 565 obsáugi zdarzeĔ, 355 proces, 736 proces inliningu, 212 program, Patrz narzĊdzie programowanie interfejsów graficznych, 391 interfejsu uĪytkownika, 317 obiektowe, 24, 132 ogólne, generic programming, 627 pasków narzĊdzi, 445
Kup książkę
proceduralne, 133 sieciowe, 33 wielowątkowe, 28 programy jednowątkowe, 736 refleksyjne, 247 wielowątkowe, 735 projektant formy, 398 projektowanie klas, 195 prostokąt, 334 protokoáy sieciowe, 24 prywatne pola, 155 przechwytywanie strumienia báĊdów, 611 wielu typów wyjątków, 574 wyjątków, 250, 571, 747 przeciąganie paska narzĊdzi, 445 przeciąĪanie konstruktorów, 172 metod, 171 przedziaá, 712 przeglądarka apletów, 535 HotJava, 31 pamiĊci podrĊcznej, 521 przejmowanie blokady, 774 przekazywanie obiektu, 138 przez wartoĞü, 167 wyjątków, 586 przeáącznik, radio button, 413 przeáączniki, 415 przeáączniki w elementach menu, 436 przenoĞnoĞü, 26, 70 przepáyw sterowania, 98, 111, 298 przerywanie dziaáania pĊtli, 111 procesu áadowania, 737 wątków, 746 przesáanianie metod, 202, 225, 647 przestrzenie numeracyjne, 66 przesuwanie iteratora, 671 przeszukiwanie liniowe, 723 przetwarzanie XML, 33 przycisk, 358, 397 domyĞlny, 490 JButton, 398 OK, 486 poáoĪenie, 402 rozmiar, 402 w rozkáadzie brzegowym, 401 przyciski radiowe, 415 przywileje klasowe, 157
Poleć książkę
853
854
Java. Podstawy
publiczne metody akcesora, 155 mutatora, 155 publiczne pola, 155 pule wątków, 802–804 punkt wstrzymania, 623, 624 pusta mapa wáasnoĞci, 553
R ramka, frame, 318 nadrzĊdna, 485, 490 wyĞwietlająca tekst, 327 ramki pozycjonowanie, 321 rozmiar, 323 warstwy, 327 wáasnoĞci, 322 wyĞwietlanie, 320 reaktywacja wątków, 766 referencja do elementów typu Object, 628 do klasy zewnĊtrznej, 291, 293 do obiektu, 138 do parametru niejawnego, 203 null, 250, 565 refleksja, reflection, 199, 247, 270, 658 analiza funkcjonalnoĞci klasy, 252 obiektów w czasie dziaáania programu, 257 generyczny kod tablicowy, 261 rejestr, 556 rejestr zdarzeĔ, 615 rejestratory, logger, 591, 597 rejestrujący obiekt poĞredni, 610 rekordy dziennika, 597 relacje agregacja, 135 dziedziczenie, 136 zaleĪnoĞü, 135 reorganizacja tablicy mieszającej, 686 repozytorium Preferences, 555 robot, 618 rodzaje ataków, 25 modalnoĞci, 485 obramowaĔ, 419 suwaków, 429 rozkáad brzegowy, 400, 402, 448 ciągáy, 448 GridBagLayout, 448–453 grupowy, 459, 461 komponentów, 407 siatkowy, 402, 448
Kup książkę
sprĊĪynowy, 449 SpringLayout, 449 rozmiar apletu, 537 ekranu, 323 ikon, 522 interpretera, 23 pola tekstowego, 407 przycisków, 402 ramki, 323 tablicy, 117 rozmieszczanie komponentów, 398 rozstrzyganie przeciąĪania, 171, 209 rozszerzanie klasy, 133, 216 klasy Throwable, 646 programów, 211 stylu, 317 rysowanie, 314 figur, 333, 337 na komponencie, 328 obrazu, 354 wykresu, 543 rzutowanie, casting, 75, 212, 637, 644, 718
S sandbox, 519, 522 scalanie list, 681 SDK, Software Development Kit, 38 SE, Standard Edition, 38 semafory, 812 separator, 445 serializacja, 539 serwer pochodzenia, 523 serwer Tomcat, 519, 520 siatka, 450 sito Eratostenesa, 730 skaner, 89 skáad tekstów, 346 skáadanie áaĔcuchów, 86 skáadnia diamentowa, diamond syntax, 234 Javy, 23 klas wewnĊtrznych, 289 wewnĊtrznych klas anonimowych, 371 skáadowe, 133, 155 skáadowe chronione, 220 skróty klawiszowe, 439 sáabe referencje, 702 sáowo kluczowe, 829 abstract, 215 assert, 587 catch, 250 class, 58
Poleć książkę
Skorowidz extends, 200, 634 final, 68, 158, 211, 299 implements, 273, 634 import, 180 instanceof, 213 interface, 272 package, 183, 186 private, 152, 158, 220 protected, 190, 219 public, 58, 152, 220 static, 69, 160, 304 strictfp, 70 super, 202 synchronized, 762, 769, 775 this, 154, 160, 174 throws, 569 try, 250 void, 60 volatile, 776 sáuchacz akcji, 414, 416 przycisku, 359 z Ĩródáami zdarzeĔ, 373 zdarzeĔ, event listener, 356, 364, 388 sortowanie, 275, 299, 720 kluczy, 701 listy elementów, 720 tablicy, 121 specyfikacja, 59 specyfikacja wyjątku, 568 specyfikator dostĊpu, 150 formatu, 92, 96 throws, 283, 569, 573 sprawdzanie parametrów, 589 pól obiektu, 265 typów, 641 typów pól, 257 zakresu, 120 sprzĊĪenie zwrotne, 286 staáa, 68 ACCELERATOR_KEY, 374 ACTION_COMMAND_KEY, 374 BorderLayout.SOUTH, 401 DEFAULT, 374 Double.NaN, 64 Double.NEGATIVE_INFINITY, 64 Double.POSITIVE_INFINITY, 64 LONG_DESCRIPTION, 374 MNEMONIC_KEY, 374 NAME, 374 SHORT_DESCRIPTION, 374 SMALL_ICON, 374
Kup książkę
staáe interfejsu Action, 374 interfejsu SwingConstants, 409 klasowe, 69 klasy BorderLayout, 401 áaĔcuchowe, 80 matematyczne, 73 statyczne, 159 stan obiektu, 133, 134 okna, 372 wątków, 749, 751 standard ECMA-262, 35 IEEE 754, 64 ISO/ANSI, 80 wyraĪania czasu, 139 status przerwania wątku, 746 statyczne funkcje skáadowe, 60 klasy wewnĊtrzne, 303 sterta, heap, 120, 140, 696 STL, Standard Template Library, 666 stopieĔ powiązaĔ miĊdzy klasami, 135 stopy oprocentowania, 126 stos, stack, 120, 729 stos wywoáaĔ, 251, 582 stosowanie blokady, 765 dziedziczenia, 269 refleksji, 270 warunków, 769 wyjątków, 584 struktura katalogów, 43 ramki JFrame, 328 struktury danych, 665 strumieĔ ByteArrayInputStream, 526 ByteArrayOutputStream, 526 InputStream, 526 PrintStream, 526 wejĞciowy, 89 styl GTK, 316 Metal, 315, 366 Nimbus, 317 Synth, 317 style obramowaĔ, 419 projektowania, 196 suwak, slider, 413, 426, 430 suwak z podziaáką, 427 SWT, 317
Poleć książkę
855
856
Java. Podstawy
sygnatura metody, 171, 209 symbole zastĊpcze, 65 symulacja banku, 756, 759, 768 synchronizacja, 756 synchronizatory, 812, 813 synchronizowane wątki, 763 system kolorów, 342 szablon bitset, 729 vector, 235 szerokoĞü kolumny, 407 szkielet rozgaáĊzienie-záączenie, 809, 812
É ĞcieĪka dostĊpu, 39 klas, 187, 189 ĞcieĪki bezwzglĊdne, 97 wzglĊdne, 97 Ğcisáa kontrola typów, 62, 274 Ğledzenie przepáywu wykonywania, 593 stosu, 251, 581, 755 Ğrodowisko dziaáania apletu, 547 Ğrodowisko programistyczne Eclipse, 44, 47 NetBeans, 44
T tabela metod, 210 tablic, 116 inicjowanie, 118 kopiowanie, 119 numerowanie, 116 przeglądanie, 117 sortowanie, 121 tablica accounts, 760 args, 120 arrayToFill, 673 par klucz – wartoĞü, 556 referencji, 628 result, 123 trójkątna, 129 tablice anonimowe, 118 generyczne, 644 kopiowane przy zapisie, 796 mieszające, 226, 428, 684, 703 postrzĊpione, 127
Kup książkę
typów ogólnych, 642 typów wieloznacznych, 642 wielowymiarowe, 124 tasowanie, 720 tasowanie elementów listy, 721 technologia Flash, 29 tekst, 406, 410 terminal, 35 test wydajnoĞci, 730 testowanie apletu, 53 blokad, 782 mechanizmu wáasnoĞci, 551 Tomcat, 519 toĪsamoĞü obiektu, 134 translacja metod ogólnych, 637 poprzez wymazywanie typów, 648 typów ogólnych, 639 wyraĪeĔ generycznych, 637 tryb peánoekranowy, 325 tworzenie akceleratora, 439 apletów, 29, 53 dziennika, 601 egzemplarza klasy, 132 etykiety, 409 klas wyjątków, 570 konstruktorów, 152 listy cyklicznej, 668 listy powiązanej, 668 menu, 432 obiektów, 96, 132, 137, 171 obiektu proxy, 307 obiektu typu Class, 249 obramowaĔ, 421 ogólnych tablic, 643 okien dialogowych, 484 okna komunikatu, 477 osobnego wątku, 741, 745 plików JAR, 512 pól wyboru, 413 przycisku, 358, 362 puli wątków, 802 ramki, 318 robota, 617 sáuchacza akcji, 363 tablic, 129, 203 postrzĊpionych, 128 generycznych, 644 trójkątnych, 129 z kolekcji, 718 widoku mapy, 698
Poleć książkę
Skorowidz typ boolean, 66 byte, 62 char, 65 Date, 92 double, 64 float, 63 graniczny, 634 int, 26, 62 Integer, 243 long, 63 MIME, 519, 520 osáony, 265 parametryzowany, 650 short, 62 short int, 26 surowy, 636, 641, 650 wbudowany, 137 wieloznaczny, 629, 634 wieloznaczny z ograniczeniem nadtypów, 654 wyliczeniowy, 77 zwrotny, 639 typy caákowite, 62 interfejsowe, 667 kolekcji, 675 komunikatów, 475 konwersji, 74 kursorów, 382 listowe, 651 ogólne, 627, 658 parametryzowane, 627 podstawowe, 221 sparametryzowane, generic types, 32 surowe, 234 tablicowe, 221 wieloznaczne, 650, 653 bez ograniczeĔ, 655 mechanizm chwytania, 656 wyliczeniowe, 245, 704 zmiennoprzecinkowe, 63 zwrotne kowariantne, 639
U ukrywanie danych, 133 UML, Unified Modeling Language, 136 Unicode, 65 uruchamianie apletu, 53, 535 aplikacji graficznej, 50 aplikacji Java Web Start, 519, 520 osobnego wątku, 741
Kup książkę
programów w konsoli, 45 programu, 44, 49 uruchomienie kilku wątków, 743 usáugi API, 526 JNLP, 526 ustawianie preferencji, 557 ĞcieĪki klas, 189 usuwanie elementów, 670 elementów z kolekcji, 673 elementu z listy powiązanej, 676 elementu z tablicy, 675 nieuĪytków, garbage collecting, 22, 702 przedziaáu, 712 UTC, Coordinated Universal Time, 139 UTF-16, 66 utrata wyjątku, 579
V varargs, 244
W warstwa implementacji, 666 interfejsów, 666 ramki, 327 wartoĞci graniczne przedziaáu, 712 zwrotne okna potwierdzenia, 476 wartoĞü NaN, 64, 70 null, 77, 81, 139, 172 skrótu, hash value, 227 warunek wstĊpny, 590 warunki, 765, 769 wątek, thread, 735, 815 dystrybucji zdarzeĔ, 319, 741, 785, 819, 828 roboczy, 824 sterowania, thread of control, 735 TransferRunnable, 785 wyliczeniowy, 791 zablokowany, 747 zamkniĊty, 747 wątki koĔczenie dziaáania, 746 oczekujące, 766 niesynchronizowane, 763 priorytet, 752 stan
Poleć książkę
857
858
Java. Podstawy
wątki stan BLOCKED, 749 NEW, 749 RUNNABLE, 749 TERMINATED, 749 TIMED WAITING, 749 WAITING, 749 synchronizowane, 763 usuniĊte z kolejki, 766 wywáaszczanie, 760 zamienianie w demona, 753 zamkniĊcie, 752 wczytywanie zasobów, 516 wejĞcie, 89 wejĞcie System.in, 96 wersje Javy, 32 wĊzeá, 556, 560 wiązanie dynamiczne, 204, 209–211 statyczne, 209 widocznoĞü metod, 211 widok, view, 394, 710 kolekcji, 715 listowy elementów, 716 mapy, 698 podprzedziaáu, 717 pola tekstowego, 394 widoki kontrolowane, 714 niemodyfikowalne, 712 przedziaáowe, 711 synchronizowane, 713 wielkie liczby, 114 wielkoĞü liter, 58 wielowątkowoĞü, 28, 33, 735 wielozadaniowoĞü, 735 wiersz poleceĔ, 44, 120 wizualne budowanie interfejsów, 51 wáasne typy wyjątków, 571 wáasnoĞci czcionki, 450, 454 interfejsów, 276 interfejsu ButtonModel, 397 klas proxy, 311 metody equals, 222 monitorów, 775 ramek, 322, 551 wątków, 752 wáasnoĞü, property, 322 wáaĞciwoĞci list, 721 systemowe, 554
Kup książkę
wáączanie asercji, 588 zegara, 293 wnioskowanie o typie, 632 wprowadzanie tekstu, 406 wskaĨniki, 25 do funkcji, 286 do metod, 264 do obiektów, 140 wspóáczynnik zapeánienia tablicy, 686 wspóárzĊdne figur, 333–336 kodowe znaków, 66, 81 siatki, 451 wstawianie komentarzy, 190 wybór kolorów, 505 plików, 495 wyciszanie wyjątków, 586 wydajnoĞü, 27 wydáuĪenie dolne, 346 górne, 346 wyjątek ArrayIndexOutOfBounds, 117 ArrayIndexOutOfBoundsException, 566, 816 ArrayStoreException, 642, 650 BadCastException, 658 Class.forName, 250 ClassCastException, 213, 262, 650, 714 CloneNotSupportedException, 283 ConcurrentModificationException, 679, 797 EmptyStackException, 584, 586 FileNotFoundException, 97, 528, 569, 648 IllegalAccessException, 257 IllegalMonitorStateException, 773 IllegalStateException, 670, 674, 683 InterruptedException, 737, 742, 748 IOException, 569, 572 NoSuchElementException, 674, 695 NullPointerException, 566, 586, 590 RuntimeException, 565, 566 ServletException, 575 ThreadDeath, 785 typu RuntimeException, 583 UnavailableServiceException, 526 UnsupportedOperationException, 711–715 wyjątki kontrolowane, 249, 567, 646 konwersji, 629 niekontrolowane, 250, 567, 647 typu IOException, 569 typu SQLException, 576 zabezpieczeĔ, 554 wykonawcze, 565
Poleć książkę
Skorowidz wyjątków, 563 deklarowanie, 567 powtórne generowanie, 575 przechwytywanie, 250, 571 przechwytywanie wielu typów, 574 przekazywanie, 586 wáasne typy, 571 zgáaszanie, 569 wyjĞcie, 89 wyjĞcie System.out, 96 wykres, 543 wykres sáupkowy, 542 wyliczenia, 727 wyáączanie asercji, 588 dziedziczenia, 211 sprawdzania wyjątków, 646 wymazywanie typów, 637–648 wymiana danych, 489 wymuszanie rysowania, 329 wypeánianie figur, 340 wyraĪenia generyczne, 637 wyrównywanie etykiet i pól, 462 WYSIWYG, 395 wysyáanie rekordów, 597 zdarzeĔ, 319 wyszukiwanie binarne, 722 wyĞcig, 756, 760 wyĞwietlanie elementów w przeglądarce, 548 informacji, 327 komponentów, 614 obrazów, 52, 351 ramki, 320 rekordów dziennika, 604 tekstu, 327, 329 zasobu, 515 wywáaszczanie wątku, 750, 760 wywoáanie dowolnych metod, 264 innego konstruktora, 174 przez nazwĊ, 165 przez referencjĊ, 164 przez wartoĞü, 164 setFirst(null), 655 wzorce nazw plików dziennika, 599 projektowe, 392 wzorzec Composite, 393 Decorator, 393 MVC, 392–396 Strategy, 393
Kup książkę
859
X XML, 33
Z zachowanie obiektu, 133 zagnieĪdĪanie bloków instrukcji, 98 pĊtli, 113 zakleszczenie, deadlock, 766, 778 zaleĪnoĞü, 135 zamiana parametrów obiektowych, 168 zamykanie aplikacji, 320 ramki, 320 wątków, 752 zapeánianie tablicy, 237 zapis báĊdów w pliku, 611 danych w repozytorium, 556 do dziennika, 592–594 plików, 96 preferencji uĪytkownika, 549 zarządca rozkáadu, layout manager, 391, 400, 448 CircleLayout, 469 brzegowego, 400 ciągáego, 398 FlowLayout, 402 grupowego, 449 niestandardowy, 469 siatkowego, 402 zasada jednego wątku, 816, 827 uczciwoĞci, 764 zamienialnoĞci, 207 zasiĊg blokowy, 98 pakietów, 185 zmiennych, 98 zasoby, resources, 515 zastosowanie asercji, 589, 590 klas abstrakcyjnych, 279 klas wewnĊtrznych, 294 kolejek priorytetowych, 696 parametrów Class<T>, 659 refleksji, 252 typów wyliczeniowych, 246 zawartoĞü pól danych, 257 zawijanie wierszy, 411 zbiór, set, 686, 697 HashSet, 684 TreeSet, 688–691 uporządkowany, 688
Poleć książkę
860
Java. Podstawy
zdarzenia, 355, 389 interfejs nasáuchu, 356 myszy, 380, 438 niskiego poziomu, 388 okna, 370 semantyczne, 388 sáuchacz, 356 Ĩródáo, 356 zdarzenie, 287 FocusEvent, 388 KeyEvent, 388 MouseEvent, 388 MouseWheelEvent, 388 WindowEvent, 369, 388 zdjĊcie blokady, 766 zegar, 286, 293 zezwolenie, permit, 812 zgáaszanie wyjątków, 569 zintegrowane Ğrodowisko programistyczne, IDE, 39, 47 zmiana koloru, 374 koloru táa, 507 rozmiaru tablicy, 117 stanu okna, 372, 388 stylu, 366, 368 typu wyjątków, 647 wáasnoĞci czcionek, 454 zmienna, 66 zmienna Ğrodowiskowa CLASSPATH, 46, 189 Path, 40, 41 zmienne atomowe, 777 finalne, 299, 777 finalne puste, 299 interfejsowe, 277 lokalne, 153 lokalne wątków, 781 obiektowe, 137–140, 216 parametryczne, 174 polimorficzne, 207 statyczne, 159 tablicowe, 116, 119 typowe, 630, 633, 643, 645 warunkowe, 765
znacznik @author, 192 @deprecated, 193 @link, 194 @Override, 225 @param, 192 @see, 193 @since, 193 @version, 192 append, 599 applet, 54, 537 object, 540 param, 541, 542 znaczniki dokumentacyjne, 190 polecenia printf, 93 znak $, 67 /, 516, 560 ampersand, 634 konwersji, 92 koĔca pliku, 565 koĔca wiersza, 514 powrotu karetki, 60 równoĞci, 68 trzykropka, 244 znaki dodatkowe, 66 echa, 410 konwersji Date i Time, 94, 95 konwersji polecenia printf, 93 nowego wiersza, 477 specjalne, 65 zniszczenie danych, 757 zoptymalizowane wywoáywanie metod, 212 zwalnianie blokady, 764 zwracanie referencji, 157
Î Ĩródáa zdarzeĔ biblioteki AWT, 389 Ĩródáo zdarzeĔ, event sources, 356, 389
Ð Īądanie zamkniĊcia wątku, 746, 747
Kup książkę
Poleć książkę