Programowanie w Javie wykład 9 Klasy wewnętrzne, klasy anonimowe Klasy opakowujące

Podobne dokumenty
Aplikacje w Javie wykład 6 Klasy wewnętrzne, klasy anonimowe Typy i metody sparametryzowane (generics)

Aplikacje w środowisku Java- wykład 6 Klasy wewnętrzne, klasy anonimowe Klasy opakowujące Typy i metody sparametryzowane (generics) wildcards

Laboratorium 03: Podstawowe konstrukcje w języku Java [2h]

Obszar statyczny dane dostępne w dowolnym momencie podczas pracy programu (wprowadzone słowem kluczowym static),

Kurs programowania. Wykład 3. Wojciech Macyna. 22 marca 2019

Interfejsy i klasy wewnętrzne

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

Dokumentacja do API Javy.

JAVA W SUPER EXPRESOWEJ PIGUŁCE

Platformy Programistyczne Podstawy języka Java

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

Programowanie obiektowe

Wykład 8: klasy cz. 4

Wykład 2: Podstawy Języka

Polimorfizm, metody wirtualne i klasy abstrakcyjne

Rozdział 4 KLASY, OBIEKTY, METODY

Wykład 4: Klasy i Metody

Java Język programowania

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

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

Programowanie obiektowe

Programowanie w Internecie. Java

Java - tablice, konstruktory, dziedziczenie i hermetyzacja

Języki i metody programowania Java. Wykład 2 (część 2)

Kurs programowania. Wstęp - wykład 0. Wojciech Macyna. 22 lutego 2016

Programowanie obiektowe

Programowanie obiektowe

Aplikacje w środowisku Java

Wykład 5: Klasy cz. 3

Definiowanie własnych klas

1 Atrybuty i metody klasowe

Enkapsulacja, dziedziczenie, polimorfizm

Podstawowe części projektu w Javie

Współbieżność i równoległość w środowiskach obiektowych. Krzysztof Banaś Obliczenia równoległe 1

Programowanie w Javie - wykład 2

Programowanie w Javie - wykład 3

Programowanie w Javie wykład 8 Interfejsy

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

Wykład 7: Pakiety i Interfejsy

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

Wstęp do programowania obiektowego. WYKŁAD 3 Dziedziczenie Pola i funkcje statyczne Funkcje zaprzyjaźnione, this

Aplikacje w Javie- wykład 11 Wątki-podstawy

Informacje ogólne. Karol Trybulec p-programowanie.pl 1. 2 // cialo klasy. class osoba { string imie; string nazwisko; int wiek; int wzrost;

Polimorfizm. dr Jarosław Skaruz

Podstawy i języki programowania

KOTLIN. Język programowania dla Androida

Programowanie obiektowe

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

PARADYGMATY PROGRAMOWANIA Wykład 4

Podstawy Języka Java

Podstawy otwartych języków programowania Przechowywanie danych

Kurs WWW. Paweł Rajba.

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

Programowanie obiektowe. Literatura: Autor: dr inŝ. Zofia Kruczkiewicz

Java: interfejsy i klasy wewnętrzne

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

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

JAVA- wykład 2 Klasy

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

Aplikacje w środowisku Java

1. Wartość, jaką odczytuje się z obszaru przydzielonego obiektowi to: a) I - wartość b) definicja obiektu c) typ oboektu d) p - wartość

Podstawy programowania skrót z wykładów:

Programowanie obiektowe

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

Wykład 6: Dziedziczenie

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

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

Wprowadzenie do języka Java

Dziedziczenie. dr Jarosław Skaruz

MATERIAŁY DO ZAJĘĆ II

Technologie i usługi internetowe cz. 2

Podstawy programowania obiektowego

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

Definicje klas i obiektów. Tomasz Borzyszkowski

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

TEMAT : KLASY DZIEDZICZENIE

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

Zofia Kruczkiewicz, Programowanie obiektowe - java, wykład 2 1

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

Multimedia JAVA. Historia

Programowanie w środowisku graficznym- wykład 2 Java - Klasy

public - może być używana w kodzie poza klasą, jedna klasa ModyfikatorKlasy może być kombinacją wyrażeń:

Typy sparametryzowane

PHP 5 język obiektowy

Informatyka I. Typy danych. Operacje arytmetyczne. Konwersje typów. Zmienne. Wczytywanie danych z klawiatury. dr hab. inż. Andrzej Czerepicki

JAVA. Java jest wszechstronnym językiem programowania, zorientowanym. apletów oraz samodzielnych aplikacji.

Języki i techniki programowania Ćwiczenia 2

Programowanie obiektowe

Języki i metody programowania Java INF302W Wykład 2 (część 1)

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

10. Programowanie obiektowe w PHP5

Spis treści. 1 Java T M

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

Tworzenie aplikacji w języku Java

Programowanie obiektowe, wykład nr 6. Klasy i obiekty

Pakiety i interfejsy. Tomasz Borzyszkowski

Java Podstawy. Michał Bereta

Programowanie obiektowe

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

Tablice (jedno i wielowymiarowe), łańcuchy znaków

Transkrypt:

1 Programowanie w Javie wykład 9 Klasy wewnętrzne, klasy anonimowe Klasy opakowujące Treści prezentowane w wykładzie zostały oparte o: Barteczko, JAVA Programowanie praktyczne od podstaw, PWN, 2014 Barteczko, JAVA Uniwersalne techniki programowania, PWN, 2017 http://docs.oracle.com/javase/8/docs/ C. S. Horstmann, G. Cornell, Java. Podstawy, Helion, Gliwice 2013

Klasy wewnętrzne Klasa wewnętrzna to klasa zdefiniowana wewnątrz innej klasy. class A {... class B {...... Klasa B jest klasą wewnętrzną w klasie A. Klasa A jest klasą otaczającą klasy B. Klasy wewnętrzne (ang. Nested Classes) dzielą się na dwie kategorie: statyczne (static) i niestatyczne (non-static) class OuterClass {... static class StaticNestedClass {... class InnerClass {... 2

Klasy wewnętrzne 3 Klasa wewnętrzna może: być zadeklarowana ze specyfikatorem private (normalne klasy nie!), uniemożliwiając wszelki dostęp spoza klasy otaczającej, odwoływać się do niestatycznych składowych klasy otaczającej (jeśli nie jest zadeklarowana ze specyfikatorem static), być zadeklarowana ze specyfikatorem static (normalne klasy nie!), co powoduje, że z poziomu tej klasy nie można odwoływać się do składowych niestatycznych klasy otaczającej (takie klasy nazywają się zagnieżdżonymi, ich rola sprowadza się wyłącznie do porządkowania przestrzeni nazw i ew. lepszej strukturyzacji kodu) mieć nazwę (klasa nazwana) lub nie mieć nazwy (wewnętrzna klasa anonimowa), być lokalna zdefiniowana w bloku (metodzie lub innym bloku np. w bloku po instrukcji if) odwoływać się do zmiennych lokalnych, jeśli jest lokalna, a wartości zmiennych lokalnych, do których się odwołujemy nie mogą się zmieniać (do Javy 7 wymagane było by były ze specyfikatorem final).

Klasy wewnętrzne 4 Klasy wewnętrzne tworzymy i używamy ponieważ: Klasy wewnętrzne mogą być ukryte przed innymi klasami pakietu (względy bezpieczeństwa). Klasy wewnętrzne pozwalają unikać kolizji nazw (np. klasa wewnętrzna nazwana Vector nie koliduje nazwą z klasą zewnętrzną o tej samej nazwie). Klasy wewnętrzne pozwalają (czasami) na lepszą, bardziej klarowną strukturyzację kodu, bo można odwoływać się z nich do składowych (nawet prywatnych) klasy otaczającej, a przy tym zlokalizować pewne działania. Klasy wewnętrzne (w szczególności anonimowe) są intensywnie używane przy implementacji standardowych interfejsów Javy. Anonimowe klasy wewnętrzne pozwalają na traktowanie fragmentów kodu do wykonania (ściślej: metod przedefiniowywanych w tych klasach) jak obiektów, a wobec tego np. umieszczanie ich w tablicach, kolekcjach, czy przekazywanie innym metodom jako argumentów.

5 Klasy wewnętrzne Do statycznej klasy wewnętrznej mamy dostęp poprzez nazwę klasy otaczającej OuterClass.StaticNestedClass Np. aby stworzyć obiekt statycznej klasy wewnętrznej należy OuterClass.StaticNestedClass nestedobject = new OuterClass.StaticNestedClass(); Między obiektami statycznej klasy wewnętrznej a obiektami klasy otaczającej nie zachodzą żadne związki. Rozważmy klasy class OuterClass {... class InnerClass {... Dla nieprywatnych klas wewnętrznych możliwe jest odwoływanie się do nich spoza kontekstu klasy otaczającej: OuterClass.InnerClass

Klasy wewnętrzne Zawarcie klasy wewnętrznej w klasie otaczającej nie oznacza, że obiekty klasy otaczającej zawierają elementy (pola) obiektów klasy wewnętrznej. Obiekt niestatycznej klasy wewnętrznej zawiera referencję do obiektu klasy otaczającej, co umożliwia odwoływanie się do jej wszystkich składowych. Tworzenie obiektu niestatycznej klasy wewnętrznej wymaga zawsze istnienia obiektu klasy otaczającej. Mówi się, że obiekt klasy wewnętrznej opiera się na obiekcie klasy otaczającej. Dlatego tworzymy najpierw obiekt klasy otaczającej OuterClass outerobject = new OuterClass(); OuterClass.InnerClass innerobject = outerobject.new InnerClass(); lub jeśli nie potrzebujemy obiektu klasy zewnętrznej OuterClass.InnerClass innerobject = new OuterClass().new InnerClass(); Wewnątrz klasy otaczającej (OuterClass) tam, gdzie dostępne jest this, można po prostu napisać: InnerClass innerobject = new InnerClass(); 6

Klasy wewnętrzne- przesłanianie zmiennych 7 public class ShadowTest { public int x = 0; // x pole klasy zewnętrznej class FirstLevel { public int x = 1;// x pole klasy wewnętrznej void methodinfirstlevel(int x) { System.out.println("x = " + x);//x parametr metody System.out.println("this.x = " + this.x); System.out.println("ShadowTest.this.x = " + ShadowTest.this.x); public static void main(string... args) { ShadowTest st = new ShadowTest(); ShadowTest.FirstLevel fl = st.new FirstLevel(); fl.methodinfirstlevel(23); Wyjście: x = 23 this.x = 1 ShadowTest.this.x = 0

8 Anonimowe klasy wewnętrzne Szczególną rolę odgrywają anonimowe klasy wewnętrzne. Klasy te nie mają nazwy. Najczęściej tworzymy je po to, by przedefiniować jakieś metody klasy bazowej przez klasę wewnętrzną bądź zdefiniować metody implementowanego przez nią interfejsu na użytek jednego obiektu. Referencję do tego obiektu chcemy traktować jako typu klasy bazowej lub typu implementowanego interfejsu. Nazwa takiej klasy wewnętrznej jest więc nam niepotrzebna i nie chcemy jej wymyślać. Wtedy stosujemy anonimowe klasy wewnętrzne. Definicja anonimowej klasy wewnętrznej : new NazwaTypu( parametry ) { // pola i metody klasy wewnętrznej gdzie: NazwaTypu nazwa nadklasy (klasy dziedziczonej w klasie wewnętrznej) lub implementowanego przez klasę wewnętrzną interfejsu, parametry argumenty przekazywane konstruktorowi nadklasy; w przypadku, gdy Typ jest nazwą interfejsu lista parametrów jest oczywiście pusta (bo chodzi o implementację interfejsu).

Anonimowe klasy wewnętrzne 9 Uwagi: anonimowe klasy wewnętrzne nie mogą mieć konstruktorów (bo nie mają nazwy), za pomocą anonimowej klasy wewnętrznej można stworzyć tylko jeden obiekt, bo definicja klasy podana jest w wyrażeniu new czyli przy tworzeniu obiektu, a nie mając nazwy klasy nie możemy potem tworzyć innych obiektów; jeśli jednak to wyrażenie new umieścimy np. w pętli to oczywiście stworzone zostanie tyle obiektów ile razy wykona się pętla, definiowanie klas wewnętrznych implementujących interfejsy stanowi jedyny dopuszczalny przypadek użycia nazwy interfejsu w wyrażeniu new anonimowe klasy wewnętrzne są kompilowane do plików.class o nazwach automatycznie nadawanych przez kompilator (nazwa składa się z nazwy klasy otaczającej i jakiegoś automatycznie nadawanego identyfikatora) Klasy wewnętrzne (nazwane i anonimowe) mogą być definiowane w blokach lokalnych (np. w ciele metody). Będziemy je krótko nazywać klasami lokalnymi. Wewnętrzne klasy lokalne są doskonale odseparowane (nie ma do nich żadnego dostępu spoza bloku, w którym są zdefiniowane), a mogą odwoływać się do składowych klasy otaczającej oraz zmiennych lokalnych zadeklarowanych w bloku (pod warunkiem, że są one niezmienne).

Anonimowe klasy wewnętrzne - przykład Przykład: Listowanie katalogu z filtrowaniem nazw (pliki.java) Obiekty plikowe (pliki i katalogi) są obiektami klasy File z pakietu java.io. Wobec katalogu można użyć metody list z klasy File, która zwraca tablicę nazw plików (i podkatalogów) w nim zawartych. Używając metody list z argumentem typu FilenameFilter możemy określić kryteria filtrowania wyniku wg nazw (np. otrzymać tylko listę plików o rozszerzeniu.java): public String[] list(filenamefilter filter) FilenameFilter jest interfejsem funkcyjnym, w którym zawarto jedną metodę boolean accept(file dir, String filename). Musimy zatem mieć obiekt klasy implementującej FilenameFilter, w której to klasie zdefiniujemy metodę accept i podać referencję do tego obiektu jako argument metody list. Metoda accept będzie wtedy wywoływana dla każdego obiektu plikowego, zawartego w katalogu z argumentami: dir katalog oraz filename nazwa pliku lub podkatalogu. Powinniśmy ją zdefiniować w taki sposób, by zwracała true tylko wtedy, gdy nazwa spełnia wymagane przez nas kryteria, a w przeciwnym razie false. Naturalnym sposobem oprogramowania jest tu umieszczenie definicji anonimowej klasy wewnętrznej implementującej FilenameFilter w wyrażeniu new podanym jako argument metody list. A ponieważ listowanie umieszczamy w jakiejś metodzie, to ta anonimowa klasa będzie lokalną klasą wewnętrzną. 10

11 Anonimowe klasy wewnętrzne - przykład void listjavafiles(string dirname) { // argument - nazwa katalogu File dir = new File(dirName); // katalog - obiekt typu File // listowanie z filtrowaniem nazw; kryteria wyboru nazw // podajemy za pomocą implementacji metody accept // w lokalnej anonimowej klasie wewnętrznej String[] fnames = dir.list( new FilenameFilter() { public boolean accept(file dir, String name) { return name.endswith(".java"); ); for (int i=0; i < fnames.length; i++) { // lista -> stdout System.out.println(fnames[i]);

Anonimowe klasy wewnętrzne przykład 2 Lista plików z rozszerzeniem.java, które zmodyfikowano po 21 sierpnia (skorzystać z public File[] listfiles(filefilter filter)). Calendar c = Calendar.getInstance(); c.set(2018,8,22,0,0); long time = c.gettimeinmillis(); File[] files = dir.listfiles( new FileFilter(){ ); public boolean accept(file file) { return file.isfile() && file.getname().endswith(".java") && file.lastmodified() >= time; //w kodzie anonimowej klasy wewnętrznej odwołujemy się do //zmiennej lokalnej time, od wersji Java 8 nie musimy //takiej zmiennej deklarować jako final, taka zmienna musi //być effectively final - tzn. nie zmieniać swoich wartości, //klasa wewnętrzna otrzymuje jej kopię 12

Anonimowe klasy wewnętrzne przykład 3 14 public class HelloWorldAnonymousClasses { interface HelloWorld { //inner nested interface public void greet(); public void greetsomeone(string someone); public void sayhello() { class EnglishGreeting implements HelloWorld { String name = "world"; public void greet() { greetsomeone("world"); public void greetsomeone(string someone) { name = someone; System.out.println("Hello " + name); HelloWorld englishgreeting = new EnglishGreeting();

Anonimowe klasy wewnętrzne przykład 3 cd 15 //klasa anonimowa HelloWorld frenchgreeting = new HelloWorld() { String name = "tout le monde"; public void greet() { greetsomeone("tout le monde"); public void greetsomeone(string someone) { name = someone; System.out.println("Salut " + name); ; englishgreeting.greet(); frenchgreeting.greetsomeone("fred"); public static void main(string[] args) { HelloWorldAnonymousClasses myapp = new HelloWorldAnonymousClasses(); myapp.sayhello();

Opakowanie typów prostych 16 Często występuje potrzeba traktowania liczb jako obiektów, np. kolekcje mogą zawierać tylko referencje do obiektów. Tymczasem liczby są reprezentowane przez typy proste (pierwotne) (i nie są obiektami). Dlatego w standardowym pakiecie java.lang umieszczono specjalne klasy opakowujące liczby (w ogóle wszystkie typy pierwotne) i czyniące z nich obiekty. Należą do nich następujące klasy: Long Integer Short Byte Double Float Obiekty tych klas reprezentują (w sposób obiektowy) liczby odpowiednich typów. Mówimy tu o opakowaniu liczby, bowiem liczba ta jest umieszczana "w środku" obiektu odpowiedniej klasy, jako jego element. We wcześniejszych wersjach Javy operatory arytmetyczne można było stosować tylko do liczbowych typów prostych. Zatem, gdy potrzebowaliśmy liczby jako obiektu, a jednocześnie typu prostego do wykonywania operacji arytmetycznych, to musieliśmy umieć zapakować liczbę do obiektu klasy opakowującej i wyciągnąć ją stamtąd.

Opakowanie typów prostych 17 Typy proste możemy pakować i rozpakowywać "ręcznie", np. obiektowy odpowiednik liczby 5 typu int możemy uzyskać tworząc obiekt klasy Integer: Integer a = new Integer(5); Z obiektu takiej klasy możemy liczbę wyciągnąć za pomocą odpowiednich metod, np. int i = a.intvalue(); // zwraca wartość typu int, Podobnie: Double dd = new Double(7.1); //"zawartą" w obiekcie a double d = dd.doublevalue(); // d == 7.1 Aby uprościć powyższe przekształcenia, w Javie 5 wprowadzono mechanizm zwany autoboxingiem.

Opakowanie typów prostych - Autoboxing Autoboxing to automatyczne przekształcanie między typami prostymi a typami obiektów klas opakowujących typy proste. Przykład: int n = 1; Integer in = n; //boxing, czyli automatyczne opakowanie // warości typu prostego w nowy obiekt klasy (nie musimy // już pisać new Integer(n), robi to za nas kompilator) n = in + 1 //unboxing - automatyczne pobranie wartości typu // prostego z obiektu klasy opakowującej(nie musimy już // pisać in.intvalue() + 1) in += 5; //obiekty typów opakowujących są niemodyfikowalne // powstaje nowy obiekt Automatyczne przekształcenia autoboxing zachodzą nie tylko przy przypisaniach, ale również przy przekazywaniu argumentów metodom i konstruktorom oraz przy zwrocie wyników z metod. Np. metoda Arrays.asList(...), która ma zmienną liczbę argumentów typu referencyjnego, może być zastosowana tak: Arrays.asList(1,2,11,12,23,24), umożliwiając w ten sposób szybką inicjację elementów niemodyfikowalnej listy liczb całkowitych (typ Integer). 18

Opakowanie typów prostych - Autoboxing 19 Przy posługiwaniu się autoboxingiem należy zwrócić uwagę na możliwe przypadki wypakowania wartości typów prostych z nieistniejących obiektów klas opakowujących (gdy referencja na obiekt ma wartość null) Opakowywanie typów prostych zachodzi również przy przypisaniach na zmienne typu Object, np. Object o = 1; spowoduje stworzenie obiektu klasy Integer opakowującego liczbę 1, jednak wypakowanie nie jest już automatyczne, przy próbie podstawienia int x = o;// błąd wystąpi błąd kompilacji, należy użyć rzutowania int x = (Integer) o;// ok Autoboxing nie działa też na tablicach, niedopuszczalne jest przypisanie: int[] a = {1,2,3; Integer[] ia=a;// niedopuszczalne, ale Integer[] iaa={1,2,3; // jest OK - autoboxing

Klasy opakowujące - metody W klasach opakowujących typy pierwotne zdefiniowano statyczne metody: public static ttt parsettt(string s) zwracające wartości typu ttt reprezentowane przez napis s, gdzie: ttt nazwa typu pierwotnego (np. int, double), Ttt - ta sama nazwa z kapitalizowaną pierwszą literą (np. Int, Double) A więc, po to by przekształcić napis s reprezentujący liczbę rzeczywistą do typu double należy napisać: double d = Double.parseDouble(s); np. String s = "12.4"; double d = Double.parseDouble(s); // d == 12.4 Użytecznych dodatkowych metod dostarcza klasa Character (opakowująca typ char). Należą do nich metody stwierdzania rodzaju znaku: isdigit() // czy znak jest znakiem cyfry isletter() // czy znak jest znakiem litery isletterordigit() // czy litera lub cyfra iswhitespace() // czy to "biały" znak (spacja, // tabulacja etc.) isuppercase() // czy to wielka litera islowercase() // czy to mała litera Metody te zwracają wartości true lub false. 20

Klasy opakowujące - stałe W klasach opakowujących typy numeryczne zdefiniowano także wiele użytecznych stałych statycznych. Należą do nich stałe zawierające maksymalne i minimalne wartości danego typu. Mają one nazwy MAX_VALUE i MIN_VALUE. Dzięki temu nie musimy pamiętać zakresów wartości danego typu. Możemy np. zsumować wszystkie dodatnie liczby typu short: public class MaxVal { public static void main(string[] args) { long sum = 0; for (int i=1; i <= Short.MAX_VALUE; i++) sum += i; System.out.println(sum); //licznik i nie może być typu short, bo po dojściu do //Short.MAX_VALUE i zwiększeniu licznika o 1 i otrzyma //wartość Short.MIN_VALUE (arytmetyczne przepełnienie) //pętla nieskończona 21