Det här med skräpinsamling, hur var det med det egentligen? Om jag t ex skapar objekt med "new" hur tar jag bort dem? Det där automatiska var ju inte att lita på?Om skräpsamling, finalize och diverse close-metoder:
Programmet är förstås lite förenklat. Ett användbart program skulle läsa från filen, och det skulle inte öppna samma fil gång på gång.import java.io.*; import java.util.*; public class FileCounter1 { public static void main(String[] args) { try { int nrFiles = 0; ArrayList files = new ArrayList(); while (true) { BufferedReader in = new BufferedReader(new FileReader("dummy.txt")); files.add(in); ++nrFiles; System.out.println("nrFiles = " + nrFiles); } } catch (FileNotFoundException e) { System.out.println("Exception caught: " + e.getMessage()); } } // main } // class FileCounter1
FileCounter1 kraschar:
Programmet FileCounter2.java:nrFiles = 1 nrFiles = 2 nrFiles = 3 nrFiles = 4 nrFiles = 5 nrFiles = 6 nrFiles = 7 ... nrFiles = 1017 nrFiles = 1018 nrFiles = 1019 Exception caught: dummy.txt (Too many open files)
FileCounter2 kraschade inte, i alla fall inte innan jag tröttnade på att vänta:import java.io.*; import java.util.*; public class FileCounter2 { public static void main(String[] args) { try { int nrFiles = 0; while (true) { BufferedReader in = new BufferedReader(new FileReader("dummy.txt")); ++nrFiles; System.out.println("nrFiles = " + nrFiles); } } catch (FileNotFoundException e) { System.out.println("Exception caught: " + e.getMessage()); } } // main } // class FileCounter2
Programmet FileCounter3.java:nrFiles = 1 nrFiles = 2 nrFiles = 3 nrFiles = 4 nrFiles = 5 nrFiles = 6 nrFiles = 7 ... nrFiles = 999998 nrFiles = 999999 nrFiles = 1000000 nrFiles = 1000001 nrFiles = 1000002 nrFiles = 1000003 ...
FileCounter3 provkördes flera gånger. Ibland körde programmet i timmar utan problem. Ibland kraschade det:import java.io.*; import java.util.*; class MyFileObject { private final BufferedReader reader; static int nrInstances = 0; public MyFileObject(BufferedReader reader) { this.reader = reader; ++nrInstances; System.out.println("nrInstances up, now " + nrInstances); } public void finalize() { --nrInstances; System.out.println("nrInstances down, now " + nrInstances); } } // class MyFileObject public class FileCounter3 { public static void main(String[] args) { try { int nrFiles = 0; while (true) { BufferedReader in = new BufferedReader(new FileReader("dummy.txt")); MyFileObject mfo = new MyFileObject(in); ++nrFiles; System.out.println("nrFiles = " + nrFiles); } } catch (FileNotFoundException e) { System.out.println("Exception caught: " + e.getMessage()); } } // main } // class FileCounter3
Övning: Den stannar på 35. Varför räknar den inte ner till 0? [Svar]nrInstances up, now 1 nrFiles = 1 nrInstances up, now 2 nrFiles = 2 nrInstances up, now 3 nrFiles = 3 ... nrInstances up, now 14 nrFiles = 14 nrInstances up, now 15 nrFiles = 15 nrInstances down, now 14 nrInstances down, now 13 nrInstances up, now 14 nrFiles = 16 nrInstances up, now 15 nrFiles = 17 ... nrInstances up, now 998 nrFiles = 7586 nrInstances up, now 999 nrFiles = 7587 nrInstances up, now 1000 nrFiles = 7588 nrInstances up, now 1001 nrFiles = 7589 nrInstances up, now 1002 nrFiles = 7590 Exception caught: dummy.txt (Too many open files) nrInstances down, now 1001 nrInstances down, now 1000 nrInstances down, now 999 nrInstances down, now 998 nrInstances down, now 997 ... nrInstances down, now 38 nrInstances down, now 37 nrInstances down, now 36 nrInstances down, now 35
Man måste frigöra resursern (den öppna filen) själv, med en metod som till exempel heter cleanup eller close. Programmet FileCounter4.java:
import java.io.*; import java.util.*; class MyFileObject { private final BufferedReader reader; static int nrInstances = 0; public MyFileObject(BufferedReader reader) { this.reader = reader; ++nrInstances; System.out.println("nrInstances up, now " + nrInstances); } public void finalize() { --nrInstances; System.out.println("nrInstances down, now " + nrInstances); } public void close() throws IOException { reader.close(); } } // class MyFileObject public class FileCounter4 { public static void main(String[] args) { try { int nrFiles = 0; while (true) { BufferedReader in = new BufferedReader(new FileReader("dummy.txt")); MyFileObject mfo = new MyFileObject(in); ++nrFiles; System.out.println("nrFiles = " + nrFiles); mfo.close(); } } catch (FileNotFoundException e) { System.out.println("Exception caught: " + e.getMessage()); } catch (IOException e) { System.out.println("Exception caught: " + e.getMessage()); } } // main } // class FileCounter4
Exempel:
Klassen ChatButtonWindow i programmet
Client5.java
från
föreläsning 8.
Ur programmet Client6.java:
En tumregel om namn: Ju större scope ett namn har, desto mer informativt ska namnet vara!private class ChatButtonWindow extends JFrame { private PrintWriter out; public ChatButtonWindow(PrintWriter outParameter) { super("Extra chat buttons"); out = outParameter; Container cp = getContentPane(); cp.setLayout(new FlowLayout()); JButton button1 = new JButton("Skicka förolämpning"); cp.add(button1); button1.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { out.println("Ni, min herre, är en apa."); System.out.println( "Skickade en förolämpning."); } }); JButton button2 = new JButton("Skicka beröm"); cp.add(button2); button2.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { out.println("Du är bäst!"); System.out.println("Skickade beröm."); } }); JButton button3 = new JButton("Avsluta"); cp.add(button3); button3.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { System.out.println("Avslutar."); System.exit(0); } }); setSize(200, 200); setVisible(true); } } // class ChatButtonWindow
(Jag använder skrivbordsschemat Öken i Windows. Java följer skrivbordsschemat när man använder Windows-look-and-feelen.)
Programmet Sqrt1.java (som påminner mycket om appleten Sqrt.java från föreläsning 3):
I programmet Sqrt2.java, som använder Windows-look-and-feelen, har vi lagt till följande rader först i main, innan vi skapar det första fönstret:import javax.swing.*; import java.awt.event.*; import java.awt.*; public class Sqrt1 extends JFrame { private JLabel label = new JLabel("Här visas roten"); private JTextField text = new JTextField("Skriv talet här"); private JButton button = new JButton("Visa rot!"); private ButtonListener bl = new ButtonListener(); public Sqrt1() { super("Sqrt1"); button.addActionListener(bl); Container cp = getContentPane(); cp.setLayout(new FlowLayout()); cp.add(text); cp.add(button); cp.add(label); } // Inre klass för att lyssna på knapp class ButtonListener implements ActionListener { // Hantera klick på roten-ur-knapp public void actionPerformed(ActionEvent event) { String numbuf = text.getText(); try { float num = Float.parseFloat(numbuf); float res = (float)Math.sqrt(num); if (Float.isNaN(res)) label.setText("Det måste vara ett positivt tal."); else label.setText("Roten ur " + num + " är " + res); } catch (NumberFormatException exc) { label.setText("'" + numbuf + "' är inte ett tal."); } } // actionPerformed } // class ButtonListener public static void main(String[] args) { Sqrt1 frame = new Sqrt1(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(200, 100); frame.setVisible(true); } } // class Sqrt1
String laf = UIManager.getSystemLookAndFeelClassName(); try { UIManager.setLookAndFeel(laf); // If you want the Cross Platform L&F instead, replace // UIManager.getSystemLookAndFeelClassName() // with // UIManager.getCrossPlatformLookAndFeelClassName() } catch (UnsupportedLookAndFeelException exc) { System.err.println("Warning: UnsupportedLookAndFeel: " + laf); } catch (Exception exc) { System.err.println("Error loading " + laf + ": " + exc); }
(Klicka på bilderna nedan för att se dem i större format.)
Swing-demons första exempel, körd på Linux:
Swing-demons första exempel, körd på Windows. Eftersom vi använder default-look-and-feelen ser det precis likadant ut inuti fönstret:
Swing-demons första exempel, körd på Windows, men nu med Windows-look-and-feel påslagen:
Tydlig skillnad på look and feel kan man se i filväljardialogen. Här en filväljardialog med Windows-look-and-feel:
Sama filväljardialog med default-look-and-feel:
Några fler exempel ur Swing-demon. (Provkör gärna själv!)
Programmet ComboBoxTest.java:
import javax.swing.*; import java.awt.event.*; import java.awt.*; public class ComboBoxTest extends JFrame { String[] description = { "Tripp", "Trapp", "Trull" }; JComboBox c = new JComboBox(); JTextField t = new JTextField(5); public ComboBoxTest() { c.addItem("Tripp"); c.addItem("Trapp"); c.addItem("Trull"); t.setEditable(false); c.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e){ JComboBox box = (JComboBox)e.getSource(); t.setText(box.getSelectedItem().toString()); } }); Container cp = getContentPane(); cp.setLayout(new FlowLayout()); cp.add(t); cp.add(c); } public static void main(String[] args) { ComboBoxTest frame = new ComboBoxTest(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(200, 80); frame.setVisible(true); } } // class ComboBoxTest
Programmet ButtonGroupTest.java:
import javax.swing.*; import java.awt.*; import java.awt.event.*; import javax.swing.border.*; public class ButtonGroupTest extends JFrame { public ButtonGroupTest() { super("ButtonGroupTest"); Container cp = getContentPane(); cp.setLayout(new FlowLayout()); ButtonGroup group = new ButtonGroup(); JPanel panel = new JPanel(); panel.setBorder(new TitledBorder("3 x JRadioButton")); JRadioButton button1 = new JRadioButton("Tripp"); group.add(button1); panel.add(button1); JRadioButton button2 = new JRadioButton("Trapp"); group.add(button2); panel.add(button2); JRadioButton button3 = new JRadioButton("Trull"); group.add(button3); panel.add(button3); cp.add(panel); } public static void main(String[] args) { ButtonGroupTest frame = new ButtonGroupTest(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(300, 100); frame.setVisible(true); } } // class ButtonGroupTest
Programmet ButtonGroups1.java:
// Adapted from Bruce Eckel's "Thinking in Java", 3d Ed, Chapter 14 import javax.swing.*; import java.awt.*; import java.awt.event.*; import javax.swing.border.*; public class ButtonGroups1 extends JFrame { private static String[] ids = { "Tripp", "Trapp", "Trull", }; public ButtonGroups1() { super("ButtonGroups"); Container cp = getContentPane(); cp.setLayout(new FlowLayout()); ButtonGroup group = new ButtonGroup(); JPanel panel = new JPanel(); panel.setBorder(new TitledBorder("3 x JButton")); for (int i = 0; i < ids.length; i++) { JButton button = new JButton(ids[i]); group.add(button); panel.add(button); } cp.add(panel); group = new ButtonGroup(); panel = new JPanel(); panel.setBorder(new TitledBorder("3 x JToggleButton")); for (int i = 0; i < ids.length; i++) { JToggleButton button = new JToggleButton(ids[i]); group.add(button); panel.add(button); } cp.add(panel); group = new ButtonGroup(); panel = new JPanel(); panel.setBorder(new TitledBorder("3 x JCheckBox")); for (int i = 0; i < ids.length; i++) { JCheckBox button = new JCheckBox(ids[i]); group.add(button); panel.add(button); } cp.add(panel); group = new ButtonGroup(); panel = new JPanel(); panel.setBorder(new TitledBorder("3 x JRadioButton")); for (int i = 0; i < ids.length; i++) { JRadioButton button = new JRadioButton(ids[i]); group.add(button); panel.add(button); } cp.add(panel); } public static void main(String[] args) { ButtonGroups1 frame = new ButtonGroups1(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(300, 300); frame.setVisible(true); } } // class ButtonGroups1
Programmet ReflectionTest.java:
Utskrifter:import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.lang.reflect.*; public class ReflectionTest extends JFrame { public static void showClassInfo(Object o) { Class c = o.getClass(); System.out.println("Klass: " + c.getName()); Class sc = c.getSuperclass(); System.out.println("Superklass: " + sc.getName()); Method[] methods = c.getDeclaredMethods(); System.out.println("Metoder:"); for (int i = 0; i < methods.length; ++i) System.out.println(" " + methods[i].getName()); Constructor[] constructors = c.getDeclaredConstructors(); System.out.println("Konstruktorer:"); for (int i = 0; i < constructors.length; ++i) System.out.println(" " + constructors[i].getName()); Field[] fields = c.getDeclaredFields(); System.out.println("Fält:"); for (int i = 0; i < fields.length; ++i) System.out.println(" " + fields[i].getName()); } public static void main(String[] args) { JButton button = new JButton("Hej"); showClassInfo(button); } } // class ReflectionTest
Klass: javax.swing.JButton Superklass: javax.swing.AbstractButton Metoder: writeObject getAccessibleContext paramString removeNotify configurePropertiesFromAction getUIClassID isDefaultButton isDefaultCapable setDefaultCapable updateUI Konstruktorer: javax.swing.JButton javax.swing.JButton javax.swing.JButton javax.swing.JButton javax.swing.JButton Fält: uiClassID defaultCapable
Samma knappgruppsexempel som ovan, men nu med en metod som använder reflektion.
Programmet ButtonGroups2.java:
// Adapted from Bruce Eckel's "Thinking in Java", 3d Ed, Chapter 14 // Uses reflection to create groups // of different types of AbstractButton. import javax.swing.*; import java.awt.*; import java.awt.event.*; import javax.swing.border.*; import java.lang.reflect.*; public class ButtonGroups2 extends JFrame { private static String[] ids = { "Tripp", "Trapp", "Trull", }; private JPanel makeButtonPanel(Class klass, String[] ids) { ButtonGroup group = new ButtonGroup(); JPanel panel = new JPanel(); String title = klass.getName(); panel.setBorder(new TitledBorder(title)); for (int i = 0; i < ids.length; i++) { AbstractButton button = new JButton("failed"); try { // Get the dynamic constructor method // that takes a String argument: Constructor ctor = klass.getConstructor(new Class[] {String.class}); // Create a new object: button = (AbstractButton) ctor.newInstance(new Object[] {ids[i]}); } catch (Exception e) { System.out.println("Exception caught: " + e); } group.add(button); panel.add(button); } return panel; } public ButtonGroups2() { super("ButtonGroups2"); Container cp = getContentPane(); cp.setLayout(new FlowLayout()); cp.add(makeButtonPanel(JButton.class, ids)); cp.add(makeButtonPanel(JToggleButton.class, ids)); cp.add(makeButtonPanel(JCheckBox.class, ids)); cp.add(makeButtonPanel(JRadioButton.class, ids)); } public static void main(String[] args) { ButtonGroups2 frame = new ButtonGroups2(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(300, 300); frame.setVisible(true); } } // class ButtonGroups2