Java: Lösningar till tentamen 2005-01-29

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 (8p)

a)

Både Swing och AWT är paket att göra grafiska gränssnitt i Java. AWT är det äldre, och anses allmänt vara ganska dåligt och svåranvänt. Swing bygger vidare på AWT, och är bättre och enklare att använda.

Rättningskommentar:
Det stod fel i tentan, AWK i stället för AWT.

b)

javac är kompilatorn, som översätter Java-källkod till byte-kod för den virtuella Java-maskinen. java är interpretatorn, som implementerar den virtuella Java-maskinen och kör den kompilerade koden.

c)

Filer som slutar på .java innehåller Java-källkod. När en sådan fil kompileras till byte-kod för den virtuella Java-maskinen, lagras den byte-koden på en fil med samma namn men med filändelsen .class.

d)

En Java-applikation är ett fristående program, medan en Java-applet är ett (oftast) mindre program som är avsett att köras i en webbläsare. Det finns fler restriktioner på vad en Java-applet får göra (till exempel när det gäller att läsa och skriva filer), jämfört med vad Java-applikationer får göra.

Uppgift 2 (6p)

class Frukt {
    private static int antalFrukter = 0;
    private int nummer = ++antalFrukter;
    private int vikt;
}

class Apelsin extends Frukt {
    private int antalKlyftor;
}

class Banan extends Frukt {
    private int krökningsradie;
}

class Äpple extends Frukt {
    private int krökningsradie;
}

public class Uppgift2 {
    public static void main(String[] args) {
        Frukt f = new Frukt();
        Apelsin a = new Apelsin();
        Banan b = new Banan();
        Äpple ä = new Äpple();
    }
}

Rättningskommentar:
Det här är enklast möjliga lösning som fortfarande uppfyller kraven i uppgiften, men den är förstås inte särskilt användbar innan man kompletterat den med bland annat konstruktorer.

Uppgift 3 (6 p)

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

public class Applet extends JApplet implements ActionListener {
    private JTextField indata = new JTextField(10);
    private JButton plusButton = new JButton("+");
    private JTextField resultat = new JTextField(10);
    private int summa = 0;

    public void actionPerformed(ActionEvent event) {
        String s = indata.getText();
        try {
            int n = Integer.parseInt(s);
            summa = summa + n;
            resultat.setText(summa + "");
        }
        catch (NumberFormatException exc) {
            resultat.setText("ERROR");
        }
    } // actionPerformed

    public void init() {
        plusButton.addActionListener(this);
        Container cp = getContentPane();
        cp.setLayout(new FlowLayout());
        cp.add(indata);
        cp.add(plusButton);
        cp.add(resultat);
        resultat.setText(summa + "");
    }
} // class Applet

Uppgift 4 (7 p)

class MängdenFullException extends Exception {

}

class Mängd {
    private final static int MAX_ELEMENT = 10;
    private Object[] elementen = new Object[MAX_ELEMENT];
    private int antalElement = 0;

    public void läggTill(Object elementet)
      throws MängdenFullException {
        if (finns(elementet)) {
            // Elementet finns redan i mängden. Gör ingenting.
        }
        else if (antalElement >= MAX_ELEMENT) {
            throw new MängdenFullException();
        }
        else {
            elementen[antalElement++] = elementet;
        }
    } // läggTill

    public void taBort(Object elementet) {
	for (int i = 0; i < antalElement; ++i) {
	    if (elementet.equals(elementen[i])) {
		for (int j = i; j < antalElement - 1; ++j)
		    elementen[j] = elementen[j + 1];
		--antalElement;
		return;
	    }
	}
	// Elementet fanns inte i mängden. Gör ingenting.
    } // taBort

    public boolean finns(Object elementet) {
        for (int i = 0; i < antalElement; ++i)
            if (elementet.equals(elementen[i]))
                return true;
        return false;
    }
} // Mängd

Uppgift 5 (9 p)

a)

import java.util.Iterator;

class MängdenFullException extends Exception {

}

class MängdIterator implements Iterator {
    private Mängd mängden;
    private Object[] elementen;
    private int antalElement;
    private int nästaElement = 0;

    public MängdIterator(Mängd mängden, Object[] elementen, int antalElement) {
        this.mängden = mängden;
        this.elementen = elementen;
        this.antalElement = antalElement;
    }

    public boolean hasNext() {
        return (nästaElement < antalElement);
    }
    public Object next() {
        return elementen[nästaElement++];
    }
    public void remove() {
        throw new UnsupportedOperationException();
    }
} // MängdIterator

b)

public MängdIterator iterator() {
    return new MängdIterator(this, elementen, antalElement);
}

Rättningskommentar:
När man skapar iterator-objektet behövs det något sätt att överföra information om mängden från mängd-objektet till iterator-objektet. I den här lösningen skickar jag med informationen till konstruktorn, och lagrar sen informationen i medlemsvariabler i iterator-objektet.
Alternativ:
Man kunde ha låtit iterator-klassen vara en inre klass i mängd-klassen, och komma åt informationen direkt.
Man kunde ha särskilda åtkomstmetoder i mängd-klassen, för att låta ett iterator-objekt komma åt informationen.

c)

public static void main(String[] args) {
    Mängd m = new Mängd();
    for (int i = 1; i <= 5; ++i) {
        try {
            m.läggTill("Sträng " + i);
        }
        catch (MängdenFullException e) {
            System.err.println("Ojdå!");
        }
    }
    for (Iterator i = m.iterator(); i.hasNext(); )
        System.out.println("Ett element: " + i.next());
}

d)

class BättreMängdIterator extends MängdIterator {
    public BättreMängdIterator(Mängd mängden, Object[] elementen, int antalElement) {
	super(mängden, elementen, antalElement);
    }

    public void remove() {
	// Här ska man egentligen göra en del kollar,
	// till exempel att next() verkligen har anropats,
	// men det struntar vi i!
	mängden.taBort(elementen[nästaElement - 1]);
	--nästaElement;
	--antalElement;
    }
} // BättreMängdIterator

Rättningskommentar:
Här bör man se upp så att iterator-objektet verkligen kommer åt informationen inuti mängd-objektet, och kan ändra den. Den enklaste lösningen är att anropa metoden taBort, som sköter borttagandet. I en riktig iterator ska det sen gå att iterera vidare, och det råkar den här lösningen klara.

Uppgift 6 (6p)

a)

class RoligTråd extends Thread {
    public void run() {
        while (true)
            System.out.println("Java är roligt!");
    }
}

public class Uppgift6 {
    public static void main(String[] args) {
        for (int i = 0; i < 1000; ++i) {
            RoligTråd t = new RoligTråd();
            t.start();
        }
    }
}

b)

Det finns (med största sannolikhet) inte tusen fysiska processorer i datorn, så de tusen trådarna får dela på en (eller ett fåtal) processorer. Eftersom det dessutom går åt tid till att byta mellan trådarna, blir det mindre arbete gjort med flera trådar än med en enda.

Dessutom är det troligen inte processorns hastighet som är den begränsande faktorn för hur mycket text som kan matas ut på standardutmatningen, utan olika I/O-kretsar i hårdvaran och I/O-funktioner i operativsystemet. De arbetar inte fortare för att Java-programmet har fler trådar.


Thomas Padron-McCarthy (Thomas.Padron-McCarthy@tech.oru.se) 4 februari 2005