Java Language
Onveranderlijke Klasse
Zoeken…
Invoering
Onveranderlijke objecten zijn instanties waarvan de status niet verandert nadat deze is geïnitialiseerd. String is bijvoorbeeld een onveranderlijke klasse en zodra deze is gestart, verandert de waarde ervan nooit.
Opmerkingen
Enkele onveranderlijke klassen in Java:
- java.lang.String
- De wrapper-klassen voor de primitieve typen: java.lang.Integer, java.lang.Byte, java.lang.Character, java.lang.Short, java.lang.Boolean, java.lang.Long, java.lang.Double, java.lang.Float
- De meeste opsommingsklassen zijn onveranderlijk, maar dit is in feite afhankelijk van het concrete geval.
- java.math.BigInteger en java.math.BigDecimal (ten minste objecten van die klassen zelf)
- java.io.File. Merk op dat dit een extern object vertegenwoordigt van de VM (een bestand op het lokale systeem), dat al dan niet bestaat, en dat sommige methoden de status van dit externe object wijzigen en doorzoeken. Maar het File-object zelf blijft onveranderlijk.
Regels om onveranderlijke klassen te definiëren
De volgende regels definiëren een eenvoudige strategie voor het maken van onveranderlijke objecten.
- Geef geen "setter" -methoden - methoden die velden of objecten wijzigen waarnaar door velden wordt verwezen.
- Maak alle velden definitief en privé.
- Sta niet toe dat subklassen methoden overschrijven. De eenvoudigste manier om dit te doen, is door de klas als definitief te verklaren. Een meer geavanceerde aanpak is om de constructeur privé te maken en instanties te bouwen in fabrieksmethoden.
- Als de instantievelden verwijzingen naar veranderlijke objecten bevatten, staat u niet toe dat deze objecten worden gewijzigd:
- Geef geen methoden die de veranderlijke objecten wijzigen.
- Deel geen verwijzingen naar de veranderlijke objecten. Sla nooit verwijzingen op naar externe, veranderlijke objecten die aan de constructor zijn doorgegeven; maak zo nodig kopieën en sla verwijzingen naar de kopieën op. Maak op dezelfde manier kopieën van uw interne veranderlijke objecten wanneer dat nodig is om te voorkomen dat de originelen in uw methoden worden geretourneerd.
Voorbeeld zonder veranderlijke refs
public final class Color {
final private int red;
final private int green;
final private int blue;
private void check(int red, int green, int blue) {
if (red < 0 || red > 255 || green < 0 || green > 255 || blue < 0 || blue > 255) {
throw new IllegalArgumentException();
}
}
public Color(int red, int green, int blue) {
check(red, green, blue);
this.red = red;
this.green = green;
this.blue = blue;
}
public Color invert() {
return new Color(255 - red, 255 - green, 255 - blue);
}
}
Voorbeeld met veranderlijke refs
In dit geval is klasse Point veranderlijk en kan een gebruiker de status van het object van deze klasse wijzigen.
class Point {
private int x, y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}
//...
public final class ImmutableCircle {
private final Point center;
private final double radius;
public ImmutableCircle(Point center, double radius) {
// we create new object here because it shouldn't be changed
this.center = new Point(center.getX(), center.getY());
this.radius = radius;
}
Wat is het voordeel van onveranderlijkheid?
Het voordeel van onveranderlijkheid komt met gelijktijdigheid. Het is moeilijk om de correctheid van veranderlijke objecten te handhaven, omdat meerdere threads proberen de status van hetzelfde object te wijzigen, waardoor sommige threads een andere status van hetzelfde object zien, afhankelijk van de timing van het lezen en schrijven naar de genoemde voorwerp.
Door een onveranderlijk object te hebben, kan men ervoor zorgen dat alle threads die naar het object kijken dezelfde status zullen zien, omdat de status van een onveranderlijk object niet zal veranderen.