Klasy wewnętrzne. Praktyka użycia interfejsów i klas wewnętrznych (c) Krzysztof Barteczko 2014
to klasa zdefiniowana wewnątrz innej klasy. Klasy wewnętrzne - definicja 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. (c) Krzysztof Barteczko 2014
Klasa wewnętrzna a otaczająca (c) Krzysztof Barteczko 2014
Właściwości klas wewnętrznych (c) Krzysztof Barteczko 2014
Po co są klasy wewnętrzne? (c) Krzysztof Barteczko 2014
(c) Krzysztof Barteczko 2014 Przykład (c) Krzysztof Barteczko 2014
(c) Krzysztof Barteczko 2014 Kod public class Car extends Vehicle { // ... private class FuelConsume implements ActionListener { @Override public void actionPerformed(ActionEvent e) { fuel -= 1; // odwolanie do pryw. składowej klasy otaczającej if (fuel == 0) stop(); } private Timer fuelTimer = new Timer(1000, new FuelConsume()); public Car start() { if (getState() == MOVING) return this; // nie można użyć start 2 razy pod rząd! if (fuel > 0) { super.start(); if (getState() == MOVING) // tylko jeśli udało się wystartować pojazd! fuelTimer.start(); // --- start Timera else error("Brak paliwa"); return this; public Car stop() { fuelTimer.stop(); super.stop(); public void crash(Vehicle v) { this.fuelTimer.stop(); if (v instanceof Car) ((Car) v).fuelTimer.stop(); super.crash(v); (c) Krzysztof Barteczko 2014
(c) Krzysztof Barteczko 2014 Test (c) Krzysztof Barteczko 2014
Odwołania do klasy wewnętrznej Odwołanie do widocznej (np. publicznej) klasy wewnętrznej: NazwaKlasyOtaczającej.NazwaKlasyWewnętrznej Tworzenie obiektu niestatycznej klasy wewnętrznej wymaga zawsze istnienia obiektu klasy otaczającej. (c) Krzysztof Barteczko 2014
Anonimowe klasy wewnętrzne (c) Krzysztof Barteczko 2014
Schematyczny przykład Record jakisRekord; //.... db.add(jakisRekord); (c) Krzysztof Barteczko 2014
Anonimowy FuelConsumer (c) Krzysztof Barteczko 2014
(c) Krzysztof Barteczko 2014 Uproszczenie Po co nam zmienna fuelConsumer? Przecież wszędzie tam, gdzie może wystąpić referencja może wystąpić wyrażenie new. Może zatem wystąpić jako drugi argument wyrażenia new, tworzacego timer. private Timer fuelTimer = new Timer(1000, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { fuel -= 1; if (fuel == 0) stop(); } }); (c) Krzysztof Barteczko 2014
Uwagi nt anonimowych klas wewnętrznych (c) Krzysztof Barteczko 2014
Lokalne klasy wenętrzne (c) Krzysztof Barteczko 2014
Java7 Przykład: wyszukiwanie plików Wobec katalogu można użyć metody listFiles z klasy File, która zwraca tablicę obiektów plikowych w nim zawartych. Używając metody listFiles z argumentem typu FileFilter możemy określić kryteria filtrowania wyniku według właściwości obiektów plikowych (np. otrzymać tylko listę plików o rozszerzeniu .java lub zmodyfikowanych po jakiejś dacie). FileFilter jest interfejsem, w którym zawarto jedną metodę boolean accept(File file). File dir = new File(...); Calendar c = Calendar.getInstance(); c.set(2013, 7, 22, 0, 0); final 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; } }); Java7 (c) Krzysztof Barteczko 2014
Java7 Parametry to też zmienne lokalne static File[] getFiles(String fromDir, final String ext, String afterDate) throws ParseException { final long time = new SimpleDateFormat("yyyy-MM-dd") .parse(afterDate) .getTime(); File[] files = new File(fromDir).listFiles( new FileFilter() { @Override public boolean accept(File f) { return f.isFile() && f.getName().endsWith(ext) && f.lastModified() >= time; } }); return files; (c) Krzysztof Barteczko 2014
Java8 Zmienne efektywnie finalne W Javie w wersji 8 wprowadzono wygodne pojęcie zmiennej efektywnie finalnej (effectively final). Jest to taka zmienna, co do której kompilator może stwierdzić, że nie zmienia ona swoich wartości (np. nie występuje z lewej strony przypisań). Dzięki temu osłabiono wymaganie na dostęp do zmiennych lokalnych z anonimowych klas wewnętrznych: takie zmienne nie muszą być już deklarowane ze specyfikatorem final, ale muszą być efektywnie finalne. static File[] getFiles(String fromDir, String ext, String afterDate) throws ParseException { long time = // ... File[] files = new File(fromDir).listFiles( new FileFilter() { @Override public boolean accept(File f) { return f.isFile() && f.getName().endsWith(ext) && f.lastModified() >= time; } }); return files; Java8 (c) Krzysztof Barteczko 2014
Praktyczna użyteczność interfejsów i klas wewnętrznych interfejsy kolekcyjne iterowalne obiekty niekolekcyjne wizytowanie drzew katalogowych (c) Krzysztof Barteczko 2014
w kategoriach interfejsów, a nie konkretnych klas Interfejsy kolekcyjne Klasy kolekcyjne w Javie implementują odpowiednie interfejsy. Na przykład: klasy ArrayList i LinkedList - interfejs List, klasy HashSet, LinkedHashSet i TreeSet - interfejs Set. Interfejsy określają dostępne operacje na wyznaczanych przez nie strukturach danych, a wybór implementacji zależy od potrzeb naszego programu (rózne implementacje mają rózne właściwości). Gdy nasz program tworzy konkretne obiekty klas kolekcyjnych, to zawsze musimy dokonać takiego wyboru. Ale ważną rzeczą jest, by wszelkie inne działania na kolekcjach wykonywać w kategoriach interfejsów, a nie konkretnych klas Zwiększa to uniwersalność kodu. (c) Krzysztof Barteczko 2014
(c) Krzysztof Barteczko 2014 Przykład (c) Krzysztof Barteczko 2014
(c) Krzysztof Barteczko 2014 Interfejs Iterable (c) Krzysztof Barteczko 2014
Iterowalne obiekty niekolekcyjne (c) Krzysztof Barteczko 2014
(c) Krzysztof Barteczko 2014 Realizacja class FromTo implements Iterable<Calendar> { private Calendar from = Calendar.getInstance(), to = Calendar.getInstance(); public FromTo(String fromString, String toString) { DateFormat df = new SimpleDateFormat("yyyy-MM-dd"); try { from.setTime(df.parse(fromString)); to.setTime(df.parse(toString)); } catch (ParseException exc) { throw new IllegalArgumentException(exc.getMessage()); } public Iterator<Calendar> iterator() { return new Iterator<Calendar>() { Calendar current = Calendar.getInstance(), next = Calendar.getInstance(); { current.setTime(from.getTime()); current.add(Calendar.DATE, -1); public boolean hasNext() { next.setTime(current.getTime()); next.add(Calendar.DATE, 1); return next.compareTo(to) <= 0; public Calendar next() { if (!hasNext()) throw new NoSuchElementException(); current.add(Calendar.DATE, 1); return current; }; W Javie 8 interfejs Iterator zawiera domyślną metodę remove(), więc nie trzeba jej implementować. (c) Krzysztof Barteczko 2014
Wizytowanie drzew katalogowych W klasie java.nio.file.Files znajdziemy użyteczną metodę statyczną: Path walkFileTree(Path startDir, FileVisitor visitor) która pozwala na rekurencyjne przeglądanie katalogów (poczynając od katalogu startDir) i wykonywanie operacji na ich elementach (plikach i podkatalogach). (c) Krzysztof Barteczko 2014
Metody interfejsu FileVisitor (c) Krzysztof Barteczko 2014
(c) Krzysztof Barteczko 2014 Wyniki wizytowania (c) Krzysztof Barteczko 2014
Przykład wizytowania drzewa katalogowego public class CountLines { private long count = 0; private PathMatcher matcher; private Path startDir; public CountLines(String startDir) { this.startDir = Paths.get(startDir); } public long of(String glob) throws IOException { matcher = FileSystems.getDefault().getPathMatcher("glob:*.java"); Files.walkFileTree(startDir, new SimpleFileVisitor<Path>() { public FileVisitResult visitFile(Path file, BasicFileAttributes a) { if (matcher.matches(file.getFileName())) { try { count += Files.readAllLines(file, Charset.defaultCharset()).size(); } catch (IOException exc) { System.out.println(exc); return FileVisitResult.CONTINUE; }); return count; public static void main(String[] args) throws IOException { long count = new CountLines("..").of("*.java"); System.out.println("Lines count: " + count); PathMatcher – regex lub glob SimpleFileVisitor daje standard, umozliwia wybór metod (c) Krzysztof Barteczko 2014
Pojęcie o lambda-wyrażeniach (c) Krzysztof Barteczko 2014
(c) Krzysztof Barteczko 2014 Lambda – przykład 1 (c) Krzysztof Barteczko 2014
(c) Krzysztof Barteczko 2014 Lambda – przykład 2 (c) Krzysztof Barteczko 2014