Laboratorium 3
Interfejsy w Javie na przykładzie listenerów i kolekcji.
Interface
Obiekty wchodzą w interakcje między sobą przy pomocy swoich metod. Innymi słowy, zbiór metod należących do obiektu definiuje jego interfejs, przy pomocy którego obiekt wchodzi w interakcję z otoczeniem. W języku Java interface to zestaw metod bez ich implementacji (bez kodu definiującego zachowanie metody). Właściwa implementacja metod danego interfejsu znajduje się w klasie implementującej dany interfejs. Składnia interfejsu jest następująca:
specyfikator_dostępu interface nazwa_interfejsu { deklaracje stałych i metod... }
Różnica między klasami a interfejsami polega na tym, że klasy zawierają zmienne i stałe oraz deklaracje metod i ich implementacje, a interfejsy mogą zawierać tylko stałe i deklaracje metod - bez implementacji. Metody zadeklarowane bez implementacji nazywa się metodami abstrakcyjnymi. Innymi słowy, klasy definiują co i jak, podczas gdy interfejsy definiują tylko co mogą robić obiekty.
Przykład 1. Prosty interfejs
Podczas Laboratorium 1 jednym z zadań było stworzenie klasy Auto
. Auto jest bez wątpienia pojazdem, tak samo jak rower, motor, samolot, statek itp. Wszystkie pojazdy mają pewne wspólne cechy, które można przedstawić jako wspólne metody.
W projekcie pojava
utwórz paczkę lab3
, a następnie wewnątrz paczki lab3
stwórz interfejs Pojazd
posiadający metody start()
, stop()
, ustawPredkosc(double[] v)
:
public interface Pojazd { public void start(); public void stop(); public void ustawPredkosc(double[] v); }
Następnie wewnątrz paczki lab3
stwórz klasę Auto
, która będzie implementować interfejs Pojazd
. Wewnątrz klasy Auto
zadeklaruj zmienną predkosc
będącą tablicą typu double i zainicjuj ją w konstruktorze tablicą o rozmiarze 3. Zdefiniuj metodę ustawPredkosc(double[] v)
tak aby przypisywała wartości wektora prędkości z argumentu metody do zmiennej predkosc
.
public class Auto implements Pojazd { double[] predkosc; public Auto() { predkosc = new double[3]; } @Override public void start() { // TODO Auto-generated method stub } @Override public void stop() { // TODO Auto-generated method stub } @Override public void ustawPredkosc(double[] v) { if(v.length>=3) { predkosc[0] = v[0]; predkosc[1] = v[1]; predkosc[2] = v[2]; } } }
Garść informacji na temat interfejsów:
- wszystkie metody interfejsu są domyślnie publiczne i abstrakcyjne,
- wszystkie pola interfejsu są domyślnie publiczne, statyczne i finalne (zmienna lub metoda statyczna to taka, do której można się odwołać bez deklaracji obiektu, natomiast zmienna finalna to taka, której można tylko raz przypisać wartość, co z reguły ma miejsce podczas jej deklaracji),
- interfejs może rozszerzać (extends) tylko interfejsy (nawet kilka, co w przypadku klas jest zabronione),
- metody intefejsu nie mogą być zadeklarowane jako statyczne,
- interfejsy mogą być wykorzystywane polimorficznie, tzn. można ich używać jako typu ogólniejszego klas, które go implementują, np:
Pojazd auto = new Auto(); Pojazd rower = new Rower();
Metody domyślne
Istnieje możliwość zdefiniowania tak zwanych metod domyślnych (od Javy 8). Metody te mogą mieć właściwą implementację w ciele interfejsu i są one poprzedzone słowe kluczowym default:
public interface Pojazd { public void start(); public void stop(); public void ustawPredkosc(double[] v); default String nazwa() { return "Pojazd"; } }
Zadanie A - Pola i obwody figur. (1 pkt)
W projekcie pojava
stwórz paczkę lab3
, a następnie wewnątrz tej paczki stwórz interfejs o nazwie Figura
, zawierający metody obliczObwod()
i obliczPole()
oraz stałą PI
, równą wartości liczby π z dokładnością do 10 miejsc po przecinku. Następnie stwórz klasy Kolo
i Trojkat
implementujące interfejs Figura
i zawierające definicje metod obliczObwod()
i obliczPole()
. Klasa Kolo
powinna zawierać zmienną promien
i konstruktor Kolo(double promien)
. Klasa Trojkat
powinna zawierac zmienne dlugoscBoku1
, dlugoscBoku2
, dlugoscBoku3
i konstruktor Trojkat(double dlugoscBoku1, double dlugoscBoku2, double dlugoscBoku3)
. Stwórz klasę ZadanieA
, zawierającą metodę main()
, w której przetestujesz klasy Kolo
i Trojkat
.
Listener
Podczas Laboratorium 2 wprowadzone zostały obiekty nasłuchujące zdarzeń. Listenery są przykładem interfejsów, a ich celem jest reagowanie na różne akcje podejmowane przez użytkownika programu, np. kliknięcie w przycisk, zaznaczenie check boxu, wpisanie wartości w pole tekstowe itp. Istnieje kilka sposobów na dodanie listenera do komponentu. Użycie klasy anonimowej zostało przedstawione podczas Laboratorium 2. Co warto wiedzieć o klasie anonimowej:
- ma dostęp do atrybutów klasy zewnętrznej (tej w której ją zdefniowano),
- nie może definiować własnego konstruktora, a jeśli implementuje ona interfejs to tylko używając konstruktora nie przyjmującego argumentów,
- ma ograniczony dostęp do zmiennych w bloku, w którym powstała (ma dostęp tylko do zmiennych final oraz effective final, czyli takich których wartość nie zmienia się po ich utworzeniu),
- wewnątrz klasy anonimowej możliwe jest jawne odwołanie do instancji
this
tej klasy, jak i instancjithis
klasy zewnętrznej poprzez operatorNazwaKlasyZewnętrznej.this
.
Drugim sposobem na implementację listenera jest użycie klasy wewnętrznej. Polega on na zdefiniowaniu klasy implementującej listener wewnątrz innej klasy, np. klasy rozszerzającej JFrame
. Sytuację tę prezentuje poniższy przykład:
Przykład 2. Implementacja listenera w klasie wewnętrznej
Stwórz nową klasę InnerClassListenerFrame
dziedziczącą po JFrame
i posiadajacą metodę main()
. W konstruktorze tej klasy dodaj do okna suwak JSlider
i etykietę JLabel
. Wewnątrz klasy InnerClassListenerFrame
zdefiniuj nową klasę SliderChangeListener
implementującą interfejs ChangeListener
. Napisz dla niej odpowiedni konstruktor i nadpisz metodę stateChanged(ChangeEvent arg0)
.
public class InnerClassListenerFrame extends JFrame { // Pola klasy InnerClassListenerFrame static final int SLIDER_MIN = -100; static final int SLIDER_MAX = 100; static final int SLIDER_INIT = 0; JSlider slider; JLabel label; // Konstruktor klasy InnerClassListenerFrame public InnerClassListenerFrame() throws HeadlessException { this.setDefaultCloseOperation(DISPOSE_ON_CLOSE); this.setSize(600,50); slider = new JSlider(JSlider.HORIZONTAL, SLIDER_MIN, SLIDER_MAX, SLIDER_INIT); this.add(slider, BorderLayout.PAGE_START); label = new JLabel(String.format("%d", slider.getValue())); this.add(label); slider.addChangeListener(new SliderChangeListener()); } // Klasa wewnętrzna SliderChangeListener implementująca ChangeListener public class SliderChangeListener implements ChangeListener{ @Override public void stateChanged(ChangeEvent arg0) { String value = String.format("%d", slider.getValue()); label.setText(value); } } public static void main(String[] args) { InnerClassListenerFrame frame = new InnerClassListenerFrame(); frame.setVisible(true); } }
W powyższym przykładzie wartość ustawiona na suwaku wyświetla się na panelu. Do nasłuchiwania wydarzeń na suwaku służy ChangeListener
. Klasa SliderChangeListener
, która implementuje ChangeListener
jest zdefiniowana wewnątrz klasy zewnętrznej InnerClassListenerFrame
. Podobnie jak w przypadku klasy anonimowej, klasa wewnętrzna ma dostęp pól z klasy zewnętrznej. Możliwe jest stworzenie instancji klasy wewnętrznej poza klasą zewnętrzną (na przykład w funkcji main()
) w następujący sposób:
InnerClassListenerFrame frame = new InnerClassListenerFrame(); SliderChangeListener listener = frame.new SliderChangeListener();
Innym powszechnym sposobem na implementację listenera jest stworzenie do tego osobnej klasy zewnętrznej. Należy wtedy zadbać o odpowiednie przekazanie do listenera wskaźników na komponenty, które mają być modyfikowane w metodzie listenera. Najlepiej zrobić to poprzez konstruktor klasy implementującej listener, tak jak w poniższym przykładzie.
Przykład 3. Implementacja listenera w klasie zewnętrznej
Stwórz nową klasę OuterClassListenerFrame
, dziedziczącą po JFrame
i posiadajacą metodę main()
. W konstruktorze tej klasy dodaj do okna rozwijaną listę (JComboBox
) z trzema kolorami tła do wyboru (np. czerwony, zielony, niebieski). Początkowy kolor tła powinien być zgodny z pierwszą pozycją na liście kolorów.
public class OuterClassListenerFrame extends JFrame { public OuterClassListenerFrame() throws HeadlessException { this.setDefaultCloseOperation(DISPOSE_ON_CLOSE); this.setSize(300,100); String[] colors = {"red", "green", "blue"}; JComboBox<String> colorList = new JComboBox<String>(colors); this.add(colorList, BorderLayout.PAGE_START); this.getContentPane().setBackground(Color.red); } public static void main(String[] args) { OuterClassListenerFrame frame = new OuterClassListenerFrame(); frame.setVisible(true); } }
W powyższym przykładzie po raz pierwszy pojawia się nietypowa deklaracja zmiennej wg. schematu KlasaZmiennej<InnaKlasa> nazwa_zmiennej
, w tym konkretnym przypadku JComboBox<String> colorList
. Szczegółowe wyjaśnienie tej składni będzie tematem trzeciej, ostatniej części tego laboratorium. Tutaj oznacza to tyle, że obiekty znajdujące się na rozwijanej liście będą klasy String
.
Aby obsłużyć akcje generowane na obiekcie klasy JComboBox
potrzebny jest ItemListener
(lub ActionListener
), dlatego stwórz nową klasę o nazwie ComboBoxItemListener
implementującą ItemListener
. Jedynym polem tej klasy powinien być obiekt klasy JPanel
(lub ewentualnie Container
), którego tło będziemy zmieniać wewnątrz metody itemStateChanged(ItemEvent arg0)
. Przekazanie wskaźnika na panel do wewnątrz klasy ComboBoxItemListener
powinno się odbywać za pośrednictwem konstruktora tej klasy. Obiekt klasy JComboBox
przy każdym kliknięciu na wybraną pozycję z rozwijanej listy generuje dwa wydarzenia ItemEvent
: jedno związane z wyborem nowej pozycji (ItemEvent.SELECTED
), a drugie z "odkliknięciem" poprzedniej pozycji (ItemEvent.DESELECTED
) i dlatego wewnątrz metody itemStateChanged(ItemEvent arg0)
należy sprawdzać jakiego rodzaju wydarzenie nastąpiło.
public class ComboBoxItemListener implements ItemListener { JPanel panel; public ComboBoxItemListener(JPanel panel) { this.panel = panel; } @Override public void itemStateChanged(ItemEvent arg0) { if(arg0.getStateChange()==ItemEvent.SELECTED) { String color = (String)arg0.getItem(); switch(color) { case "red": panel.setBackground(Color.red); break; case "green": panel.setBackground(Color.green); break; case "blue": panel.setBackground(Color.blue); break; } } } }
W powyższym przykładzie, po sprawdzeniu czy została wybrana nowa pozycja z listy następuje przypisanie tej pozycji do zmiennej color
. Warto zwrócić uwagę na sposób w jaki rzutowana jest zmienna klasy Object
, którą zwraca metoda getItem()
na zmienną klasy String
. Kiedy klasa ComboBoxItemListener
jest gotowa, należy dodać listener do obiektu JComboBox
w konstruktorze klasy OuterClassListenerFrame
:
colorList.addItemListener(new ComboBoxItemListener((JPanel)this.getContentPane()));
W powyższej linijce warto zwrócić uwagę na konieczność rzutowania obiektu typu Container
zwracanego przez metodę getContentPane()
na klasę JPanel
. Jest to spowodowane tym, że napisany powyżej konstruktor klasy ComboBoxItemListener
oczekuje jako parametru obiektu klasy JPanel
.
Przedstawione powyżej metody implementacji listenera wykorzystujące klasy anonimową, wewnętrzną i zewnętrzną mają tę wspólną cechę, że zakładają konieczność zdefiniowania osobnej klasy do nasłuchiwania komponentu. W praktyce nie zawsze jest to konieczne, gdyż można również pozwolić, aby to okno główne programu implementowało listener.
Przykład 4. Implementacja listenera w oknie głównym programu
Stwórz nową klasę RadioButtonsFrame
, dziedziczącą po JFrame
, posiadajacą metodę main()
i implementującą interfejs ActionListener
. W konstruktorze tej klasy dodaj do okna trzy przyciski JRadioButton
z trzema kolorami tła do wyboru (np. czerwony, zielony, niebieski). Początkowy kolor tła powinien być zgodny z domyślnie wciśniętym przyciskiem. Nadpisz metodę actionPerformed(ActionEvent arg0)
w ten sposób, aby w zależności od wciśniętego przycisku zmieniało się tło okna.
public class RadioButtonsFrame extends JFrame implements ActionListener { static final String[] COLOR_NAMES = {"red", "green", "blue"}; static final Color[] COLORS = {Color.red, Color.green, Color.blue}; static final Color INIT_COLOR = COLORS[0]; JRadioButton radioButton1; JRadioButton radioButton2; JRadioButton radioButton3; public RadioButtonsFrame() throws HeadlessException { this.setDefaultCloseOperation(DISPOSE_ON_CLOSE); this.setSize(300,100); this.getContentPane().setBackground(INIT_COLOR); this.setLayout(new FlowLayout()); radioButton1 = new JRadioButton(COLOR_NAMES[0]); radioButton1.setActionCommand("0"); radioButton1.setBackground(INIT_COLOR); radioButton1.addActionListener(this); radioButton1.setSelected(true); this.add(radioButton1); radioButton2 = new JRadioButton(COLOR_NAMES[1]); radioButton2.setActionCommand("1"); radioButton2.setBackground(INIT_COLOR); radioButton2.addActionListener(this); this.add(radioButton2); radioButton3 = new JRadioButton(COLOR_NAMES[2]); radioButton3.setActionCommand("2"); radioButton3.setBackground(INIT_COLOR); radioButton3.addActionListener(this); this.add(radioButton3); ButtonGroup group = new ButtonGroup(); group.add(radioButton1); group.add(radioButton2); group.add(radioButton3); } @Override public void actionPerformed(ActionEvent arg0) { Color newColor; int colorNumber = Integer.parseInt(arg0.getActionCommand()); this.getContentPane().setBackground(COLORS[colorNumber]); radioButton1.setBackground(COLORS[colorNumber]); radioButton2.setBackground(COLORS[colorNumber]); radioButton3.setBackground(COLORS[colorNumber]); } public static void main(String[] args) { RadioButtonsFrame frame = new RadioButtonsFrame(); frame.setVisible(true); } }
W Przykładzie 4 nowością jest metoda setActionCommand()
. Przy jej pomocy możemy nadać każdemu komponentowi unikalny identyfikator, który później, w metodzie actionPerformed()
jest wykorzystywany do rozpoznania, który komponent jest źródłem wydarzenia. Kolor tła okna i wszystkich przycisków jest zmieniany w zależności od tego jaki identyfikator jest zwracany przez metodę getActionCommand()
.
Zadanie B - Okno z wieloma komponentami. (3 pkt)
Do paczki lab3
dodaj nową klasę o nazwie MultiListenerFrame
, która dziedziczy po JFrame
, posiada metodę main()
i implementuje interfejs ActionListener
. Wewnątrz okna powinno znajdować się 5 paneli (górny, dolny, lewy, prawy i środkowy). W panelu górny należy umieścić JSlider
, w dolnym JButton
, w lewym trzy przyciski klasy JRadioButton
a w prawym pole tekstowe JTextField
. Wygląd okna i działanie komponentów zostało zaprezentowane na filmie poniżej. Dodaj obsługę zdarzeń do JSlider'a (napisz do tego klasę implementującą odpowiedni listener wewnątrz klasy MultiListenerFrame
), JRadioButton'ów (wykorzystaj metodę actionPerformed()
w klasie MultiListenerFrame
) oraz dolnego przycisku (napisz klasę anonimową, do wyboru koloru użyj klasy JColorChooser
).
Collection
Bardzo ważną rolę w języku Java pełnią kolekcje. Najogólniej można powiedzieć, że kolekcje służą do przechowywania obiektów. Ich przewaga nad zwykłymi tablicami zaczyna się od tego, że kolekcja w przeciwieństwie do tablicy może być rozszerzana w miarę dodawania kolejnych elementów, czyli nie trzeba znać z góry rozmiaru przechowywanych danych. Istnieje kilka rodzajów kolekcji i wszystkie one są interfejsami. Hierarchia tych interfejsów jest przedstawiona poniżej:
Zanim zapoznamy się lepiej z wybranymi interfejsami (List
i Map
), należy jeszcze wyjaśnić czym są typy generyczne, gdyż właśnie takimi typami są kolekcje.
Typy generyczne
Odpowiednikiem szablonów z C++ są tzw. typy generyczne w Javie, jednak pomiędzy tymi dwoma istnieją duże różnice. Szablony C++ generują nowe klasy, po jednej dla każdego typu parametrów szablonu, natomiast w Javie w bytekodzie istnieje tylko jedna klasa (interfejs) generyczna, która za parametry szablonu podstawia klasę Object
, a kompilator podczas kompilacji dokonuje odpowiednich rzutowań. Przykładowo, interfejs List<E>
wygląda następująco:
public interface List<E> extends Collection<E> { E get(int index); E set(int index, E element); boolean add(E element); void add(int index, E element); E remove(int index); int indexOf(Object o); int lastIndexOf(Object o); List<E> subList(int from, int to); }
Litera E w definicji interfejsu oznacza, że jest on typem generycznym i podczas deklaracji i inicjalizacji obiektu takiego typu należy podać konkretną klasę w miejsce litery E. Ponieważ typ List<E>
jest interfejsem, przy jego inicjalizacji należy podać konkretną klasę implementującą ten interfejs:
List<String> stringList = new ArrayList<String>(); List<Integer> integerList = new LinkedList<Integer>(); List<JButton> buttonList = new ArrayList<JButton();
W powyższym przykładzie są zaprezentowane dwie klasy implementujące interfejs List<E>
. Są nimi ArrayList<E>
oraz LinkedList<E>
. Choć pozornie obie klasy służą do przechowywania elementów, to przeznaczone są do różnych celów. KlasaArrayList<E>
została zoptymalizowana do szybkiego wyszukiwania (dostępu) elementów z różnych pozycji listy. Jeśli algorytm ma "skakać" po liście odczytując lub modyfikując elementy z listy, to ArrayList<E>
będzie najlepszym wyborem. Z drugiej strony jeśli w trakcie wykonywania algorytmu będą często usuwane elementy ze środka listy, to ArrayList<E>
będzie mocno spowalniał program i wtedy właściwszym wyborem jest LinkedList<E>
, który jest zoptymalizowany pod kątem usuwania elementów z listy.
Uwaga: Dobrą praktyką jest deklarowanie zmiennych typu interfejs, a nie klasy implementującej ten interfejs. Dzięki temu do takiej zmiennej można przypisać obiekt dowolnej klasy implementującej dany interfejs.
Przykład 5. Działania na listach
Poniższy przykład prezentuje w jaki sposób deklarować i inicjalizować listy, dodawać, nadpisywać i usuwać elementy a także przedstawione są sposoby iterowania po listach. Dodatkowo zaprezentowane jest szybkie sortowanie przy pomocy klasy Collections
.
public class Example5 { public static void main(String[] args) { Random rand = new Random(); List<Double> wzrost = new ArrayList<Double>(); int n = 30; // Dodawanie do listy kolejnych liczb z rokładu normalnego for(int i=0; i<n; i++) wzrost.add(177.4+5*rand.nextGaussian()); // Sortowanie listy - uwaga, ta metoda modyfikuję listę Collections.sort(wzrost); // Iteracja po liście i wypisanie elementów na ekran for(Double w : wzrost) System.out.printf("%.1f cm\n",w); // Deklaracja i inicjalizacji listy list List<ArrayList<Integer>> tabliczka = new ArrayList<ArrayList<Integer>>(); int m = 10; for(int i=0; i<m; i++){ tabliczka.add(new ArrayList<Integer>()); // Dodawanie kolejnych, nowych list integerów do listy for(int j=0; j<m; j++) tabliczka.get(i).add((i+1)*(j+1)); // Wypełnianie listy integerów iloczynami } // Iteracja po liście list i wypisanie wszystkich elementów w m wierszach System.out.println(); for(ArrayList<Integer> list : tabliczka) { for(Integer cell : list) System.out.printf("%3d ", cell); System.out.println(); } List<String> zakupy = new LinkedList<String>(); zakupy.add("pieczywo"); zakupy.add("mleko 3.2%"); zakupy.add("ser zolty"); zakupy.add("jajka"); zakupy.add("chipsy"); zakupy.add("pomidory"); zakupy.add("papryka czerwona"); System.out.println(); for(String item : zakupy) System.out.println(item); // Nadpisywanie elementów listy metodą set() zakupy.set(1, "mleko 1.2%"); zakupy.set(2, "ser bialy"); zakupy.set(6, "papryka zielona"); zakupy.remove(4); // Usunięcie czwartego elementu listy System.out.println(); for(String item : zakupy) System.out.println(item); } }
Mapy
Osobnym typem kolekcji jest mapa, która przechowuje zbiór par (klucz,wartość). Klucze muszą być unikalne i niemodyfikowalne (dobrymi kluczami są obiekty klas String
i Integer
). Jeśli wewnątrz mapy istnieje para (klucz, wartość1), a następnie dodana jest para (klucz, wartość2), to nowa para nadpisze poprzednią parę. Mapa, podobnie jak lista, jest interfejsem generycznym. Wymaga ona jednak podania dwóch klas, jednej dla kluczy a drugiej dla wartości:
Map<Integer, String> integerStringMap = new HashMap<Integer, String>(); Map<String, String> stringStringMap = new HashMap<String, String>>();
HashMap<E,E>
jest standardową implementacją interfejsu Map<E,E>
. Mapy są zoptymalizowane pod kątem szybkiego dostępu do wartości bez względu na rozmiar danych.
Przykład 6. Działania na mapach
Poniższy przykład prezentuje w jaki sposób deklarować i inicjalizować mapy, dodawać, nadpisywać i usuwać elementy a także przedstawione są sposoby iterowania po mapach.
public class Example6 { public static void main(String[] args) { Random rand = new Random(); List<String> imie = new ArrayList<String>(); imie.add("Zuzia"); imie.add("Kuba"); imie.add("Misia"); imie.add("Wojtek"); imie.add("Marta"); imie.add("Bartek"); imie.add("Asia"); imie.add("Krzysiek"); List<Integer> wiek = new ArrayList<Integer>(); for(int i=0; i<imie.size(); i++) wiek.add(5+rand.nextInt(5)); // Deklaracja i inicjalizacja mapy Map<String,Integer> dzieci = new HashMap<String, Integer>(); // Dodanie par (klucz, wartość) do mapy w pętli for for(int i=0; i<imie.size(); i++) dzieci.put(imie.get(i), wiek.get(i)); // Odczytywanie wartości z mapy System.out.printf("Ile lat ma Zuzia? Zuzia ma %d lat.\n", dzieci.get("Zuzia")); // Nadpisywanie pary (klucz,wartość) dzieci.put("Zuzia", dzieci.get("Zuzia")+1); System.out.printf("Za rok Zuzia bedzie miec %d lat.\n", dzieci.get("Zuzia")); // Iteracja po zbiorze kluczy System.out.println(); for(String key : dzieci.keySet()) System.out.println(key); // Iteracja po zbiorze wartości System.out.println(); for(Integer value : dzieci.values()) System.out.println(value); // Iteracja po parach (klucz, wartość) System.out.println(); for(Map.Entry<String,Integer> entry : dzieci.entrySet()) { System.out.printf("%s ma %d lat\n", entry.getKey(), entry.getValue()); } // Usuwanie elementów z mapy dzieci.remove("Krzysiek"); // Usuwa klucz "Krzysiek" razem z jego wartością dzieci.remove("Misia", 10); // Usuwa klucz "Misia" pod warunkiem, że jest stowarzyszony z wartością 10 // Iteracja po parach (klucz, wartość) z użyciem obiektu Iterator System.out.println(); Iterator it = dzieci.entrySet().iterator(); while(it.hasNext()) { Map.Entry<String, Integer> entry = (Map.Entry)it.next(); System.out.println(entry.getKey() + " = " + entry.getValue()); it.remove(); // Obiekt iterator pozwala na usuwanie par w trakcie iteracji } System.out.printf("\nRozmiar mapy wynosi %d.", dzieci.size()); // Sprawdzenie liczby par wewnątrz mapy } }
Zadanie C - Program do liczenia mediany. (1 pkt)
W paczce lab3
stwórz klasę MedianFrame
, dziedziczącą po JFrame
. Polami tej klasy powinna być lista przechowująca liczby rzeczywiste, pole tekstowe, dwie etykiety, przycisk "Dodaj" oraz przycisk "Mediana". Przy pomocy tych obiektów (oraz innych jeśli będą niezbędne) należy stworzyć program obliczający medianę zbioru liczb rzeczywistych. Działanie programu powinno być następujące:
- Użytkownik wpisuje liczbę w pole tekstowe, a następnie wciska przycisk "Dodaj" co powoduje dodanie liczby do listy i równocześnie wypisanie wszystkich elementów listy do jednej z etykiet.
- Kiedy użytkownik kliknie przycisk "Mediana", program powinien sortować rosnąco elementy listy i ponownie wypisać je do etykiety, tym razem w porządku rosnącym, a następnie powinien obliczyć medianę i wynik wypisać w drugiej etykiecie.
- Aby uniknąć błędu w działaniu programu w przypadku kiedy użytkownik wpisze w pole tekstowe wyrażenie, którego nie da się zamienić na liczbę rzeczywistą, parsowanie zmiennej String powinno wyglądać następująco:
try{ number = Double.parseDouble(text); } catch(NumberFormatException exception){ System.out.println("Wrong number format."); }
Przykładowe rozmieszczenie komponentów w oknie:
Źródła:
- htt jps://docs.oracle.com/javase/tutorial/java/concepts/interface.html
- https:/javastart.pl/static/programowanie-obiektowe/interfejsy/
- http://www.samouczekprogramisty.pl/interfejsy-w-jezyku-java/
- https://docs.oracle.com/javase/tutorial/uiswing/events/intro.html
- https://docs.oracle.com/javase/tutorial/collections/interfaces/index.html
- http://pojava.fizyka.pw.edu.pl/index.php/laboratoria/laboratorium-3
- http://www.samouczekprogramisty.pl/kolekcje-w-jezyku-java/