AWT och avancerad Java Johan Larsson Uppsala Universitet November 1999 [email protected] 1 Introduktion • Vad hände egentligen i FaceLab? • Hur ska projektets användargränssnitt programmeras? • Hur ska vi programmera Java så att programenheter (paket, klasser) blir välorganiserade? → hur blir objekt-orienterade program utökningsbara, korrekta, robusta … ? [email protected] 2 1 Överblick i Java • Vi använder package för att strukturera klasser. • Vi använder arv för att göra utökningar. • Vi använder interface-arv för att bestämma gränssnitt. (Ersätter multipel-arv och kan göra livet lite enklare.) • Vi använder skyddsmekanismerna public, private or protected för att gömma information. [email protected] 3 Package • Ett paket innehåller klasser och svarar mot en ”modul”. I filsystemet är ett paket oftast en katalog (kan dock vara i en speciell JARfil). • Paket hjälper oss att organisera koden. • Undviker namnkonflikter. [email protected] 4 2 Arv • Objekt-orienterade språk använder arv (inheritance) för att bilda relationer av typen: ”A är SuperA är SuperSuperA” • Arv innebär utbytbarhet (”principle of substitutability”). En klass kan bytas ut mot en valfri subklass. • Java tillåter en klass att ärva från endast en annan klass till skillnad från Eiffel. [email protected] 5 Interface-arv i Java • Ett interface är en klass där alla metoder är abstrakta. En klass kan implementera många interface men ärver endast från en annan klass. interface InterfaceA { void execute (); } class A extends SuperA implements InterfaceA { … } [email protected] 6 3 Skyddsmekanism • Private: syns inte utanför programenhetens paket. • Protected: endast synligt för subklasser. Används för att komma åt inre tillstånd på ett lite enklare sätt. • Public:del av programenhetens gränssnitt dvs tillgängliga för alla klienter. • Paketsynlig: om inget av private, protected eller public anges blir programenheten synlig inom paketet. Exempel: private String fInternalToMyself; protected void subclassesMayUseThis; public static void partOfMyInterface; [email protected] 7 Klassbiblioteket i Java applet awt io java event image EventObject LayoutManager lang EventListener util Enumeration Observer Klasserna är ordnade i paket (package) enligt ovan. T ex är java.util.EventListener en klass. [email protected] 8 4 GUI-komponenter i AWT • En AWT-komponent är något som kan visas på 2D-yta och med vilket användaren kan interagera. • Viktig relation för ett GUI: ”containment” = innehåller någonting • I AWT är detta subklasser till Container. [email protected] 9 Component extends Object setSize (int,int) - Ställer in storlek (pixel). getSize() - Returnerar storlek. setVisible (boolean) - Visar eller döljer. setForeground (Color), getForeground() setBackground, getBackground setFont(Font), getFont() repaint() - Schemalägg total omritning. - Rita om komponenten på yta paint (Graphics) addMouseListener (MouseListener) addKeyListener (KeyListener) [email protected] 10 5 AWT klasshierarki Object Component Button TextComponent Canvas Container Label List Scrollbar TextField TextArea Window Dialog Panel Frame [email protected] 11 Händelser i AWT (1) • Java genererar en händelse (event) varje gång muspekaren förflyttas, en tangent trycks, osv • Händelser är subklasser till EventObject • Det kan finnas många som lyssnar! [email protected] 12 6 Händelser i AWT (2) • Ett objekt måste “prenumerera” på händelser av intresse (kallas även en observer-observable relation). • FaceLab använder EventListener • Händelsen kommer från sin källa och når specifika EventListner-subklasser, t ex ActionListener eller AdjustmentListener. [email protected] 13 Händelser i AWT (3) • Klassen EventObject definierar en mycket användbar metod: Object getSource() – Returnerar objektet som orsakade händelsen. [email protected] 14 7 Händelser i AWT (4) • Utökningsbarhet: hur utfördes FaceLab? • Metoden adjustmentValueChanged() f rån interfacet AdjustmentListener överskrevs. • Det gick inte lika lätt med flera Scrollbar: vi behövde särskilja samma typ av händelser i samma metod. • Vi vill nå en lösning som ger utökningsbar kod. Alltså inte ett ”hemmahack”. • Lösning: Nästade Klasser. [email protected] 15 Exempel med händelser public class ColorBar extends Scrollbar implements AdjustmentListener { public ColorBar (Color c) { super (Scrollbar.VERTICAL, 40, 0, 0, 255); setBackground ©; addAdjustmentListener (this); } public void adjustmentValueChanged (AdjustmentEvent e) { // Lyssnar på sig själv } } [email protected] 16 8 Nästade Klasser • Klasser kan vara medlemmar i andra klasser! class EnclosingClass { ... class NestedClass { … } } • Nästade klasser löser problem med encapsulation: den nästade klassen kommer åt den yttre klassens medlemmar, även de som är deklarerade som private. [email protected] 17 Utan Nästade Klasser // An example with cluttered but valid code public class MyClass implements MouseListener { ... someObject.addMouseListener(this); ... /* Empty method definitions. */ public void mousePressed(MouseEvent e) { } public void mouseReleased(MouseEvent e) { } public void mouseEntered(MouseEvent e) { } public void mouseExited(MouseEvent e) { } public void mouseClicked(MouseEvent e) { } } • Svårt att utöka och mycket kod att skriva. [email protected] 18 9 Exempel med adapterklass • För att minska mängden kod introduceras adapterklasser, t ex MouseAdapter. // Less code but still a not extensible. public class MyClass extends MouseAdapter { ... someObject.addMouseListener(this); ... /* Override certain method definitions. */ public void mousePressed(MouseEvent e) { ... } } [email protected] 19 Exempel med nästade klasser • Vi vill ha en inre klass MouseAdapter som vi senare kan utöka. // An example of using an inner class public class MyClass extends Applet { ... someObject.addMouseListener(new MyAdapter()); ... class MyAdapter extends MouseAdapter { public void mouseClicked(MouseEvent e) { … } } } [email protected] 20 10 Z-ordning [email protected] 21 Layout-hantering (1) • Platformsoberoende placering av Component-objekt i Container-objekt (t ex knapp i fönster). • Ger oberoende skalning av fönster. • Viktigaste LayoutManager-subklasserna: – BorderLayout (kompassriktningar) – GridLayout (lägger komponenter i rutnät) – FlowLayout (vänster-höger eller upp-ner) [email protected] 22 11 Layout-hantering (2) • Container-klassernas metoder: setLayout (LayoutManager) add (Component), remove (Component) [email protected] 23 BorderLayout Panel P = new Panel(new BorderLayout()); // Notera att konstruktorn till Panel fick LayoutManager som parameter! p.add(“North”, new Label(“En liten rubrik”)); p.add(“South”, new Label(“Kuckeliku”)); [email protected] 24 12 GridLayout Panel P = new Panel(); // Skapa rutnät 4x4 med 3 pixel mellan varje ruta p.setLayout(new GridLayout (4,4,3,3)); p.add(new ColorButton(Color.black, ”black”)); p.add(new.ColorButton(Color.blue, ”blue”)); • Vad är Panel för klass? Vad ärver den ifrån? [email protected] 25 java.io • Många objektorienterade språk använder abstraktionen ”dataström” (stream) • Java har klasser InputStream och OutputStream i java.io. • En ström är något som kan matas med data eller som man kan hämta data från. [email protected] 26 13 InputStream och OutputStream [email protected] 27 Persistens i Java • java.io.Serializable - ”taggar klasser” • Persistens = lagra objekt i dataström så att det kan återskapas senare. • Möjliggör att objekt transporteras över Internet, lagras i filer, osv. • Grunden för distribuerade tekniker såsom CORBA, RMI, mm. [email protected] 28 14 Enkelt exempel på persistens FileOutputStream out = new FileOutputStream("theTime"); ObjectOutputStream s = new ObjectOutputStream(out); s.writeObject("Today"); s.writeObject(new Date()); s.flush(); [email protected] 29 Trådar i Java (1) • Trådar är lättviktsprocesser, dvs processor som kan exekvera parallelt med varandra inom ramen för ett programs normala sekventiella exekvering • java.lang.Thread • Anpassas med metoden run [email protected] 30 15 Trådar i Java (2) • Trådar fungerar olika bra beroende på platformens stöd. På vissa platformar måste man använda metoderna sleep och yield för att ge tid åt andra trådar, medan andra plattformar automatiskt delar upp exekveringstiden mellan trådar. • Hur gick det? [email protected] 31 Synkronisering av trådar • Trådar måste ofta synkronisera i samband med att delad data uppdateras eller kritiska uppgifter skall utföras. Annars kan vi få mycket konstiga resultat. • java.lang.Object har metoderna wait, notify och notifyAll • Syntaktiskt stöd: synchronized och volatile [email protected] 32 16 Att använda trådar • Två sätt att skapa trådar: – SomeProcess implements Runnable – SomeProcess extends Thread [email protected] 33 Exempel med Thread • Vi behöver bara överskriva metoden run public class SimpleThread extends Thread { public SimpleThread (String name) { super(name); } public void run () { for (int i = 0; i < 10; i++) { System.out.println(i + ” ” + getName()); try { sleep ((long)(Math.random() * 1000)); } catch (InterruptedException e) {} } System.out.println(”Done with ” + getName());L } n o } (fortsätter på nästa OH) [email protected] 34 17 Exempel med Thread public class TwoThreadsTest { public static void main (String[] args) { new SimpleThread (”Jamaica”).start(); new SimpleThread (”Fiji”).start(); } } 0 Jamaica 0 Fiji 1 Fiji 1 Jamaica 2 Jamaica ... [email protected] 35 Att använda Runnable 1. Skapa en klass som implementerar interfacet Runnable dvs tillhandahåll metoden run. 2. För att exekvera tråden skriv: new Thread (myRunnableObject) [email protected] 36 18 JGL, Collection Framework, STL • JGL innehåller datastrukturer och algoritmer med iteratorer, funktionsobjekt. • Standard Template Library är ett bibliotek för C++. Standardiserat bibliotek från vilket JGL lånar sina idéer. • Java 2 innehåller avancerade datastrukturer liknande dom i JGL (kallas Collection Framework) [email protected] 37 Datastrukturer i Java • Inbyggt i Java sedan tidigare versioner: Hashtable, Vector, Stack, BitSet i java.util Notera att Enumeration fungerar som Iterator i JGL. • Nytt för Java 2: Java Collections Framework • Vad ska användas? JGL rekommenderas i uppgiften men det går bra att använda Java 2 Collection Framwork. [email protected] 38 19 JGL exempel PriorityQueue queue = new PriorityQueue(); queue.push( new Integer( 5 ) ); Enumeration e = queue.elements(); while ( e.hasMoreElements() ) System.out.println( e.nextElement() ); while ( !queue.isEmpty() ) System.out.println( queue.pop() ); [email protected] 39 Iteratorer = generaliserad pekare (exempel från JGL) public class Test { public static void main (String [] args) { Array array = new Array(); array.add( "bat" ); array.add( "cat" ); System.out.println( "array = " + array ); ReverseIterator iterator = new ReverseIterator( array.end() ); while ( iterator.hasMoreElements() ) System.out.print( iterator.nextElement() + ” ” ); } } array = Array( bat, cat ) cat bat [email protected] 40 20 OrderedSet i JGL • OrderedSet är en associativ array med hjälp av ett röd-svart träd vilket medför O(lg N) på alla operationer. Metoden remove raderar alla element som matchar en viss nyckel. • Element identifieras med predikatet ”<” skickat som argument till konstruktorn. • a = b ⇔ !(a < b) and !(b < a) [email protected] 41 Exempel med Primtal (1) import java.util.*; class Sieve implements Enumeration { private BitSet primes; private int index = 2; // Datastruktur från java.util public Sieve (int n) { primes = new BitSet(n); for (int i = 1; i < n; i++) primes.set(i); // Sätt bitar // Ta bort delbara tal (sålla bort) for (int i = 2; i *i < n; i++) if (primes.get(i)) for (int j = i+i; j <= n; j+= i) primes.clear(j); } (fortsätter på nästa OH) [email protected] 42 21 Exempel med Primtal (2) ... public boolean hasMoreElements () { index++; int n = primes.size(); while (! primes.get(index)) if (++index > n) return false; return true; } public Object nextElement() { return new Integer (index); } public static void main (String [] args) { Sieve p = new Sieve (100); while (p.hasMoreElements()) System.out.println(p.nextElement()); } } [email protected] 43 Ytterligare exempel från JGL public class CopyingTest { public static void main( String[] args ) { int ints[] = { 2, 6, 3, 7 }; Vector vector = new Vector(); vector.addElement( new Integer( 1 ) ); vector.addElement( new Integer( 4 ) ); // Skapa en IntArray från arrayen ints. IntArray intArray = new IntArray( ints ); VectorArray vectorArray = new VectorArray( vector ); System.out.println( "before copying = " + vector ); Copying.copy( intArray, vectorArray ); System.out.println( "after copying = " + vector ); } } [email protected] 44 22 Några diskussionsfrågor • Behövs interface-arv? • Behövs nästade klasser (hur var det innan dom kom till i Java)? • Vad ska man tänka på då man konstruerar lite större Java program enligt denna lektion? [email protected] 45 Litteratur • Eckel, Thinking in Java, Prentice Hall, 1998. • Flanaga, Java in a Nutshell. O'Reilly & Associates, 1997. • Horstmann and Cornell, Core Java: Volume I Fundamentals, Prentice Hall 1997. • Horstmann and Cornell, Core Java: Volume II Advanced Features, Prentice Hall 1997. • Budd, Understanding Object-Oriented Progrmaming with Java, Addison-Wesley, 1998. [email protected] 46 23