Fråga:
En synpunkt på vad du gärna får repetera för min del.Kom ihåg programmet PresenterTask.java från föreläsning 10. Det använder en java.util.Timer för att köra en viss metod vid vissa tidpunkter.
- Jag har inte riktigt koll på hur man implementerar egna gränssnitt, och du får gärna reda ut begreppet gränssnitt i Java-sammanhang.
- Abstrakta klasser. Vet inte om det är något vi ska kunna men det är ju något som förkommer. Jag har inte riktigt greppat vad det är.
Låt oss göra vår egen timer-klass!
Första försöket, DåligTajmer.java:
Hur vet man att det där objektet (av den mest generella klassen, Object) överhuvudtaget har någon metod som heter utförUppgiften?public class DåligTajmer { final private Object uppgiften; final private double väntetid; final private VäntansTråd tråden; public DåligTajmer(Object u, double väntetid) { uppgiften = u; this.väntetid = väntetid; tråden = new VäntansTråd(); tråden.start(); } // DåligTajmer private class VäntansTråd extends Thread { public void run() { try { Thread.sleep((int)(väntetid * 1000)); uppgiften.utförUppgiften(); } catch (InterruptedException e) { // Ja, vad ska man göra nu då? } } } // class VäntansTråd } // class DåligTajmer
Det vet man inte. I en del språk (som Pike) skulle detta fungera, och det kollas när programmet körs. Om det då visar sig att objektet tillhör en klass som inte har någon utförUppgiften-metod, uppstår ett fel, som signaleras på något sätt: undantag kastas, programmet kraschar, anropet returnerar 0...
Java kontrollerar redan vid kompileringen, och man får ett kompileringsfel:
Det är för det mesta bäst att upptäcka felen så tidigt som möjligt!DåligTajmer.java:17: cannot resolve symbol symbol : method utförUppgiften () location: class java.lang.Object uppgiften.utförUppgiften(); ^ 1 error
Skapa ett gränssnitt (=interface), som enbart säger att de klasser som förverkligar (=implementerar) det här gränssnittet ska ha en metod som heter utförUppgiften, som inte tar några argument, och som inte returnerar några värden:
Gränssnittet Tajmeruppgift.java:
public interface Tajmeruppgift { public void utförUppgiften(); } // interface Tajmeruppgift
Byt ut Object i DåligTajmer.java mot Tajmeruppgift, vilket ger programmet Tajmer.java:
Utvikning: Det hade fungerat (nästan) lika bra med en abstrakt klass: abstract public class Tajmeruppgift { abstract public void utförUppgiften(); } // class Tajmeruppgift
Provkör tajmerklassen Tajmer med programmet Tajmertest1.java:public class Tajmer { final private Tajmeruppgift uppgiften; final private double väntetid; final private VäntansTråd tråden; public Tajmer(Tajmeruppgift u, double väntetid) { uppgiften = u; this.väntetid = väntetid; tråden = new VäntansTråd(); tråden.start(); } // Tajmer private class VäntansTråd extends Thread { public void run() { try { Thread.sleep((int)(väntetid * 1000)); uppgiften.utförUppgiften(); } catch (InterruptedException e) { // Ja, vad ska man göra nu då? } } } // class VäntansTråd } // class Tajmer
class SkrivLite implements Tajmeruppgift { public void utförUppgiften() { System.out.println("Nu har det gått fem sekunder!"); } } // class SkrivLite public class Tajmertest1 { public static void main(String[] args) { Tajmer t = new Tajmer(new SkrivLite(), 5.0); System.out.println("Klar med main."); } // main } // class Tajmertest1
Utskrift:
Utvikning: Om Tajmeruppgift hade varit en abstrakt klass i stället för ett gränssnitt, hade vi fått byta ut implements Tajmeruppgift mot extends Tajmeruppgift.
Programmet Tajmertest3.java klarar sig utan en särskild Tajmeruppgift-klass:Klar med main. (följt av en paus i fem sekunder) Nu har det gått fem sekunder! (och sen avslutas programmet)
Programmet Tajmertest4.java klarar sig också utan en särskild Tajmeruppgift-klass:public class Tajmertest3 implements Tajmeruppgift { public void utförUppgiften() { System.out.println("Nu har det gått fem sekunder!"); } private Tajmertest3() { Tajmer t = new Tajmer(this, 5.0); } public static void main(String[] args) { Tajmertest3 t = new Tajmertest3(); System.out.println("Klar med main."); } // main } // class Tajmertest3
Programmet Tajmertest6.java är en applet:public class Tajmertest4 { private Tajmertest4() { Tajmer t = new Tajmer(new Tajmeruppgift() { public void utförUppgiften() { System.out.println("Nu har det gått fem sekunder!"); } }, 5.0); } // Tajmertest4 public static void main(String[] args) { Tajmertest4 t = new Tajmertest4(); System.out.println("Klar med main."); } // main } // class Tajmertest4
Det här hade inte fungerat om Tajmeruppgift hade varit en abstrakt klass!
Appleten Tajmertest6, fem sekunder efter knapptryckning:// <applet code="Tajmertest6" width="400" height="200"> // </applet> import java.awt.*; import java.awt.event.*; import javax.swing.*; public class Tajmertest6 extends JApplet implements Tajmeruppgift { private JTextArea textarean = new JTextArea(10, 30); private JButton knappen = new JButton("5-sekundersknappen"); private void log(String s) { textarean.append(s + "\n"); textarean.setCaretPosition(textarean.getDocument().getLength()); } private void startaTajmern() { Tajmer t = new Tajmer(this, 5.0); } public void init() { log("Nu körs metoden init."); Container cp = getContentPane(); cp.setLayout(new BorderLayout()); cp.add(BorderLayout.CENTER, new JScrollPane(textarean)); cp.add(BorderLayout.SOUTH, knappen); knappen.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { log("Nu tryckte du på knappen."); try { startaTajmern(); } catch (Exception e) { log("Fångat: " + e); } } // actionPerformed }); } public void utförUppgiften() { javax.swing.SwingUtilities.invokeLater(new Runnable() { public void run() { log("Nu har det gått fem sekunder!"); } }); } public static void main(String[] args) { JApplet applet = new Tajmertest6(); JFrame frame = new JFrame("Tajmertest6"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.getContentPane().add(applet); frame.setSize(300, 200); applet.init(); frame.setVisible(true); } // main } // class Tajmertest6
Utskrifter:import java.util.*; import java.text.*; public class Datumtest { public static void main(String[] args) { // Klassen Date Date nu = new Date(); // Milliseconds since January 1, 1970, 00:00:00 GMT Date start = new Date(0); Date biljon = new Date(1000000000000L); System.out.println("nu = " + nu); System.out.println("start = " + start); System.out.println("biljon = " + biljon); // Klassen TimeZone TimeZone dtz = TimeZone.getDefault(); System.out.println("dtz = " + dtz); String[] ids = TimeZone.getAvailableIDs(); System.out.println("Det finns " + ids.length + " tidszoner:"); for (int i = 0; i < ids.length; ++i) System.out.println(" " + i + ". " + ids[i]); TimeZone tokyo = TimeZone.getTimeZone("Asia/Tokyo"); TimeZone.setDefault(tokyo); System.out.println("nu = " + nu); TimeZone.setDefault(dtz); System.out.println("nu = " + nu); // Klassen Calendar Calendar c = Calendar.getInstance(); System.out.println("c = " + c); Calendar ct = Calendar.getInstance(tokyo); System.out.println("ct = " + ct); System.out.println("Veckonummer (locale-dependent!): " + c.get(Calendar.WEEK_OF_YEAR)); System.out.println("År: " + c.get(Calendar.YEAR)); System.out.println("Månad: " + c.get(Calendar.MONTH)); System.out.println("Dag: " + c.get(Calendar.DAY_OF_MONTH)); System.out.println("Timmar: " + c.get(Calendar.HOUR_OF_DAY)); System.out.println("Timmar (0-12): " + c.get(Calendar.HOUR)); System.out.println("Minuter: " + c.get(Calendar.MINUTE)); System.out.println("Sekunder: " + c.get(Calendar.SECOND)); System.out.println("Millisekunder: " + c.get(Calendar.MILLISECOND)); System.out.println("Tokyo 1: " + ct.get(Calendar.HOUR_OF_DAY) + ":" + ct.get(Calendar.MINUTE)); ct.setTimeZone(dtz); System.out.println("Tokyo 2: " + ct.get(Calendar.HOUR_OF_DAY) + ":" + ct.get(Calendar.MINUTE)); ct.setTime(biljon); System.out.println("Tokyo 3: " + ct.get(Calendar.HOUR_OF_DAY) + ":" + ct.get(Calendar.MINUTE)); ct.add(Calendar.MINUTE, 99); System.out.println("Tokyo 4: " + ct.get(Calendar.HOUR_OF_DAY) + ":" + ct.get(Calendar.MINUTE)); // Klassen DateFormat DateFormat f1 = DateFormat.getInstance(); DateFormat f2 = DateFormat.getTimeInstance(); DateFormat f3 = DateFormat.getDateInstance(); DateFormat f4 = DateFormat.getDateInstance(DateFormat.SHORT); DateFormat f5 = DateFormat.getDateInstance(DateFormat.MEDIUM); DateFormat f6 = DateFormat.getDateInstance(DateFormat.LONG); DateFormat f7 = DateFormat.getDateInstance(DateFormat.FULL); DateFormat f8 = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG); System.out.println("f1.format(nu) = " + f1.format(nu)); System.out.println("f2.format(nu) = " + f2.format(nu)); System.out.println("f3.format(nu) = " + f3.format(nu)); System.out.println("f4.format(nu) = " + f4.format(nu)); System.out.println("f5.format(nu) = " + f5.format(nu)); System.out.println("f6.format(nu) = " + f6.format(nu)); System.out.println("f7.format(nu) = " + f7.format(nu)); System.out.println("f8.format(nu) = " + f8.format(nu)); // Lokala konventioner Locale[] locales = Calendar.getAvailableLocales(); System.out.println("Det finns " + locales.length + " locales:"); for (int i = 0; i < locales.length; ++i) System.out.println(" " + i + ". " + locales[i]); Locale dl = Locale.getDefault(); System.out.println("dl = " + dl); Locale sverige = new Locale("sv", "SE"); Locale.setDefault(sverige); DateFormat f9 = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG); System.out.println("f9.format(nu) = " + f9.format(nu)); } } // class Datumtest
(Utvecklingen går framåt: 2003 fanns det bara 558 tidszoner och 134 locales.)nu = Sat Dec 15 21:04:33 CET 2007 start = Thu Jan 01 01:00:00 CET 1970 biljon = Sun Sep 09 03:46:40 CEST 2001 dtz = sun.util.calendar.ZoneInfo[id="Europe/Stockholm",offset=3600000,dstSavings=3600000,useDaylight=true,transitions=119,lastRule=java.util.SimpleTimeZone[id=Europe/Stockholm,offset=3600000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=2,startMonth=2,startDay=-1,startDayOfWeek=1,startTime=3600000,startTimeMode=2,endMode=2,endMonth=9,endDay=-1,endDayOfWeek=1,endTime=3600000,endTimeMode=2]] Det finns 592 tidszoner: 0. Etc/GMT+12 1. Etc/GMT+11 2. MIT 3. Pacific/Apia ... 589. Pacific/Kiritimati 590. America/Indiana/Petersburg 591. America/Indiana/Vincennes nu = Sun Dec 16 05:04:33 JST 2007 nu = Sat Dec 15 21:04:33 CET 2007 c = java.util.GregorianCalendar[time=1197749073209,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="Europe/Stockholm",offset=3600000,dstSavings=3600000,useDaylight=true,transitions=119,lastRule=java.util.SimpleTimeZone[id=Europe/Stockholm,offset=3600000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=2,startMonth=2,startDay=-1,startDayOfWeek=1,startTime=3600000,startTimeMode=2,endMode=2,endMonth=9,endDay=-1,endDayOfWeek=1,endTime=3600000,endTimeMode=2]],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2007,MONTH=11,WEEK_OF_YEAR=50,WEEK_OF_MONTH=3,DAY_OF_MONTH=15,DAY_OF_YEAR=349,DAY_OF_WEEK=7,DAY_OF_WEEK_IN_MONTH=3,AM_PM=1,HOUR=9,HOUR_OF_DAY=21,MINUTE=4,SECOND=33,MILLISECOND=209,ZONE_OFFSET=3600000,DST_OFFSET=0] ct = java.util.GregorianCalendar[time=1197749073210,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="Asia/Tokyo",offset=32400000,dstSavings=0,useDaylight=false,transitions=10,lastRule=null],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2007,MONTH=11,WEEK_OF_YEAR=51,WEEK_OF_MONTH=4,DAY_OF_MONTH=16,DAY_OF_YEAR=350,DAY_OF_WEEK=1,DAY_OF_WEEK_IN_MONTH=3,AM_PM=0,HOUR=5,HOUR_OF_DAY=5,MINUTE=4,SECOND=33,MILLISECOND=210,ZONE_OFFSET=32400000,DST_OFFSET=0] Veckonummer (locale-dependent!): 50 År: 2007 Månad: 11 Dag: 15 Timmar: 21 Timmar (0-12): 9 Minuter: 4 Sekunder: 33 Millisekunder: 209 Tokyo 1: 5:4 Tokyo 2: 21:4 Tokyo 3: 3:46 Tokyo 4: 5:25 f1.format(nu) = 12/15/07 9:04 PM f2.format(nu) = 9:04:33 PM f3.format(nu) = Dec 15, 2007 f4.format(nu) = 12/15/07 f5.format(nu) = Dec 15, 2007 f6.format(nu) = December 15, 2007 f7.format(nu) = Saturday, December 15, 2007 f8.format(nu) = December 15, 2007 9:04:33 PM CET Det finns 152 locales: 0. ja_JP 1. es_PE 2. en 3. ja_JP_JP ... 149. sv_SE 150. da_DK 151. es_HN dl = en_US f9.format(nu) = den 15 december 2007 21:04:33 CET
Utskrifter:import java.util.*; import java.text.*; public class Taltest { public static void main(String[] args) { int miljard = 1000000000; double glass = 14.50; System.out.println("miljard = " + miljard); System.out.println("glass = " + glass); NumberFormat nf = NumberFormat.getInstance(); System.out.println("miljard = " + nf.format(miljard)); System.out.println("glass = " + nf.format(glass)); Locale dl = Locale.getDefault(); System.out.println("dl = " + dl); Locale sverige = new Locale("sv", "SE"); Locale.setDefault(sverige); NumberFormat nf2 = NumberFormat.getInstance(); System.out.println("miljard = " + nf2.format(miljard)); System.out.println("glass = " + nf2.format(glass)); nf2.setMinimumFractionDigits(2); nf2.setMaximumFractionDigits(2); System.out.println("glass = " + nf2.format(glass)); } } // class Taltest
Programmet Taltest2.java:miljard = 1000000000 glass = 14.5 miljard = 1,000,000,000 glass = 14.5 dl = en_US miljard = 1 000 000 000 Obs: nbsp, inte space! glass = 14,5 glass = 14,50
Utskrifter:import java.util.*; import java.text.*; public class Taltest2 { public static void main(String[] args) { Locale sverige = new Locale("sv", "SE"); Locale.setDefault(sverige); // Obs: nbsp, inte space! String miljarden = "1 000 000 000"; String glassen = "14,50"; NumberFormat nf = NumberFormat.getInstance(); int miljard; double glass; try { Number miljardObjekt = nf.parse(miljarden); Number glassObjekt = nf.parse(glassen); // ReflectionTest.showClassInfo(miljardObjekt); miljard = miljardObjekt.intValue(); // ReflectionTest.showClassInfo(glassObjekt); glass = glassObjekt.doubleValue(); System.out.println("miljard = " + miljard); System.out.println("glass = " + glass); } catch (java.text.ParseException e) { System.out.println("Fångat: " + e); } } }
miljard = 1000000000 glass = 14.5
Oändlig loop:while (true) { break; }
Hur gör man för att hoppa ur flera nivåer av loopar på en gång?while (true) { while (true) { break; } }
C++-programmet breaktest.cpp:
(Återhopp med return är också vanligt för att åstadkomma detta i C och i C++.)#include <iostream> int main(int argc, char *argv[]) { int loops = 0; for (int x = 0; x < 1000; ++x) { for (int y = 0; y < 1000; ++y) { for (int z = 0; z < 1000; ++z) { ++loops; if (x == 245 && y == 201 && z == 270) goto after_x_loop; } } } after_x_loop: ; std::cout << loops << " loops.\n"; } // main
Utskrift:
Java-programmet BreakTest.java:245201271 loops.
public class BreakTest { public static void main(String[] args) { int loops = 0; xLoop: for (int x = 0; x < 1000; ++x) { for (int y = 0; y < 1000; ++y) { for (int z = 0; z < 1000; ++z) { ++loops; if (x == 245 && y == 201 && z == 270) break xLoop; } } } System.out.println(loops + " loops."); } // main } // class BreakTest
Ur HTML-filen Parametrar.html:// <applet code="Parametrar" width="300" height="200"> // </applet> import java.awt.*; import java.awt.event.*; import javax.swing.*; public class Parametrar extends JApplet { private JTextArea textarean = new JTextArea(10, 30); private JButton knappen = new JButton("foo & fum"); private void log(String s) { textarean.append(s + "\n"); textarean.setCaretPosition(textarean.getDocument().getLength()); } public void init() { log("init"); Container cp = getContentPane(); cp.setLayout(new BorderLayout()); cp.add(BorderLayout.CENTER, new JScrollPane(textarean)); cp.add(BorderLayout.SOUTH, knappen); knappen.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { try { String foo = getParameter("foo"); log("foo = " + foo); String fum = getParameter("fum"); log("fum = " + fum); } catch (Exception e) { log("Fångat: " + e); } } // actionPerformed }); } public void start() { log("start"); } public void stop() { log("stop"); } public static void main(String[] args) { JApplet applet = new Parametrar(); JFrame frame = new JFrame("Parametrar"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.getContentPane().add(applet); frame.setSize(300, 200); applet.init(); frame.setVisible(true); } } // class Parametrar
Appleten Parametrar, körd som applet respektive som applikation, efter en knapptryckning:<applet code="Parametrar" width="300" height="200"> <param name="foo" value="Tjolahopp!"> <param name="bar" value="Tjolahej!"> </applet>