Nästan alla Swing-komponenter är dubbelbuffrade som default. Det går att stänga av:
Man kan till exempel få det animerade cirkeldiagrammet i programmet Grafikdemo6.java från föreläsning 11 att flimra lite.RepaintManager currentManager = RepaintManager.currentManager(komponenten); currentManager.setDoubleBufferingEnabled(false);
I AWT var man tvungen att göra dubbelbuffringen själv.
I Java:
Klassen Point har en "normal" equals-metod, som uppfyller kraven. Programmet EqualsExample.java:
Utmatning:class Point { private final int x, y; public Point(int x, int y) { this.x = x; this.y = y; } public boolean equals(Object o) { if (!(o instanceof Point)) return false; Point p = (Point)o; return this.x == p.x && this.y == p.y; } } // class Point public class EqualsExample { public static void main(String[] args) { // Repetition av hur metoden "equals" fungerar Point p1 = new Point(1, 2); Point p2 = new Point(1, 2); Point p3 = new Point(1, 2); Point p4 = new Point(3, 3); System.out.println("*** Repetition av hur metoden \"equals\" fungerar"); System.out.println("p1 == p2: " + (p1 == p2)); System.out.println("p1.equals(p2): " + (p1.equals(p2))); System.out.println("p1.equals(p4): " + (p1.equals(p4))); // Fem grundregler som bör uppfyllas för likhet ("equals" i Java) // 1. Reflexivitet: x = x (läs "=" som matematikens "lika med") // I Java motsvaras detta av: x.equals(x) System.out.println("*** 1. Reflexivitet: x = x (läs \"=\" som \"lika med\")"); System.out.println("p1.equals(p1): " + (p1.equals(p1))); // 2. Symmetri: om x = y <==> y = x // I Java motsvaras detta av: x.equals(y) <==> y.equals(x) System.out.println("*** 2. Symmetri: om x = y <==> y = x"); System.out.println("p1.equals(p2): " + (p1.equals(p2))); System.out.println("p2.equals(p1): " + (p2.equals(p1))); System.out.println("p1.equals(p4): " + (p1.equals(p4))); System.out.println("p4.equals(p1): " + (p4.equals(p1))); // 3. Transitivitet: x = y och y = z <==> x = z // I Java motsvaras detta av: // x.equals(y) och y.equals(z) <==> x.equals(z) System.out.println("*** 3. Transitivitet: x = y och y = z <==> x = z"); System.out.println("p1.equals(p2): " + (p1.equals(p2))); System.out.println("p2.equals(p3): " + (p2.equals(p3))); System.out.println("p1.equals(p3): " + (p1.equals(p3))); // 4. Konsekvens: samma jämförelse ska ge samma resultat varje gång // (om inte objekten har ändrats!) // I Java motsvaras detta av: // x.equals(y) ska ge samma resultat varje gång System.out.println("*** 4. Konsekvens: samma jämförelse ska ge samma resultat varje gång"); System.out.println("p1.equals(p2): " + (p1.equals(p2))); System.out.println("p1.equals(p2): " + (p1.equals(p2))); // 5. null är unik, dvs x != null för alla x utom null // I Java motsvaras detta av: // x.equals(null) ska ge false för varje x som inte är null System.out.println("*** 5. null är unik, dvs x != null för alla x utom null"); System.out.println("p1.equals(null): " + (p1.equals(null))); } } // class EqualsExample
Vi använder den enkla mängdklassen SimpleSet för att visa hur equals kan användas inuti en behållare. (Senare ska vi också se vad som händer i SimpleSet när den innehåller objekt som har en osymmetrisk equals-metod.)*** Repetition av hur metoden "equals" fungerar p1 == p2: false p1.equals(p2): true p1.equals(p4): false *** 1. Reflexivitet: x = x (läs "=" som "lika med") p1.equals(p1): true *** 2. Symmetri: om x = y <==> y = x p1.equals(p2): true p2.equals(p1): true p1.equals(p4): false p4.equals(p1): false *** 3. Transitivitet: x = y och y = z <==> x = z p1.equals(p2): true p2.equals(p3): true p1.equals(p3): true *** 4. Konsekvens: samma jämförelse ska ge samma resultat varje gång p1.equals(p2): true p1.equals(p2): true *** 5. null är unik, dvs x != null för alla x utom null p1.equals(null): false
Notera att klassen SimpleSet har en main-metod som testkör klassen! Bra programmeringsmetodik: Testa varje klass för sig!
Programmet SimpleSet.java:
Utmatning:// Must compile with "javac -source 1.4 SimpleSet.java" class SimpleSetFullException extends Exception { } public class SimpleSet { final int MAX_MEMBERS = 3; Object[] content = new Object[MAX_MEMBERS]; public boolean contains(Object o) { for (int i = 0; i < MAX_MEMBERS; ++i) if (content[i] != null && content[i].equals(o)) return true; return false; } boolean add(Object o) throws SimpleSetFullException { if (contains(o)) return false; for (int i = 0; i < MAX_MEMBERS; ++i) { if (content[i] == null) { content[i] = o; return true; } } throw new SimpleSetFullException(); } public static void main(String[] args) { System.out.println("Testing SimpleSet"); SimpleSet s = new SimpleSet(); Point p1 = new Point(1, 2); Point p2 = new Point(2, 3); Point p3 = new Point(3, 4); Point p4 = new Point(4, 5); Point p5 = new Point(1, 2); assert s.contains(p1) == false; assert s.contains(p2) == false; assert s.contains(p3) == false; assert s.contains(p4) == false; assert s.contains(p5) == false; try { assert s.add(p1) == true; assert s.add(p1) == false; } catch (SimpleSetFullException ssfe) { assert false; } assert s.contains(p1) == true; assert s.contains(p2) == false; assert s.contains(p3) == false; assert s.contains(p4) == false; assert s.contains(p5) == true; try { assert s.add(p2) == true; assert s.add(p2) == false; } catch (SimpleSetFullException ssfe) { assert false; } assert s.contains(p1) == true; assert s.contains(p2) == true; assert s.contains(p3) == false; assert s.contains(p4) == false; assert s.contains(p5) == true; try { assert s.add(p3) == true; assert s.add(p3) == false; } catch (SimpleSetFullException ssfe) { assert false; } assert s.contains(p1) == true; assert s.contains(p2) == true; assert s.contains(p3) == true; assert s.contains(p4) == false; assert s.contains(p5) == true; try { s.add(p4); assert false; } catch (SimpleSetFullException ssfe) { } assert s.contains(p1) == true; assert s.contains(p2) == true; assert s.contains(p3) == true; assert s.contains(p4) == false; assert s.contains(p5) == true; System.out.println("SimpleSet ok"); } } // class SimpleSet
Testing SimpleSet SimpleSet ok
Klassen CaseInsensitiveString ärver (dvs utökar, extends) klassen String: En CaseInsensitiveString är en String som inte bryr sig om stora och små bokstäver. Exempelvis ska "apa" vara lika med "Apa", om det är två CaseInsensitiveString som jämförs.
Men vad händer när en CaseInsensitiveString jämförs med en vanlig String? Vi försöker göra även den jämförelsen så att den inte bryr sig om stora och små bokstäver.
Programmet SymmetryExample.java:
Utmatning:class CaseInsensitiveString { private String content; public CaseInsensitiveString(String string) { this.content = string; } public boolean equals(Object o) { if (o instanceof CaseInsensitiveString) { CaseInsensitiveString cis = (CaseInsensitiveString)o; return content.equalsIgnoreCase(cis.content); } else if (o instanceof String) { /* Bad part */ String s = (String)o; return content.equalsIgnoreCase(s); } else return false; } } // class CaseInsensitiveString public class SymmetryExample { public static void main(String[] args) throws SimpleSetFullException { CaseInsensitiveString s1 = new CaseInsensitiveString("hej"); String s2 = "Hej"; System.out.println("s1.equals(s2): " + (s1.equals(s2))); // true System.out.println("s2.equals(s1): " + (s2.equals(s1))); // false! SimpleSet set1 = new SimpleSet(); set1.add(s1); System.out.println("set1.contains(s1): " + set1.contains(s1)); // true System.out.println("set1.contains(s2): " + set1.contains(s2)); // true SimpleSet set2 = new SimpleSet(); set2.add(s2); System.out.println("set2.contains(s2): " + set2.contains(s2)); // true System.out.println("set2.contains(s1): " + set2.contains(s1)); // false! } } // class SymmetryExample
s1.equals(s2): true s2.equals(s1): false set1.contains(s1): true set1.contains(s2): true set2.contains(s2): true set2.contains(s1): false
Klassen ColorPoint ärver (dvs utökar, extends) klassen Point: En ColorPoint är en Point som har en färg.
Först låter vi bli att definiera en egen equals-metod i ColorPoint. Då används equals-metoden i Point.
Delar av programmet TransitivityExample1.java:
Utmatning:import java.awt.Color; class ColorPoint extends Point { final private Color color; public ColorPoint(int x, int y, Color color) { super(x, y); this.color = color; } } // class ColorPoint public class TransitivityExample1 { public static void main(String[] args) throws SimpleSetFullException { ColorPoint cp1 = new ColorPoint(1, 2, Color.RED); ColorPoint cp2 = new ColorPoint(1, 2, Color.RED); ColorPoint cp3 = new ColorPoint(1, 2, Color.BLUE); ColorPoint cp4 = new ColorPoint(3, 3, Color.GREEN); System.out.println("cp1.equals(cp2): " + cp1.equals(cp2)); // true System.out.println("cp1.equals(cp3): " + cp1.equals(cp3)); // true! System.out.println("cp1.equals(cp4): " + cp1.equals(cp4)); // false } // main } // class TransitivityExample1
Den tyckte alltså att en röd punkt i (1, 2) var lika med en blå punkt i (1, 2). Vi försöker göra en equals som hanterar jämförelser med ColorPoint-objekt, så två olikfärgade punkter inte blir lika!cp1.equals(cp2): true cp1.equals(cp3): true cp1.equals(cp4): false
Ur programmet TransitivityExample2.java:
Utmatning:class ColorPoint extends Point { final private Color color; public ColorPoint(int x, int y, Color color) { super(x, y); this.color = color; } public boolean equals(Object o) { if (!(o instanceof ColorPoint)) return false; ColorPoint cp = (ColorPoint)o; return super.equals(o) && this.color == cp.color; } } // class ColorPoint public class TransitivityExample2 { public static void main(String[] args) throws SimpleSetFullException { ColorPoint cp1 = new ColorPoint(1, 2, Color.RED); ColorPoint cp2 = new ColorPoint(1, 2, Color.RED); ColorPoint cp3 = new ColorPoint(1, 2, Color.BLUE); ColorPoint cp4 = new ColorPoint(3, 3, Color.GREEN); System.out.println("cp1.equals(cp2): " + cp1.equals(cp2)); // true System.out.println("cp1.equals(cp3): " + cp1.equals(cp3)); // false System.out.println("cp1.equals(cp4): " + cp1.equals(cp4)); // false Point p1 = new Point(1, 2); System.out.println("cp1.equals(p1): " + cp1.equals(p1)); // false! System.out.println("p1.equals(cp1): " + p1.equals(cp1)); // true! } // main } // class TransitivityExample2
Ok, nu är en blå punkt inte lika med en röd punkt i samma position.cp1.equals(cp2): true cp1.equals(cp3): false cp1.equals(cp4): false cp1.equals(p1): false p1.equals(cp1): true
Jämförelserna är alltså osymmetriska:
Ur programmet TransitivityExample3.java:
Utmatning:class ColorPoint extends Point { final private Color color; public ColorPoint(int x, int y, Color color) { super(x, y); this.color = color; } public boolean equals(Object o) { if (o instanceof ColorPoint) { ColorPoint cp = (ColorPoint)o; return super.equals(o) && this.color == cp.color; } else if (o instanceof Point) return o.equals(this); else return false; } } // class ColorPoint public class TransitivityExample3 { public static void main(String[] args) throws SimpleSetFullException { ColorPoint cp1 = new ColorPoint(1, 2, Color.RED); ColorPoint cp2 = new ColorPoint(1, 2, Color.RED); ColorPoint cp3 = new ColorPoint(1, 2, Color.BLUE); ColorPoint cp4 = new ColorPoint(3, 3, Color.GREEN); System.out.println("cp1.equals(cp2): " + cp1.equals(cp2)); // true System.out.println("cp1.equals(cp3): " + cp1.equals(cp3)); // false System.out.println("cp1.equals(cp4): " + cp1.equals(cp4)); // false Point p1 = new Point(1, 2); System.out.println("cp1.equals(p1): " + cp1.equals(p1)); // true System.out.println("p1.equals(cp1): " + p1.equals(cp1)); // true System.out.println("cp1.equals(p1): " + cp1.equals(p1)); // true System.out.println("p1.equals(cp3): " + p1.equals(cp3)); // true System.out.println("cp1.equals(cp3): " + cp1.equals(cp3)); // false! } // main } // class TransitivityExample3
Ajaj! Nu är jämförelsen symmetrisk, men inte transitiv!cp1.equals(cp2): true cp1.equals(cp3): false cp1.equals(cp4): false cp1.equals(p1): true p1.equals(cp1): true cp1.equals(p1): true p1.equals(cp3): true cp1.equals(cp3): false
Allmänt i objektorientering: Det går inte att utöka en klass (som Point) med en aspekt (som färg), och få jämförelser mellan objekt från bas- och subklassen att bli både symmetriska och transitiva.
Lösning: Låt bli att ärva. Använd komposition i stället för arv, och gör en klass ColorPoint som inte ärver utan bara innehåller en Point.
Ur programmet TransitivityExample4.java:
Utmatning:class ColorPoint { final private Point point; final private Color color; public ColorPoint(int x, int y, Color color) { point = new Point(x, y); this.color = color; } public Point asPoint() { return point; } public boolean equals(Object o) { if (!(o instanceof ColorPoint)) return false; ColorPoint cp = (ColorPoint)o; return this.point.equals(cp.point) && this.color == cp.color; } } // class ColorPoint public class TransitivityExample4 { public static void main(String[] args) throws SimpleSetFullException { ColorPoint cp1 = new ColorPoint(1, 2, Color.RED); ColorPoint cp2 = new ColorPoint(1, 2, Color.RED); ColorPoint cp3 = new ColorPoint(1, 2, Color.BLUE); ColorPoint cp4 = new ColorPoint(3, 3, Color.GREEN); System.out.println("cp1.equals(cp2): " + cp1.equals(cp2)); // true System.out.println("cp1.equals(cp3): " + cp1.equals(cp3)); // false System.out.println("cp1.equals(cp4): " + cp1.equals(cp4)); // false Point p1 = new Point(1, 2); System.out.println("cp1.equals(p1): " + cp1.equals(p1)); // false! System.out.println("p1.equals(cp1): " + p1.equals(cp1)); // false! System.out.println("cp1.equals(p1): " + cp1.equals(p1)); // false! System.out.println("p1.equals(cp3): " + p1.equals(cp3)); // false! System.out.println("cp1.equals(cp3): " + cp1.equals(cp3)); // false! } // main } // class TransitivityExample4
Nu är Point och ColorPoint helt olika saker, och om man jämför en Point och en ColorPoint är de aldrig lika.cp1.equals(cp2): true cp1.equals(cp3): false cp1.equals(cp4): false cp1.equals(p1): false p1.equals(cp1): false cp1.equals(p1): false p1.equals(cp3): false cp1.equals(cp3): false
Lärdomar:
Programmet SecurityManagerTest.java:
Körexempel 1:import java.io.*; public class SecurityManagerTest { public static void main(String[] args) throws Exception { BufferedReader stdin = new BufferedReader( new InputStreamReader(System.in)); try { System.setSecurityManager( new PasswordSecurityManager("gazonk", stdin)); } catch (SecurityException se) { System.err.println("SecurityManager already set!"); } BufferedReader in = new BufferedReader(new FileReader("in.txt")); PrintWriter out = new PrintWriter(new FileWriter("out.txt")); String inputString; while ((inputString = in.readLine()) != null) out.println(inputString); in.close(); out.close(); } }
Körexempel 2:Password: gazonk Password: gazonk
Programmet PasswordSecurityManager.java:Password: gabonk Exception in thread "main" java.lang.SecurityException: No Way! at PasswordSecurityManager.checkRead(PasswordSecurityManager.java:35) at java.io.FileInputStream.(FileInputStream.java:100) at java.io.FileInputStream. (FileInputStream.java:66) at java.io.FileReader. (FileReader.java:41) at SecurityManagerTest.main(SecurityManagerTest.java:17)
import java.io.*; public class PasswordSecurityManager extends SecurityManager { private String password; private BufferedReader stdin; public PasswordSecurityManager(String p, BufferedReader b) { super(); this.password = p; this.stdin = b; } private boolean accessOK() { String response; System.out.print("Password: "); try { response = stdin.readLine(); if (response.equals(password)) return true; else return false; } catch (IOException e) { return false; } } public void checkRead(FileDescriptor filedescriptor) { if (!accessOK()) throw new SecurityException("Not a Chance!"); } public void checkRead(String filename) { if (!accessOK()) throw new SecurityException("No Way!"); } public void checkRead(String filename, Object executionContext) { if (!accessOK()) throw new SecurityException("Forget It!"); } public void checkWrite(FileDescriptor filedescriptor) { if (!accessOK()) throw new SecurityException("Not!"); } public void checkWrite(String filename) { if (!accessOK()) throw new SecurityException("Not Even!"); } } // PasswordSecurityManager
Utmatning:import java.io.*; import java.util.*; class Data implements Serializable { private int n; public Data(int n) { this.n = n; } public String toString() { return Integer.toString(n); } } // class Data public class SerializationTest { public static void main(String[] args) throws ClassNotFoundException, IOException { Data d1 = new Data(17); Data d2 = new Data(4711); Data d3 = new Data(7); System.out.println("d1 = " + d1); System.out.println("d2 = " + d2); System.out.println("d3 = " + d3); ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("data.out")); out.writeObject(d1); out.writeObject(d2); out.writeObject(d3); out.close(); // Also flushes output ObjectInputStream in = new ObjectInputStream(new FileInputStream("data.out")); Data d4 = (Data)in.readObject(); Data d5 = (Data)in.readObject(); Data d6 = (Data)in.readObject(); System.out.println("d4 = " + d4); System.out.println("d5 = " + d5); System.out.println("d6 = " + d6); } } // class SerializationTest
Filen data.out innehåller 53 bytes. Decimal utskrift:d1 = 17 d2 = 4711 d3 = 7 d4 = 17 d5 = 4711 d6 = 7
Som tecken:172 237 0 5 115 114 0 4 68 97 116 97 187 52 26 19 141 248 164 9 2 0 1 73 0 1 110 120 112 0 0 0 17 115 113 0 126 0 0 0 0 18 103 115 113 0 126 0 0 0 0 0 7
Programmet WormTest.java (fritt efter Bruce Eckels Thinking in Java, 3rd Ed):¬ í \0 005 s r \0 004 D a t a » 4 032 023 215 ø ¤ \t 002 \0 001 I \0 001 n x p \0 \0 \0 021 s q \0 ~ \0 \0 \0 \0 022 g s q \0 ~ \0 \0 \0 \0 \0 \a
Utmatning:import java.io.*; import java.util.*; class Data implements Serializable { private int n; public Data(int n) { this.n = n; } public String toString() { return Integer.toString(n); } } // class Data class Worm implements Serializable { private static Random rand = new Random(); private Data[] d = { new Data(rand.nextInt(10)), new Data(rand.nextInt(10)), new Data(rand.nextInt(10)) }; private Worm next; private char c; public Worm(int nr_segments, char x) { System.out.println("Worm constructor: " + nr_segments); c = x; if (--nr_segments > 0) next = new Worm(nr_segments, (char)(x + 1)); } public Worm() { System.out.println("Default constructor"); } public String toString() { String s = ":" + c + "("; for (int i = 0; i < d.length; i++) s += d[i]; s += ")"; if (next != null) s += next; return s; } } // class Worm public class WormTest { public static void main(String[] args) throws ClassNotFoundException, IOException { Worm w = new Worm(6, 'a'); System.out.println("w = " + w); ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("worm.out")); out.writeObject("Worm storage\n"); out.writeObject(w); out.close(); // Also flushes output ObjectInputStream in = new ObjectInputStream(new FileInputStream("worm.out")); String s = (String)in.readObject(); Worm w2 = (Worm)in.readObject(); System.out.println(s + "w2 = " + w2); ByteArrayOutputStream bout = new ByteArrayOutputStream(); ObjectOutputStream out2 = new ObjectOutputStream(bout); out2.writeObject("Worm storage\n"); out2.writeObject(w); out2.flush(); ObjectInputStream in2 = new ObjectInputStream(new ByteArrayInputStream(bout.toByteArray())); s = (String)in2.readObject(); Worm w3 = (Worm)in2.readObject(); System.out.println(s + "w3 = " + w3); } } // class WormTest
Worm constructor: 6 Worm constructor: 5 Worm constructor: 4 Worm constructor: 3 Worm constructor: 2 Worm constructor: 1 w = :a(839):b(652):c(246):d(663):e(468):f(373) Worm storage w2 = :a(839):b(652):c(246):d(663):e(468):f(373) Worm storage w3 = :a(839):b(652):c(246):d(663):e(468):f(373)