1. Subklass och Superklass
Arv är en central del av objektorientering.
- Subklassen är den nya klassen som ärver av den redan existeradne klassen.
- Superklassen är den klass som man ärver av. Klassen Object är alla klassers superklass.
I java ärver en klass alltid från en och endast en klass. class x extends y betyder att klass x ärver av klass y. Om extends saknas ärver Java från Object. Nedan ges ett exempel:
class TestExtends{
public static void main(String[] args){
B b=new B();
System.out.println("name="+b.name);
}
}
class A{ String name="Olle";}
class B extends A{ String address;}
|
[olle@dev1]$ java TestExtends
name=Olle
|
2. Konstruktorer och arv
Konstruktorerna kan använda de ärvda konstruktorerna från superklassen. Nedan listas några regler om hur super()-konstruktorn används:
- Man kan anropa en konstruktor hos superklassen med super(...), där ... står för de parametrar superklassens konstruktorer kan ta. Metoden super(...) fungerar precis som superklassens konstruktorer.
- super(...)-anropet måste stå på konstruktorns första rad.
- Om det inte finns något super(...)-anrop på konstruktorns första rad lägger kompilatorn in ett anrop till kostruktorn super(). Alltså kan man inte undgå att anropa konstruktorn för superklassen.
- Om du ärver av en klass annan än Object och din konstruktor inte innehåller super(...) kan du alltså få ett kompileringsfel om superklassen inte har någon konstruktor utan parametrar.
Nedan ges ett exempel:
class TestSuper{
public static void main(String[] args){
B b=new B("Anna","Orebro");
System.out.println("name="+b.name);
System.out.println("address="+b.address);
}
}
class A{
String name="Olle";
A(String n){ name=n;}
}
class B extends A{
String address;
B(String n, String a){
super(n);
address=a;
}
}
|
När vi kör exemplet får vi:
[olle@dev1]$ java TestSuper
name=Anna
address=Orebro
|
OBS! Om satsen super(n); tas bort ur klass B kan programmet inte kompilera, eftersom klassen A inte har någon A()-konstruktor.
3. Gränssnitt
Eftersom multipelt arv inte är tillåtet i Java använder man gränssnitt istället.
- Gränssnitt fungerar som klasser men kan bara ha abstrakta metoder och static final variabler. Skriv inte ut nyckelordet abstract i metoddeklarationenerna.
- Gränssnitt ska skrivas i en egen .java-fil, och vara medlemmar i paket, precis som klasser.
- Gränssnitt kan ärva av andra gränssnitt.
- En klass implementerar ett gränssnitt genom att implementera alla metoder som hör till gränssnittet.
- En klass kan implementera hur många gränssnitt som helst.class x implements y,z innebär att klassen x implementerar gränssnitten y och z.
Nedan ges ett exempel på ett gränssnitt:
class TestInterface{
public static void main(String[] args){
Adder a=new A();
System.out.println(a.add(1,1));
}
}
interface Adder{
public int add(int x, int y);
}
class A implements Adder{
public int add(int x,int y){
return x+y+7;
}
}
|
Satsen Adder a=new A(); skapar ett objet av klassen A som tilldelas en referens av gränssnittet Adder. Detta är fullt godkänt.
[olle@dev1]$ java TestInterface
9
|
4. Överridning
Vid arv får subklassen tillgång till superklassens metoder. Överridning betyder att man deklarerar en metod i subklassen med samma namn, parametrar och returtyp som en metod i superklassen.
- Alla metoder som deklarerats abstract måste överridas, annars måste subklassen deklareras abstract.
- Metoder som deklarerats final kan inte överridas.
- När man överrider en synchronized metod behöver inte metoden i subklassen vara synchronized.
- En överriden metod kan bara göras mer publik än metoden i superklassen. Annars kan kod som använder superklassen sluta fungera. Ordningen från minst publik till och mest är: private, (inget), protected och public.
- När man överrider en metod som kastar ett undantag, behöver inte metoden i subklassen kasta något undantag. Men ska metoden i subklassen kasta något undantag så måste det vara samma undantag eller en subklass till undantaget. Om man skulle tillåta den nya metoden att kasta ett mer generellt undantag så skulle kod som använder superklassen sluta fungera.
- Även variabler kan överridas, men varför skulle någon vilja göra det?
I exemplet nedan överrids metoden print():
class TestOverride{
public static void main(String[] args){
B b=new B();
b.print();
A a=b;
a.print();
}
}
class A{
void print(){
System.out.println("Super");
}
}
class B extends A{
void print(){
System.out.println("Sub");
}
}
|
Även i andra anropet är det Bs metod som används. Det är därför att ett objekt alltid kommer ihåg vad det är för typ.
[olle@dev1]$ java TestOverride
Sub
Sub
|
5. Typomvandlingar
En referenstyp av superklass kan peka på ett objekt av en subklass. Ett objekt kommer alltid ihåg vad det är, oavsett vilken referenstyp som pekar på det. Samlingsklasserna har bara Object-referenser, och kan därför lagra allt. När man tar ut ett objekt från en samlingsklass måst man typomvandla det:
import java.util.*;
class TestConv{
public static void main(String[] args){
List l=new ArrayList(2);
l.add(new Integer(5));
Integer i;
i=(Integer) l.get(0);
System.out.println(i.intValue());
}
}
|
Vi testar programmet:
[olle@dev1]$ java TestConv
5
|
6. instanceof
Ibland vet man inte vilken typ av objekt som ligger lagrat i en referens. Med instanceof kan man kontrollera huruvida ett objekt är av en viss klass eller ett visst gränssnitt. Operatorn tar som vänster operand en referens och som höger operand en referenstyp. Om objektet är av referenstypen eller en subklass till referenstypen så returneras true. Nedan ges ett exempel:
import java.util.*;
class TestInstanceof{
public static void main(String[] args){
HashSet hs=new HashSet();
System.out.println(hs instanceof Set);
System.out.println(hs instanceof Object);
hs=null;
System.out.println(hs instanceof Set);
System.out.println(hs instanceof Object);
}
}
|
Vi kör programmet:
[olle@dev1]$ java TestInstanceof
true
true
false
false
|
null är som vi ser inte en instans av någonting.