1. Tip Tahmini

Referans tiplerini (sınıfları) saklayan değişkenler de farklı tiplere dönüştürülebilir. Ancak bu yalnızca tek bir tür hiyerarşisi içinde çalışır. Basit bir örneğe bakalım. Aşağıdaki sınıfların yukarıdaki sınıfları miras aldığı aşağıdaki sınıf hiyerarşisine sahip olduğumuzu varsayalım.

daktilo

İlkel türlerin yanı sıra referans türlerinin tip tahmini de genişletme ve daraltma olarak kategorize edilir.

Cat sınıfının Pet sınıfını ve Pet sınıfının da Animal sınıfını miras aldığını görüyoruz.

Şöyle bir kod yazarsak:

Animal kitten = new Cat();

Bu, genişleyen bir tür dönüştürmedir . Aynı zamanda örtük döküm olarak da adlandırılır. cat referansını, artık bir Cat nesnesine atıfta bulunacak şekilde genişlettik . Bunun gibi bir tür dönüştürme ile, Cat sınıfında bulunan ancak Animal sınıfında olmayan yöntemleri çağırmak için yavru kedi referansını kullanamayacağız .

Ters yönde bir daraltma dönüştürmesi (veya açık atama) gerçekleşir:

Cat cat = (Cat) kitten;

Kitty değişkeninde (tipi Animal olan ) saklanan referansı Cat tipine dönüştürmek istediğimizi açıkça belirttik .



2. Bir nesnenin türünü kontrol etme

Ancak burada çok dikkatli olmalısınız. Eğer bunu yaparsan:

Animal beast = new Cat();
Wolf grayWolf = (Wolf) beast;

Derleyici bu koda izin verecektir, ancak program çalışırken bir hata olacaktır ! JVM bir istisna atar:

Exception in thread "main" java.lang.ClassCastException: Cat cannot be cast to a Wolf

Bir Cat nesnesine yapılan başvurular, yalnızca türü Cat sınıfının atası olan değişkenlerde saklanabilir: Pet, Animal veya Object.

Nedenmiş?

Buradaki ilgili nokta, bir nesne referansının, o nesnenin yöntemlerine ve değişkenlerine atıfta bulunmak için kullanılmasıdır . Ve bir Cat nesnesine referans depolamak için bir Animal değişkeni kullanırsak herhangi bir sorun olmaz: Cat türü her zaman Animal türünden değişkenlere ve yöntemlere sahiptir — onları miras almıştır!

Ancak JVM, bir Cat nesnesine bir başvuruyu bir Wolf değişkeninde saklamamıza izin verdiyse, o zaman o değişkende depolanan Cat nesnesinde bulunmayan bir yöntemi çağırmak için grayWolf değişkenini kullanmayı deneyebileceğimiz bir durumla karşılaşabiliriz. . Bu yüzden bu düzenlemeye izin verilmiyor.

instanceofJava , bir nesnenin belirli bir türde olup olmadığını ve bu nedenle belirli bir türdeki bir değişkende depolanabileceğini kontrol etmenizi sağlayan özel bir operatöre sahiptir . Oldukça basit görünüyor:

variable instanceof Type

Örnek:

Animal beast = new Cat();
if (beast instanceof Wolf)
{
   Wolf grayWolf = (Wolf) beast;
}

Bu kod, çalışma zamanında bile hatalara neden olmaz.

İşte durumu gösteren birkaç örnek daha:

Genişletme tipi dönüştürme Tanım
Cow cow = new Whale();

Bu, klasik bir genişletme dönüştürmesidir - tür dönüştürme operatörü gerekmez. Artık nesne üzerinde yalnızca sınıfta tanımlanan yöntemler Cowçağrılabilir Whale.

değişkeninde cow, derleyici yalnızca türünün (sınıfın Cow) sahip olduğu yöntemleri çağırmanıza izin verecektir.

Daraltma tipi dönüştürme
Cow cow = new Whale();
if (cow instanceof Whale)
{
   Whale whale = (Whale) cow;
}
Klasik daraltma dönüştürmesi: Bir tür denetimi ve bir atama işleci eklemeniz gerekir.
Değişken Cow cow, bir nesneye referans depolar Whale.
Durumun böyle olduğunu doğrularız ve ardından bir (daraltma) tür dönüştürmesi gerçekleştiririz. Veya şu şekilde de adlandırılır:
bir tip döküm
.

Cow cow = new Cow();
Whale whale = (Whale) cow; // Exception
Nesnenin tipini kontrol etmeden bir referans tipini daraltabilirsiniz.
Değişken cow, a olmayan bir nesneye başvuruyorsa Whale, o zaman an InvalidClassCastExceptionoluşturulur.


3. Orijinal yöntemi çağırmak: superanahtar kelime

Bir üst sınıfın yöntemini geçersiz kılarken, bazen onu kendi yöntemimizle değiştirmek yerine, onu yalnızca biraz tamamlamak isteriz.

Ana sınıfın yöntemini kendi yöntemimizde kullanabilsek ve sonra kendi kodumuzun bir kısmını çalıştırabilsek harika olurdu. Ya da belki önce kendi kodumuzu çalıştırın ve sonra üst sınıfın yöntemini çağırın.

Ve Java tam da bunu yapmamıza izin veriyor. Üst sınıfın bir yöntemini çağırmak için şunu yapın:

super.method(arguments);

Örnekler:

class PeaceTime
{
   public double getPi()
   {
      return 3.14;
   }
}

class WarTime extends PeaceTime
{
   public double getPi()
   {
      return super.getPi()*2;  // 3.14*2
   }
}

Savaş zamanında değeri Pi6'dan büyük olabilir! Elbette şaka yapıyoruz, ancak bu örnek tüm bunların nasıl çalışabileceğini gösteriyor.

İşleri biraz netleştirmek için birkaç örnek daha:

kod Tanım
class Cow
{
   public void printAll()
   {
      printColor();
      printName();
   }

   public void printColor()
   {
      System.out.println("I'm a white whale");
   }

   public void printName()
   {
      System.out.println("I'm a cow");
   }
}

class Whale extends Cow
{
   public void printName()
   {
      System.out.print("This is incorrect: ");
      super.printName();
      System.out.println("I'm a whale");
   }
}
Cowve Whalesınıflar
public static void main(String[] args)
{
   Whale whale = new Whale();
   whale.printAll();
}
Ekran çıktısı şöyle olacaktır:
I'm a white whale
This is incorrect: I'm a cow
I'm a whale

Bu zor bir şey. Dürüst olmak gerekirse, OOP'deki en zor şeylerden biri . Bununla birlikte, onu bilmeniz ve anlamanız gerekiyor.