Commit 002fa3b5 authored by Børge Haugset's avatar Børge Haugset
Browse files

nytt arv/abstrkt

parent 41d41a6a
package uke13.abstrakt.bok;
public abstract class Bok {
private String tittel;
private int antallSider;
protected Bok(String tittel, int antallSider) {
super();
this.tittel = tittel;
this.antallSider = antallSider;
}
protected String toStringHelper() {
return "tittel=" + tittel + ", antallSider=" + antallSider;
}
@Override
public String toString() {
return getSjanger() + "[" + toStringHelper() + "]";
}
protected abstract String getSjanger();
public String getTittel() {
return tittel;
}
public int getAntallSider() {
return antallSider;
}
public static void main(String[] args) {
var roman = new Roman("Kurt koker hodet", 65); // Her støtter vi dog at forfatter er null...
System.out.println(roman);
var roman2 = new Roman("Kurt koker hodet", 65, "Erlend Loe");
System.out.println(roman2);
Bok bok = new Tegneseriealbum("Maus", 295);
System.out.println(bok);
}
}
package uke13.abstrakt.bok;
public class Roman extends Bok {
private String forfatter;
public Roman(String tittel, int antallSider) {
super(tittel, antallSider);
}
public Roman(String tittel, int antallSider, String forfatter) {
super(tittel, antallSider);
this.forfatter = forfatter;
}
protected String getSjanger() {
return "Roman";
}
protected String toStringHelper() {
return "forfatter=" + forfatter + ", " + super.toStringHelper();
}
}
package uke13.abstrakt.bok;
public class Tegneseriealbum extends Bok {
public Tegneseriealbum(String tittel, int antallSider) {
super(tittel, antallSider);
}
@Override
protected String getSjanger() {
return "Tegneseriealbum";
}
}
...@@ -5,6 +5,7 @@ import java.io.InputStream; ...@@ -5,6 +5,7 @@ import java.io.InputStream;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
public class ClassGetClass { public class ClassGetClass {
...@@ -17,8 +18,26 @@ public class ClassGetClass { ...@@ -17,8 +18,26 @@ public class ClassGetClass {
Class cls; Class cls;
try { try {
// GetClass()
ClassGetClass cgc = new ClassGetClass();
cls = cgc.getClass();
System.out.println("class: "+cls);
System.out.print("cls == ClassGetClass.class: ");
System.out.println(cls == ClassGetClass.class);
System.out.println("cls == Object.class: "+cls.equals(Object.class));
// Hva er forskjellen med denne og den over?
System.out.print("cgc instanceof ClassGetClass: ");
System.out.println(cgc instanceof ClassGetClass);
System.out.print("cgc instanceof Object: ");
System.out.println(cgc instanceof Object);
// Forskjellen er at instanceof også returnerer true for en subklasse.
// Linjen over returnerer _klasseobjektet_, ikke en instans av klassen. // Linjen over returnerer _klasseobjektet_, ikke en instans av klassen.
cls = Class.forName("uke13.arv.Bok"); cls = Class.forName("uke13.arv.bok.Bok");
System.out.println("Class found= "+ cls.getName()); System.out.println("Class found= "+ cls.getName());
System.out.println("Package found= "+ cls.getPackage()); System.out.println("Package found= "+ cls.getPackage());
...@@ -28,13 +47,14 @@ public class ClassGetClass { ...@@ -28,13 +47,14 @@ public class ClassGetClass {
// System.out.println(method); // System.out.println(method);
} }
// Dette under er ikke pensum, men tenker det kan være med å klargjøre hva vi snakker om: // Dette under er ikke viktig pensum, men tenker det kan være med å klargjøre hva vi snakker om:
// Vi kan bruke dette til blant annet å instansiere objekter ved kjøretid. Også for 'reflection' // Vi kan bruke dette til blant annet å instansiere objekter ved kjøretid. Også for 'reflection'
System.out.println("Antall konstruktører i Bok: "+cls.getConstructors().length); System.out.println("Antall konstruktører i Bok: "+cls.getConstructors().length);
System.out.println("Den første konstruktøren: "+cls.getConstructors()[0]); System.out.println("Den første konstruktøren: "+cls.getConstructors()[1]);
Bok bok = (Bok) cls.getConstructors()[0].newInstance("Tittel"); var bok = (uke13.arv.bok.Bok) cls.getConstructors()[1].newInstance("Tittel");
System.out.println("Bok: "+bok); System.out.println("Bok: "+bok);
} catch (ClassNotFoundException | IllegalArgumentException | SecurityException | InstantiationException | IllegalAccessException | InvocationTargetException e) { } catch (ClassNotFoundException | IllegalArgumentException | SecurityException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace(); e.printStackTrace();
} }
......
...@@ -8,6 +8,10 @@ public class MyObject { ...@@ -8,6 +8,10 @@ public class MyObject {
// return super.toString(); // return super.toString();
} }
public void lala() {
}
public static void main(String[] args) { public static void main(String[] args) {
MyObject mo = new MyObject(); MyObject mo = new MyObject();
System.out.println(mo); System.out.println(mo);
...@@ -15,9 +19,9 @@ public class MyObject { ...@@ -15,9 +19,9 @@ public class MyObject {
Object o = new Object(); Object o = new Object();
System.out.println(o.toString()); System.out.println(o.toString());
// Hva gjør den nå? // // Hva gjør den nå?
Object o2 = new MyObject(); Object o2 = new MyObject();
System.out.println(o2.toString()); System.out.println(o2.toString());
MyObject mo2 = (MyObject) o2;
} }
} }
...@@ -9,7 +9,8 @@ public class NameValidationException extends IllegalArgumentException{ ...@@ -9,7 +9,8 @@ public class NameValidationException extends IllegalArgumentException{
this.illegalName = illegalName; this.illegalName = illegalName;
} }
// Merk at vi ikke har noen toString() her. Det har ingen unntak, så vi må helt opp til Throwable // Merk at vi ikke har noen toString() her. Det har ingen unntak, så vi må helt opp til Throwable
// (se F4)
@Override @Override
// Denne skrives ut i catch-metoden i person. Via Throwable sin getLocalizedMessage(). // Denne skrives ut i catch-metoden i person. Via Throwable sin getLocalizedMessage().
......
...@@ -31,8 +31,8 @@ public class Person { ...@@ -31,8 +31,8 @@ public class Person {
} }
// Trenger ikke returnere noe, den utløser unntak hvis den finner noe. // Trenger ikke returnere noe, den utløser unntak hvis den finner noe.
// Unntaket skriver ikke automatisk ut, men det // Unntaket skriver ikke automatisk ut, men det skrives ut der en fanger opp feilen,
// Det skrives ut der en fanger opp feilen, se catch i main. // se catch i main.
private void checkName(final String name) { private void checkName(final String name) {
for (int i = 0; i < name.length(); i++) { for (int i = 0; i < name.length(); i++) {
final char c = name.charAt(i); final char c = name.charAt(i);
...@@ -55,7 +55,7 @@ public class Person { ...@@ -55,7 +55,7 @@ public class Person {
System.out.println(c.contains(new Person("Anne"))); // Nope System.out.println(c.contains(new Person("Anne"))); // Nope
System.out.println(c.contains(new Person("Per"))); // Yay, siden alt vi sjekker for likhet er navnet. System.out.println(c.contains(new Person("Per"))); // Yay, siden alt vi sjekker for likhet er navnet.
// Lysark 21 // Lysark NameValidationException
Person p2 = new Person("Per Berg-Hansen"); // Lovlig grunnet indexOf-sjekken. Person p2 = new Person("Per Berg-Hansen"); // Lovlig grunnet indexOf-sjekken.
Person p3 = new Person("Per@Hansen"); // ulovlig Person p3 = new Person("Per@Hansen"); // ulovlig
System.out.println(p.getName()); System.out.println(p.getName());
......
package uke13.arv; package uke13.arv;
// Records har ingen kostruktører, gettere eller settere. // Records har ingen konstruktører, gettere eller settere.
// Ingen verdier kan endres, det er kun lagring. OG den har // Ingen verdier kan endres, det er kun lagring. OG den har
// automatisk likhetskontroll som sjekker alle felt. // automatisk likhetskontroll som sjekker alle felt.
public record Point(double x, double y) { public record Point(double x, double y) {
......
...@@ -8,6 +8,37 @@ public class UnderstandEquals { ...@@ -8,6 +8,37 @@ public class UnderstandEquals {
this.streng = ting; this.streng = ting;
} }
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((streng == null) ? 0 : streng.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
UnderstandEquals other = (UnderstandEquals) obj;
if (streng == null) {
if (other.streng != null)
return false;
} else if (!streng.equals(other.streng))
return false;
return true;
}
public static void main(String[] args) { public static void main(String[] args) {
// Kommentarer for utvidelse nederst // Kommentarer for utvidelse nederst
......
package uke13.arv.bok;
public class Bok {
private String tittel;
private String specialCharacters = " -,.%";
public Bok() {
}
public Bok(String tittel) {
setTittel(tittel);
}
public String getTittel() {
return tittel;
}
protected String getToStringAttributes() {
return "tittel=" + tittel; }
@Override
public String toString() {
return getToStringAttributes();
}
public void setTittel(String tittel) {
if (!isValidTittel(tittel)) {
throw new IllegalArgumentException(tittel+" er ikke en gyldig boktittel.");
}
this.tittel = tittel;
}
public boolean isValidTittel(String tittel) {
// System.out.println("Bok.isValidTittel");
for (int i = 0; i < tittel.length(); i++) {
char c = tittel.charAt(i);
if (! (Character.isLetter(c) || Character.isDigit(c) ||
specialCharacters.indexOf(c) >= 0)) {
return false;
}
}
return true;
}
public static void main(String[] args) {
Bok bok = new Bok("Titten tei på eventyr");
System.out.println(bok);
// Sjekk av tittel i setTitle, som kalles i konstruktøren
// Bok bok2 = new Bok("Hei{");
// System.out.println(bok2); // Vil utløse unntak
// For isValidTitle()
Bok bok3 = new Bok("Titten tei på eventyr");
System.out.println(bok3);
Bok ordbok = new Ordbok("Engelsk-norsk ordbok", 33);
Bok tegneseriealbum = new Tegneseriealbum("Asterix og romerne", 43);
// Vi kan ikke kalle tegneseriealbum.getAntallStriper, men siden toString kaller
// toString overskygget i Tegneseriealbum vises det allikevel:
System.out.println(tegneseriealbum);
// Arv arver også hva de er er:
System.out.println("ordbok er en Bok: "+(ordbok instanceof Bok));
System.out.println("ordbok er en Ordbok: "+(ordbok instanceof Ordbok));
System.out.println("ordbok er classen Bok: "+(ordbok.getClass() == Bok.class));
System.out.println("ordbok er classen Ordbok: "+(ordbok.getClass() == Ordbok.class));
// Substitusjonsprinsippet:
Bok bok4 = new Ordbok();
bok.setTittel("Egentlig ikke noen ordbok");
System.out.println(bok4.toString()); // Hva skjer her?
Bok bok5 = new Ordbok("Ikke ordbok", 234);
System.out.println(bok5.toString()); // Hva skjer her?
}
}
package uke13.arv.bok;
public class Ordbok extends Bok{
int antallOrd;
public Ordbok() {
super();
}
public Ordbok(String tittel, int antallOrd) {
super(tittel);
this.antallOrd = antallOrd;
}
public void setAntallOrd(int antallOrd) {
this.antallOrd = antallOrd;
}
public int getAntallOrd() {
return antallOrd;
}
// Skygger over Bok.getToStringAttributes(), men bruker den!
protected String getToStringAttributes() {
return super.getToStringAttributes() + ", antallOrd=" + antallOrd;
}
public static void main(String[] args) {
Bok bok = new Ordbok();
bok.setTittel("Lawrence of Arabia");
System.out.println(bok);
Ordbok ordbok = new Ordbok("Nynorsk ordbok", 654);
System.out.println(ordbok);
}
}
package uke13.arv.bok;
public class Tegneseriealbum extends Bok {
int antallStriper;
public Tegneseriealbum(String tittel, int antallStriper) {
super(tittel); // Merk at vi bruker Bok sin konstruktør, for å sjekke tittelkorrekthet
this.antallStriper = antallStriper;
}
public int getAntallStriper() {
return antallStriper;
}
// Denne kalles når en Bok kalles med toString().
protected String getToStringAttributes() {
return super.getToStringAttributes() + ", antallStriper=" + antallStriper;
}
public void setAntallStriper(int antallStriper) {
this.antallStriper = antallStriper;
}
}
package uke13.arv.bok_avansert;
public class Bok {
private String tittel;
private String specialCharacters = " -,.%";
private String ulovligeBokstaver = "#¤([]){]}";
@Override
public String toString() {
// Den første skriver bare ut for bok. Men dersom du lager en
// ny metode, kaller den, og den kan skygges over av subklasser,
// da kan en ende opp med en fin løsning. Når du kaller toString
// på en Ordbok vil den ende opp i Bok.toString() siden Ordbok ikke
// implementerer denne. Kallet vil allikevel rutes tilbake til
// Ordbok.GetToStringAttributes()!
// return "Bok [tittel=" + tittel + "]";
return GetToStringAttributes();
}
protected String GetToStringAttributes() {
return "tittel=" + tittel; }
public Bok() {
super();
}
public Bok(String tittel) {
setTittel(tittel);
}
public String getTittel() {
return tittel;
}
public void setTittel(String tittel) {
if (!isValidTitle(tittel)) {
throw new IllegalArgumentException(tittel+" er ikke en gyldig boktittel.");
}
this.tittel = tittel;
}
public boolean isValidTitle(String tittel) {
// System.out.println("Bok.isValidTittel");
for (int i = 0; i < tittel.length(); i++) {
char c = tittel.charAt(i);
if (! (Character.isLetter(c) || Character.isDigit(c) ||
specialCharacters.indexOf(c) >= 0)) {
return false;
}
}
return true;
}
public static void main(String[] args) {
Bok bok = new Bok("Titten tei på eventyr");
System.out.println(bok);
// Sjekk av tittel i setTitle, som kalles i konstruktøren
// Bok bok2 = new Bok("Hei{");
// System.out.println(bok2); // Vil bli null
// For isValidTitle()
Bok bok3 = new Bok("Titten tei på eventyr");
System.out.println(bok3);
Bok ordbok = new Ordbok("Engelsk-norsk ordbok", 33);
Bok tegneseriealbum = new Tegneseriealbum("Asterix og romerne", 43);
// Vi kan ikke kalle tegneseriealbum.getAntallStriper, men siden toString kaller
// toString overskygget i Tegneseriealbum vises det allikevel:
System.out.println(tegneseriealbum);
}
}
package uke13.arv.bok_avansert;
public class Ordbok extends Bok {
int antallOrd;
public Ordbok(String tittel, int antallOrd) {
super(tittel); // Merk at vi bruker Bok sin konstruktør, for å sjekke tittelkorrekthet
this.antallOrd = antallOrd;
}
public int getAntallOrd() {
return antallOrd;
}
public void setAntallOrd(int antallOrd) {
this.antallOrd = antallOrd;
}
public void setTittel(String tittel) {
// System.out.println("Ordbok.setTittel");
if (! isValidTitle(tittel))
throw new IllegalArgumentException(tittel +
" er ikke rett navn på en ordbok");
// this.tittel = tittel; // Men da tester en ikke for feil tegn... Da må en:
super.setTittel(tittel);
}
// isValidTitle overskygger Bok sin, men den sjekker på noe annet...
// Det nye kravet er at en ordbok må slutte på "ordbok". Vi må allikevel
// også huske på å sjekke at den følger super sine krav, så det kan sjekkes først:
public boolean isValidTitle(String tittel) {
// System.out.println("Ordbok.isValidTitle");
if (! super.isValidTitle(tittel)) {
return false;
}
return tittel.endsWith("ordbok");
}
// Denne kalles når en Bok kalles med toString().
protected String GetToStringAttributes() {
return super.GetToStringAttributes() + ", antallOrd=" + antallOrd;
}
public static void main(String[] args) {
Ordbok ordbok = new Ordbok("Nynorsk ordbok", 98543);
System.out.println(ordbok);
// Ordbok ordbok2 = new Ordbok("Nynorsk ordbøk", 98543);
// System.out.println(ordbok2);
System.out.println(ordbok instanceof Bok);
System.out.println(ordbok.getClass().equals(uke13.arv.bok_avansert.Bok.class));
System.out.println(ordbok.getClass().equals(uke13.arv.bok_avansert.Ordbok.class));
// Substitusjonsprinsippet, kan vi bruke dette fullstendig her?
// Vi kan ikke bruke Ordbok for å lage alle slags bøker, da vi har krav for tittel
// Vi setter altså større krav til en tittel her enn for en Bok. Da virker ikke substitusjonsprinsippet
// I tillegg krever vi antallOrd i konstruktøren...
// Se https://stackoverflow.com/questions/56860/what-is-an-example-of-the-liskov-substitution-principle
// Bok bok = new Ordbok(""); // Går jo ikke.
// En bedre løsning er å bruke abstrakte klasser, og/eller interface.
}
}
package uke13.arv.bok_avansert;
public class Tegneseriealbum extends Bok {
int antallStriper;
public Tegneseriealbum(String tittel, int antallStriper) {