KALITIM
(Inheritance)
Java’da kalıtım nedir?
Nesne
Yönelimli Programlama dillerinde kalıtım olgusu, bir sınıfta (class)
tanımlanmış değişkenlerin ve/veya metotların (fonksiyon, procedure) yeniden
tanımlanmasına gerek olmaksızın yeni bir sınıfa taşınabilmesidir. Bunun için
yapılan iş, bir sınıftan bir alt-sınıf (subclass) türetmektir. Türetilen alt-sınıf,
üst-sınıfta tanımlı olan bütün değişkenlere ve metotlara sahip olur. Bu özeliğe
kalıtım özeliği (inheritance) diyoruz.
Programcı,
yeni alt-sınıfları tanımlarken, üst-sınıftan (superclass) kalıtsal olarak
geleceklere ek olarak, kendisine gerekli olan başka değişken ve metotları da
tanımlayabilir.
Bu yolla,
bir kez kurulmuş olan sınıfın tekrar tekrar kullanılması olanaklı olur.
Böylece, programlar daha kısa olur, programın yazılma zamanı azalır ve
gerektiğinde değiştirilmesi ve onarılması (debug) kolay olur.
Alt-sınıf türetme
hiyerarşik bir yapıda olur. Bir alt-sınıfın türetildiği sınıf, o alt-sınıfın
üst-sınıfıdır. Java’da bir alt-sınıfın ancak bir tane üst-sınıfı olabilir (C++
‘dakinden farklı olduğuna dikkat ediniz). Ama bir sınıftan birden çok alt-sınıf
türetilebilir.
Üst-sınıfa
ata (parent), alt-sınıfa da oğul (child) denir.
Örnekler
Liste 1:
Ön-tanımlı (default) belirtkeli sınıfta kalıtım
Liste 1 içindeki
sınıflar kalıtımın basit bir örneğidir. B sınıfı A sınıfının bir alt-sınıfıdır.
A sınıfının erişim belirtkesi olmadığından, ön-tanımlı (default) belirtke
etkindir. Dolayısıyla, A sınıfının değişkenlerini ve metodunu B sınıfı
kullanabilir.
/* A sınıfının değişken ve metodu B ye
* kalıtımsal
geçecektir.
*/ Üst sınıf tanımlanıyor.
class
A {
int i, j;
void showij() {
System.out.println("i and j: " + i
+ " " + j);
}
}
// A ‘nın B alt-sınıfı tanımlanıyor.
class
B extends A {
int k;
void showk() {
System.out.println("k: " + k);
}
void sum() {
System.out.println("i+j+k: " +
(i+j+k));
}
}
// Uygulama programı
// A ve B sınıflarına ait nesneler yaratılıyor.
// A ve B ile aynı pakette (aynı dizinde) bulunmalıdır.
class
BasitInheritance {
public static void main(String args[]) {
A ustOb = new A(); // A ‘ya ait
nesne
B altOb = new B(); // B ’ye ait
nesne
// Anlık
değişkenlere atama yapılıyor.
ustOb.i = 15;
ustOb.j = 25;
System.out.println(" ustOb nesnesinin
öğeleri: ");
ustOb.showij(); //ustOb ‘nin
öğelerini yazar
System.out.println();
/* Alt-sınıf
üst-sınıfın bütün
* öğelerine
erişebilir.
*/
altOb.i = 3;
altOb.j = 5;
altOb.k = 7;
System.out.println("altOb nesnesinin
öğeleri: ");
altOb.showij(); //üst-sınıftaki
değişkenleri yazar
altOb.showk(); //alt-sınıftaki
değişkeni yazar
System.out.println();
System.out.println("üst ve alt
sınıftaki değişkenler toplanıyor… ");
System.out.println("(i + j + k) =
");
altOb.sum();
}
}
Liste 2 :
private damgalı öğelere erişim
Üst-sınıfın private öğelerine, kendi alt sınıfı da
dahil olmak üzere başka hiçbir sınıftaki kodlar erişemez. Aşağıdaki listede
tanımlanan B alt-sınıfındaki kodlar, A üst-sınıfının private damgalı öğelerine erişemiyor.
/*
* Üst-sınıfın
private öğelerini
* alt-sınıfın
kodları kullanamaz.
*/
//
Üst-sınıf tanımlanıyor.
class
A {
int i; // erişim kısıtı yok
private int j; // erişim
kısıtlanıyor
void setij(int x, int y) {
i = x;
j = y;
}
}
// A'nın j
öğesine erişemez.
class
B extends A {
int toplam;
void sum() {
total = i + j; // HATA!, alt-sınıftaki bu kod j ye
erişemez
}
}
class
DegerVer {
public static void main(String args[]) {
B subOb = new B();
subOb.setij(15, 20);
subOb.sum();
System.out.println("Toplam : " +
subOb.toplam);
}
}
Liste 3:
Bu listede AltKutu alt-sınıfı, üst sınıfta olmayan bir değişken (agr) tanımlıyor. Bu değişken kutunun ağırlığını
tutacaktır. Bir sınıf içinde parametresiz ve parametreli yapıcılar (constructor
metodu) tanımlanabilir. Formal parametre(ler),
sınıfın anlık değişkenlerine değer atamak için, o tip(ler)den
seçilebileceği gibi, o sınıf tipinden de olabilir. Formal parametreli bir metot
çağrılırken, o parametrelere gerçek değerler verilir. Gerçek değerler, formal
parametrelerle aynı tipten olmalı ve aynı sırada yazılmalıdır. Formal parametre
bir sınıf tipinden ise, metot çağrılırken formal parametre yerine o sınıftan
bir nesne konulur.
/* Kutu – üst-sınıfının 3 tane anlık (instance)
değişkeni var.
*/
class
Kutu {
double en;
double boy;
double yukseklik;
// Parametreli
constructor tanımı.
// Parametre class
tipinden olabilir.
// Bu constructor
Kutu’nun bir kopyasını yaratıyor.
Kutu(Kutu
ob) { // parametre kendi sınıfının tipindendir.
en =
ob.en;
boy = ob.boy;
yukseklik = ob.yukseklik;
}
// Formal parametreli
constructor tanımı.
// Constructor
Kutu’nun boyutlarını belirliyor.
Kutu(double
e, double b, double y) { // boyutlar
için 3 parametre
en =
e;
boy = b;
yukseklik = y;
}
/*
*
parametresiz constructor tanımı.
* Henüz asıl değerlerin
verilmediğini belirtmek için
*
değişkenlere -1 değeri atanıyor.
*/
Kutu() {
en =
-1; // geçici değer
boy = -1; // geçici değer
yukseklik = -1; // geçici değer
}
// Formal parametreli
constructor tanımı.
// Constructor
Kutu’nun boyutlarını eşitliyor (küp oluşturuyor)
Kutu(double
uzunluk) {
en = boy = yukseklik = uzunluk;
}
// hacim hesaplar
double hacim()
{
return en * boy * yukseklik;
}
}
// alt-sınıf
tanımı
// Kutu’nun
değişkenlerine bir ek yapılıyor (agr).
class
AltKutu extends Kutu {
double agr; // Kutu’nun ağırlığı
// AltKutu için
constructor metodunun tanımı
AltKutu(double
e, double b, double y, double a) {
en =
e;
boy = b;
yukseklik = y;
agr = a;
}
}
// Uygulama programı.
class
DemoAltKutu {
public static void main(String args[]) {
AltKutu kutu1 = new AltKutu(15, 30, 25, 53.7);
AltKutu kutu2 = new AltKutu(4, 5, 6, 0.123);
double vol;
vol = kutu1.hacim();
System.out.println("kutu1 ‘in
hacmi = " + vol);
System.out.println("kutu1 ‘in ağırlığı
= " + kutu1.agr);
System.out.println();
vol = kutu2.hacim();
System.out.println("kutu2 ‘nin
hacmi = " + vol);
System.out.println("kutu2 ‘nin
ağırlığı = " + kutu2.agr);
}
}
Uyarı:
Aşağıdaki uygulama programı üst-sınıftan bir referansa (işaretçi, pointer)
alt-sınıftan bir referansın değerinin atanabileceğini göstermektedir. 3-üncü
satırda yaratılan ve alt-sınıfa ait olan nesnenin bellekteki adresini altKutu1 işaretçisi göstermektedir. 4-üncü satırda
yaratılan ve üst-sınıfa ait olan nesnenin bellekteki adresini ustKutu2 işaretçisi göstermektedir. 16-ıncı
satırdaki ustKutu2 = altKutu1;
ataması geçerlidir. Bu tür atamalar, bazen programcıya kolaylık sağlar. Burada
dikkat edilmesi gereken şey şudur. Üst-sınıfa ait işaretçisine alt-sınıf
işaretçisi atansa bile, üst-sınıftaki kodlar, alt-sınıftaki öğelere erişemez.
Oysa slt-sınıftaki kodlar, üst-sınıfta private damgası
taşımayan öğelere erişebilir.
/*
Bu uygulama programı referansların (işaretçi, pointer)
kullanılışını göstermektedir. */
class
UygulaPrg {
public static void main(String args[]) {
AltKutu altKutu1 = new AltKutu(4, 5, 6, 12.23);
Kutu ustKutu2 = new Kutu();
double vol;
vol = altKutu1.hacim();
System.out.println("altKutu1 in
hacmi = " + vol);
System.out.println("altKutu1 in
ağırlığı = " + altKutu1.agr);
System.out.println();
/*
* ustKutu2
işaretçisinin gösterdiği adres
* altKutu1
işaretçisinin gösterdiği adres ile aynı kılınıyor.
* Aynı tipten
referanslar eşitlenebibilir.
*/
ustKutu2 = altKutu1;
vol = ustKutu2.hacim(); // hacim(), Kutu ‘nun bir metodudur,
// dolayısyla kod
geçerlidir.
System.out.println("ustKutu2 ‘nin
hacmi = " + vol);
/* Aşağıdaki kod
geçersizdir, çünkü ustKutu2’nin
agr öğesi
yoktur. */
System.out.println("ustKutu2’ın ağırlığı
= " + ustKutu2.agr);
}
}