Java: Lösningar till tentamen 2004-01-31

Observera att detta är förslag på lösningar. Det kan finnas andra lösningar som också är korrekta, och det kan hända att en del av lösningarna är mer omfattande än vad som krävs för full poäng på uppgiften.

Uppgift 1 (3p)

Skapar ett djur
Skapar ett djur
Skapar en katt
Skapar ett djur
Skapar en katt
Skapar ett namnlöst djur
Skapar en myra
Allmänt djurljud
Mjau!
Mjau!
Myran är tyst

Uppgift 2 (3p)

a (1p)

Ena.java:8: x has private access in Andra
        a.x = 7;
         ^
Klassen Ena kommer inte åt privata variabler i den andra klassen Andra.

För att åtgärda felet kan man göra variabeln x publik genom att ändra från private till public. Alternativt kan man använda en konstruktor för att ge x sitt initiala värde.

b (1p)

Fel.java:7: non-static method f() cannot be referenced from a static context
        f();
        ^
Instansmetoder måste anropas för ett visst objekt, som inuti metoden refereras med this. Eftersom main är en klassmetod och inte en instansmetod, finns det inget this-objekt när main körs, och instansmetoden f kan alltså inte anropas direkt.

Man kan göra om funktionen f från en instansmetod till en klassmetod. Alternativt kan man skapa ett objekt av klassen Fel och sen anropa f i det objektet.

c (1p)

Yttre.java:9: non-static variable this cannot be referenced from a static context
        Inre i = new Inre();
                 ^

En instans av en inre klass (som klassen Inre) "finns" alltid "inuti" en instans av sin ytter klass (här Yttre). Eftersom main är en klassmetod och inte en instansmetod, finns det inget this-objekt när main körs, och alltså inget yttre objekt som det skapade inre objektet kan finnas i.

En lösning, av flera möjliga, är att static-deklarera den inre klassen Inre.

Uppgift 3 (5p)

// <applet code="StringApplet" width="250" height="200"></applet>

import javax.swing.*;
import java.awt.event.*;
import java.awt.*;

public class StringApplet extends JApplet
implements ActionListener {
    private JTextField numbertext = new JTextField(5);
    private JTextField texttext = new JTextField(10);
    private JButton fillButton = new JButton("Fyll på");
    private JTextArea svarstext = new JTextArea(8, 20);

    public void actionPerformed(ActionEvent event) {
        String numberstring = numbertext.getText();
        String textstring = texttext.getText();
        if (textstring.equals("")) {
            svarstext.append("ERROR");
        }
        else {
            try {
                double n = Integer.parseInt(numberstring);
                for (int i = 0; i < n; ++i)
                    svarstext.append(textstring);
            }
            catch (NumberFormatException exc) {
                svarstext.append("ERROR");
            }
        }
    } // actionPerformed

    public void init() {
        fillButton.addActionListener(this);
        Container cp = getContentPane();
        cp.setLayout(new FlowLayout());
        cp.add(numbertext);
        cp.add(texttext);
        cp.add(fillButton);
        cp.add(svarstext);
    }
} // class StringApplet

Uppgift 4 (12p)

a (1p)

Alla användarna, med sina klienter, kan skriva rader när som helst. Alltså måste servern ligga och vänta på alla klienterna samtidigt, för att se vem som skickar en rad. Det behövs flera samtidiga readLine-anrop (eller motsvarande), och det gör man (enklast) med en tråd som lyssnar på varje klient.

Om servern är enkeltrådad kan den bara lyssna på en klient i taget, med ett enda readLine-anrop åt gången. Om den då lyssnar på en klient i taget, måste varje klient "vänta på sin tur".

b (1p)

Klienten måste samtidigt ligga och vänta på att användaren ska skriva något, och på att det ska komma text från servern som någon annan användare skrivit. Det behövs två samtidiga readLine-anrop (eller motsvarande), och det gör man (enklast) med två trådar.

Om klienten är enkeltrådad kan den bara lyssna på en datakälla i taget: antingen användaren eller servern, med ett enda readLine-anrop åt gången. Om det bara finns en enda tråd, måste både användaren och servern "vänta på sin tur". En inkommande rad från servern kommer inte att läsas och visas förrän användaren skrivit sin rad, och på samma sätt kommer en rad som användaren skrivit inte att läsas och skickas iväg till servern förrän servern skickat sin rad.

c (10p)

import java.net.Socket;
import java.net.InetAddress;

import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.PrintWriter;
import java.io.IOException;

final class ServerListener extends Thread {
    final private BufferedReader fromServer;

    public ServerListener(BufferedReader fromServer) {
        this.fromServer = fromServer;
    }

    public void run() {
        String lineFromServer;
        try {
            while ((lineFromServer = fromServer.readLine()) != null) {
                System.out.println("Från servern: " + lineFromServer);
            }
            System.out.println("Servern verkar ha kopplat ner.");
            System.exit(0);
        }
        catch (IOException e) {
            System.out.println("Undantag fångat: " + e);
        }
    }
} // class ServerListener

public class ChatClient {
    public static final int PORT = 3000;
    public static final String host = "chat.oru.se";

    public static void main(String[] args) {
        try {
            Socket socket = new Socket(host, PORT);

            BufferedReader in = new BufferedReader(
                new InputStreamReader(socket.getInputStream()));
            PrintWriter out = new PrintWriter(
                new BufferedWriter(
                    new OutputStreamWriter(
                        socket.getOutputStream())), true);
            // true: PrintWriter is line buffered

            BufferedReader kbd_reader = new BufferedReader(
                new InputStreamReader(System.in));

            ServerListener t = new ServerListener(in);
            t.start();

            String buf;
            while (true) {
                buf = kbd_reader.readLine();
                System.out.println("Skickas till servern: " + buf);
                out.println(buf);
            }
        }
        catch (IOException e) {
            System.err.println("Kommunikationsfel: " + e);
        }
    } // main
} // class ChatClient

Uppgift 5 (3p)

a (1p)

b (2p)

Följande program skapar och startar två trådar med de två olika metorderna:
class Tråd1 extends Thread {
    public void run() {
        while (true)
            System.out.print("1");
    } // run
} // class Tråd1

class Tråd2 implements Runnable {
    public void run() {
        while (true)
            System.out.print("2");
    } // run
} // class Tråd2

public class Trådar {
    public static void main(String[] args) {
        Tråd1 t1 = new Tråd1();
        t1.start();
        Tråd2 r = new Tråd2();
        Thread t2 = new Thread(r);
        t2.start();
    } // main
} // class Trådar

Uppgift 6 (8p)

Exempel på kod:

package Adventure;

import java.util.ArrayList;

class Sak {
    private String namn;
    private String beskrivning;
    private double vikt;

    public Sak(String namn, String beskrivning, double vikt) {
        this.namn = namn;
        this.beskrivning = beskrivning;
        this.vikt = vikt;
    }

    public String getNamn() { return namn; }
    public String getBeskrivning() { return beskrivning; }
    public double getVikt() { return vikt; }
}

class Vapen extends Sak {
    private double farlighet;

    public Vapen(String namn, String beskrivning, double vikt, double farlighet) {
        super(namn, beskrivning, vikt);
        this.farlighet = farlighet;
    }

    double getFarlighet() { return farlighet; }
}

class Väska extends Sak {
    private ArrayList innehåll = new ArrayList();

    public Väska(String namn, String beskrivning, double vikt) {
        super(namn, beskrivning, vikt);
    }

    public ArrayList getHelaInnehållet() { return (ArrayList)innehåll.clone(); }
    public void stoppaIn(Sak s) { innehåll.add(s); }
    public void taUt(Sak s) { innehåll.remove(s); }
}

Thomas Padron-McCarthy (Thomas.Padron-McCarthy@tech.oru.se) 12 februari 2004