Typy sparametryzowane

Podobne dokumenty
Klasy abstrakcyjne i interfejsy

JAVA W SUPER EXPRESOWEJ PIGUŁCE

Konstruktory. Streszczenie Celem wykładu jest zaprezentowanie konstruktorów w Javie, syntaktyki oraz zalet ich stosowania. Czas wykładu 45 minut.

Dziedziczenie. Streszczenie Celem wykładu jest omówienie tematyki dziedziczenia klas. Czas wykładu 45 minut.

Java - tablice, konstruktory, dziedziczenie i hermetyzacja

Kurs programowania. Wykład 2. Wojciech Macyna. 17 marca 2016

Dokumentacja do API Javy.

Interfejsy. Programowanie obiektowe. Paweł Rogaliński Instytut Informatyki, Automatyki i Robotyki Politechniki Wrocławskiej

Aplikacje w środowisku Java

Wyjątki. Streszczenie Celem wykładu jest omówienie tematyki wyjątków w Javie. Czas wykładu 45 minut.

Polimorfizm. dr Jarosław Skaruz

Dziedziczenie. dr Jarosław Skaruz

Programowanie obiektowe

Metody Metody, parametry, zwracanie wartości

Wykład 6: Dziedziczenie

Klasy abstrakcyjne, interfejsy i polimorfizm

C++ - przeciążanie operatorów. C++ - przeciążanie operatorów. C++ - przeciążanie operatorów. C++ - przeciążanie operatorów

Java: kilka brakujących szczegółów i uniwersalna nadklasa Object

Informatyka I. Klasy i obiekty. Podstawy programowania obiektowego. dr inż. Andrzej Czerepicki. Politechnika Warszawska Wydział Transportu 2018

1 Wskaźniki i zmienne dynamiczne, instrukcja przed zajęciami

Języki i techniki programowania Ćwiczenia 3 Dziedziczenie

Kurs WWW. Paweł Rajba.

Zad.30. Czy można utworzyć klasę, która implementuje oba interfejsy?

PARADYGMATY PROGRAMOWANIA Wykład 4

Dziedziczenie. Tomasz Borzyszkowski

Java: interfejsy i klasy wewnętrzne

Dawid Gierszewski Adam Hanasko

Szablony funkcji i klas (templates)

1. Które składowe klasa posiada zawsze, niezależnie od tego czy je zdefiniujemy, czy nie?

TYPY GENERYCZNE (GENERICS)

Programowanie obiektowe

Wątki. Definiowanie wątków jako klas potomnych Thread. Nadpisanie metody run().

TEMAT : KLASY DZIEDZICZENIE

Kurs programowania. Wykład 1. Wojciech Macyna. 3 marca 2016

Aplikacje w środowisku Java

Dziedziczenie Dana jest klasa Punkt w pliku o nazwie Punkt.java:

Technologie i usługi internetowe cz. 2

Programowanie w Javie 1 Wykład i Ćwiczenia 3 Programowanie obiektowe w Javie cd. Płock, 16 października 2013 r.

Programowanie strukturalne i obiektowe. Funkcje

Obiekt klasy jest definiowany poprzez jej składniki. Składnikami są różne zmienne oraz funkcje. Składniki opisują rzeczywisty stan obiektu.

Java podstawy jęyka. Wykład 2. Klasy abstrakcyjne, Interfejsy, Klasy wewnętrzne, Anonimowe klasy wewnętrzne.

Informatyka I. Dziedziczenie. Nadpisanie metod. Klasy abstrakcyjne. Wskaźnik this. Metody i pola statyczne. dr inż. Andrzej Czerepicki

Rozdział 4 KLASY, OBIEKTY, METODY

Aplikacje Internetowe. Najprostsza aplikacja. Komponenty Javy. Podstawy języka Java

Programowanie obiektowe Wykład 3. Dariusz Wardowski. dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ 1/21

Funkcje. Wprowadzenie. Mirosław Ochodek

Język JAVA podstawy. Wykład 4, część 1. Jacek Rumiński. Politechnika Gdańska, Inżynieria Biomedyczna

Enkapsulacja, dziedziczenie, polimorfizm

Programowanie obiektowe

1 Atrybuty i metody klasowe

Polimorfizm, metody wirtualne i klasy abstrakcyjne

Języki i techniki programowania Ćwiczenia 2

Techniki programowania INP001002Wl rok akademicki 2018/19 semestr letni. Wykład 3. Karol Tarnowski A-1 p.

Mechanizm dziedziczenia

Przypomnienie o klasach i obiektach

Programowanie w Internecie. Java

Programowanie obiektowe i zdarzeniowe

Techniki programowania INP001002Wl rok akademicki 2018/19 semestr letni. Wykład 4. Karol Tarnowski A-1 p.

Język JAVA podstawy. wykład 2, część 2. Jacek Rumiński. Politechnika Gdańska, Inżynieria Biomedyczna

Kurs programowania. Wykład 9. Wojciech Macyna. 28 kwiecień 2016

2. Tablice. Tablice jednowymiarowe - wektory. Algorytmy i Struktury Danych

Definicje klas i obiektów. Tomasz Borzyszkowski

UML a kod w C++ i Javie. Przypadki użycia. Diagramy klas. Klasy użytkowników i wykorzystywane funkcje. Związki pomiędzy przypadkami.

Podstawy obiektowości

Programowanie obiektowe

Związek między pojęciami Zasada podstawialności Podklasy muszą realizować kontrakt zawarty przez nadklasy

IMIĘ i NAZWISKO: Pytania i (przykładowe) Odpowiedzi

Metody sparametryzowane

Kurs programowania. Wykład 13. Wojciech Macyna. 14 czerwiec 2017

dziedziczenie - po nazwie klasy wystąpią słowa: extends nazwa_superklasy

Diagram klas UML jest statycznym diagramem, przedstawiającym strukturę aplikacji bądź systemu w paradygmacie programowania obiektowego.

Wykład 8: klasy cz. 4

1. Co można powiedzieć o poniższym kodzie (zakładając, że zaimportowano wszystkie niezbędne klasy)?

Wykład 5: Więcej o Klasach i Metodach

C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy WSKAŹNIKI KLASOWE

Platformy Programistyczne Podstawy języka Java

Programowanie obiektowe i język Java

Java. Wykład. Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ

Języki i techniki programowania Ćwiczenia 4 Wzorce

2. Składnia, środowisko i konwencje w Javie

Wykład 2 Wybrane konstrukcje obiektowych języków programowania (1)

Programowanie obiektowe

Kompilacja javac prog.java powoduje wyprodukowanie kilku plików o rozszerzeniu.class, m.in. Main.class wykonanie: java Main

Programowanie obiektowe

Programowanie obiektowe Wykład 6. Dariusz Wardowski. dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ 1/14

Programowanie obiektowe

Klasa jest nowym typem danych zdefiniowanym przez użytkownika. Najprostsza klasa jest po prostu strukturą, np

Polimorfizm a klasy generyczne w języku Java. Zdzisław Spławski 1

Wykład 3 Składnia języka C# (cz. 2)

Programowanie obiektowe

Java. język programowania obiektowego. Programowanie w językach wysokiego poziomu. mgr inż. Anna Wawszczak

KLASY, INTERFEJSY, ITP

Programowanie w C++ Wykład 14. Katarzyna Grzelak. 3 czerwca K.Grzelak (Wykład 14) Programowanie w C++ 1 / 27

Klasy. dr Anna Łazińska, WMiI UŁ Podstawy języka Java 1 / 13

Pakiety i interfejsy. Tomasz Borzyszkowski

Programowanie obiektowe

WSNHiD, Programowanie 2 Lab. 2 Język Java struktura programu, dziedziczenie, abstrakcja, polimorfizm, interfejsy

Programowanie obiektowe. Materiały przygotował: mgr inż. Wojciech Frohmberg

C++ - polimorfizm. C++ - polimorfizm. C++ - polimorfizm. C++ - polimorfizm. C++ - polimorfizm POLIMORFIZM

Transkrypt:

Typy sparametryzowane Streszczenie Celem wykładu jest zaprezentowanie typów sparametryzowanych. Czas wykładu 90 minut. Istnieją algorytmy, których zasada działania nie zależy od typu danych wejściowych. Możemy na przykład sortować obiekty różnych typów stosując te same mechanizmy. Ważne tylko, aby zadane było pewne kryterium porównujące obiekty między sobą. Zanim zajmiemy się algorytmami, zobaczmy w jaki sposób przygotowuje się sparametryzowane struktury danych. Parametr (bądź parametry) przekazuje się poprzez dowolny identyfikator (bądź identyfikatory) umieszczone w nawiasach <> po nazwie klasy: class A<T> T t; void wypisz() System.out.println(t); Powyższy przykład definiuje klasę A z parametrem T. Wykorzystanie jej wymaga podania konkretnego typu, który będzie podstawiony zamiast parametru. W poniższym przykładzie generowane są dwa obiekty: jeden (wskazywany przez referencję a) typu A<Integer>, drugi (wskazywany przez b) typu A<String>. Typem a i b nie jest klasa A, ale klasa A z odpowiednim argumentem. A<Integer> a = new A<Integer>(); a.t = new Integer(-3); a.wypisz(); A<String> b = new A<String>(); b.t = "Ala ma kota"; b.wypisz(); Typem podstawianym za parametry klasy muszą być klasy. Typy skalarne są niedopuszczalne. Poniższy przykład jest zatem niepoprawny. 1

A<int> c; // błąd Wykorzystanie parametrów w klasach Parametr klasy może być wykorzystany jako typ pola, typ argumentów funkcji oraz typ wyniku funkcji: class A<T> T t; // typ pola A(T a) t = a; // typ argumentu funkcji T g() return t; // typ wyniku funkcji void wypisz() System.out.println(g()); Istnieją jednak pewne ograniczenia na stosowanie parametru klasy. Pól, których typem jest parametr, nie można inicjalizować w momencie deklaracji. Nie można generować tablic o typie bazowym, który jest parametrem (związane z powyższym). Funkcja o typie wyniku będącym parametrem nie może być statyczna. Klasy wyjątków nie mogą być sparametryzowane. Proszę odkomentować kolejne linie przykładu i zaobserwować komentarze kompilatora. class A<T> // T t = new T(); // inicjalizacja pola // T[] x = new T[4]; // tworzenie tablicy // static T f() // funkcja statyczna Nie są to jednak ograniczenia, które uniemożliwiają wygodne stosowanie klas sparamatryzowanych. Inicjalizacje należy przenieść, np. do konstruktorów: class A<T> T[] x; A(T[] y) x = y; 2

Kolejne ograniczenie związane z klasami z parametrem jest obserwowalne przy klasach z wieloma parametrami. Przeanalizujmy przykład klasy z dwoma parametrami: class A<T1,T2> void f(t1 t) void f(t2 t) Na pierwszy rzut oka wydaje się, że przykład jest poprawny. Przyjrzyjmy się jednak funkcjom f(t1 t) oraz f(t2 t). W momencie definiowania klasy nie mamy żadnej gwarancji, że w momencie użycia klasy parametry T1 oraz T2 będą konkretyzowane różnymi typami. Co się stanie, gdy za T1 i T2 podstawiony zostanie ten sam typ, np. Integer? W konsekwencji powstaną dwie funkcje f(integer t). Z własności mechanizmu przeciążania funkcji wiemy, że taka sytuacja jest niedopuszczalna. Klasy z ograniczonym parametrem Rozważmy program obliczający średnią arytmetyczną wyrazów tablicy. Jaki jest algorytm? Należy zsumować wszystkie elementy tablicy i tę sumę podzielić przez ilość elementów. Proszę zauważyć, że nic nie mówimy o typie elementów tablicy. Może nim być typ całkowity, rzeczywisty, lub inny typ liczbowy w językach które dopuszczają inne typy liczbowe. Ale nawet w Javie nic ma potrzeby o mówieniu, który typ całkowity czy rzeczywisty wybieramy. Istotne jest tylko, aby elementy danego typu miały wartość liczbową, którą można będzie sumować. Poniższy przykład ilustruje implementację programu. Zwróćmy uwagę na instrukcję suma += a.doublevalue();. Pobierana jest wartość liczbowa kolejnego elementu tablicy tab o typie bazowym T będącym parametrem klasy. Ale żeby to było możliwe elementy typu T muszą taką wartość posiadać. Muszą być zatem potomkami klasy Number, klasy posiadającej funkcję doublevalue(); class A<T extends Number> T[] tab; A(T[] x) tab = x; double srednia() double suma = 0.0; for (T a: tab) suma += a.doublevalue(); return suma / tab.length; void wypisz() System.out.println(srednia()); Wykorzystajmy tę klasę do obliczenia średniej arytmetycznej tablicy liczb całkowitych oraz tablicy liczb rzeczywistych: 3

Integer[] i = 4,6,8,10 ; A<Integer> ai = new A<Integer>(i); ai.wypisz(); Double[] d = 2.0, 4.0, 6.0 ; A<Double> ad = new A<Double>(d); ad.wypisz(); // String[] s1 = "aa" ; // A<String> as1 = new A<String>(s1); // as1.wypisz(); Proszę z powyższym kodem zrobić dwa eksperymenty: a) wykomentować część dotyczącą napisów oraz b) skasować tekst <T extends Number> i zaobserwować komentarze kompilatora. Wieloznaczne argumenty funkcji Rozszerzmy program o funkcję porównującą wartości średnie dwóch różnych tablic. Wiemy, że mając jedną funkcję srednia() możemy obliczać średnie tablic o różnych typach bazowych. Chcielibyśmy zatem, aby nowo dodana funkcja pozwalała na porównywanie średnich tablic o różnych typach bazowych. Java umożliwia to przez zastosowanie tzw. argumentów wieloznacznych. Uzyskuje się je stosując? (znak zapytania) zamiast identyfikatora typu parametru. class A<T extends Number> T[] tab; A(T[] x) tab = x; double srednia() double suma = 0.0; for (T a: tab) suma += a.doublevalue(); return suma / tab.length; boolean porownaj_srednie(a<?> o) return srednia() == o.srednia(); Zwróćmy uwagę, że gdyby funkcja porównująca średnie korzystała z typu T będącego parametrem całej klasy, tj. miała sygnaturę boolean porownaj_srednie(a<t> o), umożliwiałaby porównywanie średnich tablic o jednakowych typach bazowych. Oto przykład wykorzystujący omawianą klasę do obliczania i porównywania średnich tablic liczb całkowitych oraz rzeczywistych: 4

Integer[] i = 2,4,6,1 ; A<Integer> ai = new A<Integer>(i); Integer[] j = 2,4,6 ; A<Integer> aj = new A<Integer>(j); Double[] d = 2.0, 4.0, 6.0, 1.0 ; A<Double> ad = new A<Double>(d); System.out.println(ai.porownaj_srednie(aj)); System.out.println(ai.porownaj_srednie(ad)); Argumenty wieloznaczne z ograniczeniem Kolejnym rozszerzeniem języka są tzw. argumenty wieloznaczne z ograniczeniem. Podobnie jak w przypadku parametrów klas możemy ograniczyć typy argumentów funkcji, które mogą być podstawiane za argumenty wieloznaczne. Po znaku zapytania oznaczającego argument wieloznaczny podaje się słowo extends i identyfikator typu. Za taki argument podstawiony może być obiekt dowolnego typu, ale koniecznie potomka typu zadeklarowanego jako ograniczenie bądź typu ograniczenia. Ponadto, stosując słowo super i identyfikator typu ogranicza się typy argumentów, które mogą być podstawione w danym miejscu do typu ograniczenia lub jego przodka. Przeanalizujmy przykład. Zdefiniujmy ciąg klas od siebie zależnych (ich zawartość nie jest istotna dla przykładu): class K1 class K2 extends K1 class K3 extends K2 class K4 extends K3 class K5 extends K4 class K6 extends K5 oraz klasę class A<T extends K2> void f1 (A<T> o) System.out.println("f1"); void f2 (A<?> o) System.out.println("f2"); void f3 (A<? extends K4> o) System.out.println("f3"); void f4 (A<? super K4> o) System.out.println("f4"); 5

Pytanie: które z klas K1 do K6 mogą być podstawiane za typ T będący parametrem klasy A oraz które z tych klas mogą być typami argumentów funkcji od f1 do f4? // A<K1> k1 = new A<K1>(); A<K2> k2 = new A<K2>(); A<K3> k3 = new A<K3>(); A<K4> k4 = new A<K4>(); A<K5> k5 = new A<K5>(); A<K6> k6 = new A<K6>(); // przetestować poniższe kombinacje // k6.f4(k6); // k2.f1(k3); // k2.f2(k3); // k4.f3(k6); // k2.f4(k4); Dziedziczenie klas z parametrami Klasy sparametryzowane mogą być elementami drzewa typów. Mogą dziedziczyć po innych klasach. Mogą być dziedziczone. Mogą mieć większą ilość parametrów niż klasa przodka. Mogą mieć mniejszą ilość parametrów niż klasa przodka. class K1 class K2<T> extends K1 class K3<T,V extends T> extends K2<Integer> class K4 extends K3<Object,String> Klasa K1 jest potomkiem klasy Object. Nie posiada żadnych parametrów. Klasa K2 dziedziczy po bezparametrowej klasie K1, ale sama posiada parametr. Klasa K3 jest potomkiem sparametryzowanej klasy K2, gdzie ten parametr ukonkretnia typem Integer. Sama zaś posiada dwa parametry, gdzie drugi musi rozszerzać pierwszy. Klasa K4 nie ma parametrów, ale dziedziczy po klasie K3 ukonkretniając jej parametry typami Object oraz String. Przykład wykorzystania klas od K1 do K4: K1 k1 = new K1(); K2<Double> k2 = new K2<Double>(); K3<Object,String> k3 = new K3<Object,String>(); 6

K4 k4 = new K4(); Funkcje ze sparametryzowanymi typami argumantów Jeśli typ z parametrem potrzebny jest nie w obrębie całej klasy, ale tylko w jednej funkcji (lub kilku funkcjach, ale niezwiązanych ze sobą), można sparametryzować tylko wybrane typy argumentów wybranych funkcji. Parametry typów wprowadza się w nawiasach <> przed typem wyniku. Klasa class A static <T, V extends T> void f(t t, V v) System.out.println("" + t + " " + v); definiuje jedną dwuargumentową funkcję f, której typ drugiego argumentu ma rozszerzać się do typu argumentu pierwszego. (Funkcję f zdefiniowano jako statyczną, ale tylko na potrzeby poniższego jej użycia. W ogólnym przypadku funkcje z argumentami sparametryzowanymi nie muszą być statyczne.) A.f(new Object(), new Integer(3)); // A.f(new String(), new Integer(1)); Dlaczego drugie wywołanie funkcji f jest wykomentowane? Interfejsy z parametrami Sparametryzowane mogą być również interfejsy. interface I<T,V extends Number> void f(t t,v v); Klasy implementujące takie interfejsy muszą w swojej deklaracji zawrzeć typy konkretyzujące parametry implementowanego interfejsu. Może to być parametr klasy (T w przykładzie), lub konkretny typ (Integer w przykładzie): 7

class A<T> implements I<T,Integer> public void f(t t,integer v) System.out.println("Jestem w f: " + t + " " + v); A<Double> a = new A<Double>(); a. f ( new Double(3), new Integer(8) ); a. f (3.0, 8); Podsumowanie Klasy z parametrami umożliwiają programowanie algorytmów niezależnych od typów. Nazwy parametrów podaje się w <> po nazwie klasy. Typy parametrów klas mogą być ograniczane. Klasy z parametrami mogą dziedziczyć inne klasy. Klasy z parametrami mogą być dziedziczone przez inne klasy. Parametry mogą posiadać tylko wybrane funkcje klas (niekoniecznie całe klasy). Interfejsy mogą mieć parametry. Funkcje mogą mieć parametry wieloznaczne i wieloznaczne z ograniczeniami. 8