Programmeren in Java Een stoomcursus door Edgar de Graaf, november 2006 Deze tekst geeft een zeer korte inleiding in de programmeertaal Java, uitgaande van kennis van de taal C++. Daarnaast bestudere men de sheets van het college. In de tekst hieronder staan enkele programmeeropgaven, gemarkeerd met &. Zie verder: http://www.liacs.nl/home/kosters/pm/java.pdf (de sheets) http://www.liacs.nl/home/kosters/pm/javatekst.doc (deze file) De Onderdelen 1. Terminal uitvoer en compilatie. Hiermee wordt de werking van de Java compiler getoond. Verder laten wij zien hoe schermuitvoer gaat: dit verschilt van C++. 2. Java en bestanden. Bestanden inlezen gaat anders in Java. Bij dit onderdeel laten wij zien hoe je met Streams en Readers kunt omgaan. Ook Exceptions zullen kort aan bod komen. Java is volledig object­georiënteerd, en daarom zullen wij hier ook objecten behandelen. 3. Graphical User Interfaces. Objecten maken het bouwen van een grafische interface (GUI) eenvoudiger. In dit onderdeel zullen wij een Applet bouwen. Terminal uitvoer en compilatie Eén van de sterke punten van de programmeertaal Java is de platform­onafhankelijkheid, die men bereikt door broncode om te zetten naar bytecode. Deze bytecode ligt tussen machinecode en broncode in. Bytecode is verschillend van machinecode omdat het onafhankelijk is van het platform en het is verschillend van broncode omdat het een binair bestand is, geoptimaliseerd voor de interpreter. De bytecode­interpreter noemen wij de Java Virtual Machine (JVM). Java kent verschillende versies, lopend van de oude versie Java 1.0 tot Java 1.5 op het moment van schrijven van dit document. Deze versies verschillen soms sterk van elkaar, vooral tussen versie 1.0 en 1.1 en tussen versie 1.1 en 1.2 (vanaf 1.2 heet het Java 2). Men kan de Java compiler gratis downloaden van de Java website: http://java.sun.com Sun (de maker van Java) stelt verschillende technologieën beschikbaar die allemaal Java in hun naam hebben. De laatste Java­compiler noemt men J2SE (Java 2 Standard Edition). Verder stelt men de JRE (Java Runtime Environment) en de SDK (Software Development Kit) beschikbaar. Deze laatste gebruiken wij. Java staat al geïnstalleerd op de meeste systemen in het Snellius, het installeren is alleen nodig voor thuis. Test welke versie het universitair systeem beschikbaar stelt. Open een (Linux/UNIX) terminal en gebruik hiertoe het volgende commando: java -version Het java commando roept de Java­interpreter aan. Hiermee kun je straks jouw Java bytecode uitvoeren. Het commando javac roept de Java­compiler aan waarmee de bytecode gemaakt wordt, mits je geen fouten maakt uiteraard. Het volgende programma bevat een veel voorkomende fout. Maak een directory en maak in deze directory een bestand genaamd Main.java. Neem de code met de fout vervolgens over (copy/paste): import java.io.*; public class Main { public Main(String naam){ System.out.println("Hello smart student " + naam) int moeilijk = 1 + 1; System.out.println("1 + 1 = " + moeilijk); }//Main public static void main(String args[]) throws IOException { BufferedReader input = new BufferedReader(new InputStreamReader(System.in)); System.out.print("Please type your name: "); new Main(input.readLine()); }//main }//class Main Compileer de code met het volgende commando: javac *.java Java­programma’s bestaan vaak uit verschillende classes en elke class zit doorgaans in een apart .java bestand. Met bovenstaand commando worden ze allemaal gecompileerd. Merk op: het .java bestand moet dezelfde naam hebben als de class die erin zit; let hierbij ook op hoofdletters. De compiler zal je vervolgens vertellen dat achter System.out.println("Hello smart student" + naam) een ; nodig is. Verbeter deze fout en compileer opnieuw. De compiler zal Main.class maken; dit is de bytecode die je kunt uitproberen door het volgende commando: java Main Een aantal verschillen met C++ zullen meteen duidelijk zijn: • De main­functie zit in de Main class. Deze class mag elke andere naam hebben, de main functie moet er ongeveer zo uitzien. Executie begint bij deze main. • Voor uitvoer naar het scherm gebruikt men System.out.println voor een zin met een regelovergang erbij, en System.out.print voor idem zonder. • Invoer gaat via System.in en twee Readers, hierover later meer. • De include­bibliotheek heet hier import. De package naam java.io kun je eenvoudig opzoeken in de Java API documenten die zijn te downloaden op de Java website. • Java heeft alle informatie over een class in een bestand, het kent geen header bestanden. • Voor elke functie wordt aangeven of deze public, private of protected is: buiten de package beschikbaar, alleen binnen de class of alleen binnen de package. Een package is een verzameling van bij elkaar horende classes. • Het declareren van een object betekent niet dat automatisch de constructor wordt aangeroepen. • Een object wordt pas gemaakt bij het ‘new’­commando dat je alleen op de aangeven manieren kunt maken. • Java kent geen call­by­reference of pointers (geen delete's, wel new's). Verder werkt men vaak met String, in principe niet met char arrays. String is een object en daarom schrijven wij het met een hoofdletter. Echter, int is geen object en wij schrijven dat dan ook met een kleine letter. Opgave & 1. Schrijf een Hello World programma, compileer en run het. Tip: kopieer steeds benodigde Java­code uit de elektronische versie van dit document! 2. Schrijf een Java­programma dat aan de gebruiker twee getallen vraagt, en hun product afdrukt op het beeldscherm. 3. [Thuis] Neem het gedeelte van de eerste C++­programmeeropgave dat bij gegeven datum de bijbehorende dag bepaalt, en zet dit om in Java. Java en bestanden In het vorige onderdeel had je al gezien dat het afhandelen van bestanden heel anders verloopt in Java. Alle bestandsafhandeling wordt gedaan door de (objecten van) classes uit het java.io package. Zoek uit welke classes in deze package zitten door gebruik te maken van de API documentatie te vinden op de volgende website: http://java.sun.com/j2se/1.5.0/docs/api/ De class Reader is een abstract class. Dit wil zeggen dat bepaalde onderdelen van deze class (blauwdruk voor een object) nog niet zijn geïmplementeerd. Deze implementatie zal gedaan worden in zijn subclass en van een abstract class kun je dan ook geen object maken. Zoek in de documentatie van java.io de Reader class, en noteer wat Readers doen volgens deze documentatie. Een voorbeeld van zulke implementatie’s zijn de BufferedReader en de FileReader. Zoek ook op wat beide doen en noteer dit in eigen woorden. Objecten van deze twee classes zal je vaak gebruiken voor het inlezen van bestanden. Hun verschillende functionaliteit wordt gecombineerd zoals bij het voorbeeld in het vorige onderdeel (het ene object als parameter voor de constructor van het andere object). Zoals je kunt zien in dat voorbeeld, objecten worden gemaakt door gebruik te maken van het commando new. Een class moet je zien als een blauwdruk, bijvoorbeeld een class Mens zal omschrijven wat er gebeurt als een mens zijn armspier spant, een voorbeeld van een object van de class Mens ben jij. Mens is weer een subclass van de abstracte class Organisme. Deze is abstract omdat nog moet worden aangeven hoe het organisme ademt en zich voortbeweegt. Bij de Reader zal dit betekenen dat het bekend is dat een Reader karakters leest, maar hoe hij dat doet en uit welke bron wordt gespecificeerd in bijvoorbeeld de BufferedReader. De Java documentatie geeft bij readLine van BufferedReader aan ‘throws IOException’. Het gebruik van Exceptions is min of meer verplicht in Java. Deze Exceptions handelen fouten af die niet bij compilatie optreden, maar tijdens het runnen. In het voorbeeld van het eerste onderdeel werd deze Exception gewoon ‘doodgegooid’. Dit is geen mooie afhandeling van Exceptions, verander dit: import java.io.*; public class Main { public Main(String naam){ System.out.println("Hello smart student " + naam); int moeilijk = 1 + 1; System.out.println("1 + 1 = " + moeilijk); }//Main public static void main(String args[]){ try { BufferedReader input = new BufferedReader(new FileReader("mijnbest.txt")); System.out.print("Please type your name: "); new Main(input.readLine()); input.close(); } catch(IOException ex){ System.out.println("Inleesfout"); ex.printStackTrace(); }//catch }//main }//class Main Compileer dit programma en voer het uit zonder het bijhorende bestand mijnbest.txt te maken, en kijk wat er gebeurd. De functie (method in Java) printStackTrace van het IOException object drukt de details van de fout af naar het scherm. Deze method gebruik je eigenlijk alleen tijdens debugging. De try­catch constructie zorgt er voor dat Exceptions worden afgevangen als zij in een method optreden. Opgave & Maak nu zelf een class die de eerste 3 letters van een bestand inleest en afdrukt op het beeldscherm. In het package java.io kun je ook nog InputStreams vinden. Deze groep van classes zorgt voor al het inlezen waar je met ingewikkelder zaken werkt in plaats van met karakters. Een voorbeeld is de ObjectInputStream, deze leest complete objecten in die zijn weggeschreven met de ObjectOutputStream. OutputStreams handelen alles af wat met het schrijven van bytes te maken heeft. Writers daarentegen schrijven karakters en strings naar bestanden. Opgave & Maak een programma dat gebruik maakt van een PrintWriter en een FileWriter om een String naar een bestand te schrijven. Let op: je kunt deze string in één keer naar het bestand laten schrijven, dus het hoeft niet karakter voor karakter. Graphical User Interfaces Het is vrij eenvoudig om met Java een grafische interface te maken. Dit komt onder andere door het object georiënteerde karakter. Het is mogelijk een grafische interface te maken die werkt via Internet, een Applet geheten, en/of een interface die buiten Internet om is uit te voeren, een Frame geheten. Wij zullen een Applet bouwen die via een knop een Frame opent met een menu. Eerst maken wij een Applet en zijn bijhorende HTML bestand: import java.awt.*; import java.awt.event.*; import javax.swing.*; import java.applet.*; public class MyApplet extends JApplet { public void init(){ }//init }//class MyApplet <HTML> <HEAD> <TITLE>Een eerste applet</TITLE> </HEAD> <BODY> <APPLET CODE="MyApplet.class" WIDTH=400 HEIGHT=200> <PARAM NAME="buttonName" VALUE="Klik hier"> </APPLET> </BODY> </HTML> Compileer eerst de Applet. Als je nu de HTML­pagina opent gebeurt er niets: je ziet alleen een grijs vierkant. Het kan overigens ook zonder browser: gebruik dan het commando appletviewer. We voegen een Button toe; deze button komt uit de Swing package. De AWT package (Abstract Windows Toolkit) bevat de oude grafische elementen zoals Button, en Swing bevat de nieuwe zoals JButton. Voeg de button toe binnen de init method: Container contentPane = getContentPane(); contentPane.setLayout(new FlowLayout()); myButton = new JButton(getParameter("buttonName")); myButton.setBounds(10,10,100,50); myButton.setToolTipText("Aardigheidje .."); contentPane.add(myButton); Voeg nu nog een button object toe aan de class, nog net buiten de init method: private JButton myButton; Nu kan je de Applet weer compileren en uitvoeren (door de HTML pagina te openen). Bij sommige browsers is het nodig om alle windows eerst te sluiten, anders blijft de oude Applet staan. De contentPane is het blad van de Applet waaraan je de componenten, zoals de JButton, toevoegt. Normaal gesproken werk je met layout managers, maar deze zullen wij niet behandelen. Vervolgens maken wij de button, stellen zijn positie en omvang in en voegen hem toe aan het blad van de Applet. De button heeft nu nog geen functionaliteit behalve het oplichten als je er op drukt. Java is event­driven wat wil zeggen dat het drukken op een button een event genereert dat wij af moeten vangen en af moeten handelen. Voeg eerst achter extends JApplet (voor de accolade) het volgende toe: implements ActionListener ActionListener is een interface die je verplicht bepaalde methodes te implementeren, in dit geval: public void actionPerformed(ActionEvent evt){ Object source = evt.getSource(); if (source == myButton){ myButton.setText("Test"); }//if }//actionPerformed Voeg deze toe aan de MyApplet class, en compileer en bekijk het resultaat. Nu moet je de events van de button nog koppelen met de ActionListener (de MyApplet class). Voeg het volgende toe onder de setBounds in de init method: myButton.addActionListener(this); Het zou nu aardig moeten werken. En hoe lees je tekst in uit een “textbox”? Hier staan de benodigde elementen: ... private JTextField myText; ... myText = new JTextField(15); myText.setText("Uw getal aub"); myText.addActionListener(this); contentPane.add(myText); ... else if (source == myText){ String tekst = myText.getText(); int i = Integer.parseInt(tekst); JOptionPane.showMessageDialog(null,"Kwadraat: "+(i*i)); }//if ... Opgave & bestudeer onderstaand programma. Ter oefening kun je het zelf mogelijk maken dat de title van de Frame verandert als je item1 selecteert. Maak hiervoor gebruik van de ActionListener. Opgave & Tot slot: maak een GUI voor de datum­opgave. Voor liefhebbers met een Jslider :­) Wil je het eventueel nog mooier maken, fabriceer dan een aparte class MyFrame in een apart bestand genaamd MyFrame.java: import javax.swing.*; import java.awt.*; import java.awt.event.*; public class MyFrame extends JFrame { public MyFrame(){ setTitle("Mijn Eerste JFrame Object"); setBounds(100,100,300,200); JMenu eenMenu = new JMenu("Menu 1"); JMenu eenMenu2 = new JMenu("Menu 2"); item1 = new JMenuItem("Item1"); item2 = new JMenuItem("Item2"); item3 = new JMenuItem("Item3"); eenMenu.add(item1); eenMenu.add(item2); eenMenu2.add(item3); JMenuBar menuBar = new JMenuBar(); menuBar.add(eenMenu); menuBar.add(eenMenu2); setJMenuBar(menuBar); setVisible(true); }//MyFrame JMenuItem item1; JMenuItem item2; JMenuItem item3; }//class MyFrame Vervolgens moet je nog in de actionPerformed method van MyApplet de regel met setText vervangen met het volgende: new MyFrame();