Sınıf değişkeni açısından yukarı ve aşağı döküm arasındaki fark nedir


138

Sınıf değişkeni açısından yukarı ve aşağı döküm arasındaki fark nedir?

Örneğin, aşağıdaki program sınıfında Animal yalnızca bir yöntem içerir, ancak Dog sınıfı iki yöntem içerir; bu durumda Dog değişkenini Animal Variable'a nasıl dönüştürdüğümüz.

Döküm yapılırsa, Animal'in değişkeniyle Köpeğin başka bir yöntemini nasıl çağırabiliriz.

class Animal 
{ 
    public void callme()
    {
        System.out.println("In callme of Animal");
    }
}


class Dog extends Animal 
{ 
    public void callme()
    {
        System.out.println("In callme of Dog");
    }

    public void callme2()
    {
        System.out.println("In callme2 of Dog");
    }
}

public class UseAnimlas 
{
    public static void main (String [] args) 
    {
        Dog d = new Dog();      
        Animal a = (Animal)d;
        d.callme();
        a.callme();
        ((Dog) a).callme2();
    }
}

A Dogbir Animal. Aşırı yüklenmiş bir yöntemi kullanmak istemediğiniz sürece çoğu zaman upcasting gereksizdir. callmeher ikisi de mevcut Animalve Dog. callme2sadece çalışmasını sağlamak için Dogyayınladığınız . aDog
Brian

Kodunuzun çıktısı nedir?
Malwinder Singh

İlginç olan, d.callme d hayvana döküm olmasına rağmen 'In callme of Dog' döndürür !!
Chris311

4
@ Chris311 hem 'd' hem de 'a' aynı nesneyi işaret ediyor ... ki bu bir Köpek, ama 'a' çalışma zamanında mahsup edildiğinde sadece Köpeğe özgü yöntemlere erişebiliyor. Etkisi: Hayvan a = (Hayvan) d; gereksizdir, sadece Animal a = d; upcasting gibi.
Mark Keen

Yanıtlar:


223

Upcasting bir üst tipe dökülürken downcasting bir alt tipe dökülür. Upcasting her zaman izin verilir, ancak downcasting bir tip kontrolü içerir ve a atabilir ClassCastException.

Senin durumunda bir bir döküm Dogbir karşı Animalbir nedeni, bir hava bacası olan Dogis-a Animal. Genel olarak, iki sınıf arasında bir ilişki olduğu zaman yukarı çıkabilirsiniz.

Aşağı indirme böyle bir şey olurdu:

Animal animal = new Dog();
Dog castedDog = (Dog) animal;

Temel olarak yaptığınız şey derleyiciye nesnenin çalışma zamanı türünün gerçekte ne olduğunu bildiğini söylemektir . Derleyici dönüşüme izin verir, ancak dönüşümün anlamlı olduğundan emin olmak için bir çalışma zamanı akıl sağlığı kontrolü ekler. Zamanında çünkü bu durumda, döküm mümkündür animalaslında bir olduğunu Dogbile olsa statik tip animalolduğunu Animal.

Ancak, bunu yapacak olsaydınız:

Animal animal = new Animal();
Dog notADog = (Dog) animal;

Bir alırsın ClassCastException. Bunun nedeni, animalçalışma zamanı türünün olmasıdır Animalve bu nedenle çalışma zamanına döküm işlemini gerçekleştirmesini söylediğinizde animal, bunun gerçekten a olmadığını görür Dogve a atar ClassCastException.

Bir üst sınıf yöntemini çağırmak için super.method()veya yukarı doğru yürüterek yapabilirsiniz.

Bir alt sınıfın yöntemini çağırmak için bir downcast yapmalısınız. Yukarıda gösterildiği gibi, normalde ClassCastExceptionbunu yaparak risk altındasınız; ancak, kullanabilirsiniz instanceofsen önlemek sağlayan döküm, gerçekleştirmeden önce nesnenin çalışma zamanı türünü kontrol etmesine ClassCastExceptions:

Animal animal = getAnimal(); // Maybe a Dog? Maybe a Cat? Maybe an Animal?
if (animal instanceof Dog) {
    // Guaranteed to succeed, barring classloader shenanigans
    Dog castedDog = (Dog) animal;
}

Düzgün iniş, hayır sağlar mı ClassCastExceptionalmaz mı? İlk durumda olduğu gibi mi?
Malwinder Singh

@MS "Doğru" ile ne demek istiyorsun?
awksp

2
@awksp Bu mükemmel ve eklemli bir cevap. Döküm hakkında bilmem gereken her şeyi özetliyor.
Gautham Honnavara

kuşkusuz, hayvanın köpek örneği olduğu sınıflar yapmadınız mı? peki neden kontrol ediyorsun?
barlop

62

Aşağı döküm ve yukarı döküm aşağıdaki gibidir:
resim açıklamasını buraya girin

Upcasting : Bir Sub sınıfını Super sınıfa atmak istediğimizde Upcasting (veya genişletme) kullanıyoruz. Otomatik olarak gerçekleşir, açıkça bir şey yapmanıza gerek yoktur.

Downcasting : Bir Super sınıfını Sub sınıfa dökmek istediğimizde Downcasting (veya daraltma) kullanıyoruz ve Java'da Downcasting doğrudan mümkün değil, açıkça yapmak zorundayız.

Dog d = new Dog();
Animal a = (Animal) d; //Explicitly you have done upcasting. Actually no need, we can directly type cast like Animal a = d; compiler now treat Dog as Animal but still it is Dog even after upcasting
d.callme();
a.callme(); // It calls Dog's method even though we use Animal reference.
((Dog) a).callme2(); // Downcasting: Compiler does know Animal it is, In order to use Dog methods, we have to do typecast explicitly.
// Internally if it is not a Dog object it throws ClassCastException

Öyleyse, yöntemin ebeveynini çağırmak için yayın yapmanın böyle bir yolu yok mu?
karlihnos

32

Upcasting ve downcasting, Java'nın basit bir sözdizimi kullanarak karmaşık programlar oluşturmamızı sağlayan ve Polimorfizm veya farklı nesneleri gruplandırma gibi büyük avantajlar sağlayan önemli bir parçasıdır. Java, alt sınıf türündeki bir nesneye, herhangi bir üst sınıf türünün nesnesi gibi davranılmasına izin verir. Buna upcasting denir. Upcasting otomatik olarak yapılır, downcasting manuel olarak programcı tarafından yapılmalıdır ve ben neden böyle olduğunu açıklamak için elimden geleni yapacağım.

Upcasting ve downcasting, birinden diğerine döküm ilkelleri DEĞİLDİR ve programcı döküm nesnelerini öğrenmeye başladığında çok fazla karışıklığa neden olan şey olduğuna inanıyorum.

Çok biçimlilik: Java'daki tüm yöntemler varsayılan olarak sanaldır. Bu, miras olarak kullanıldığında herhangi bir yöntemin, nihai veya statik olarak bildirilmediği sürece geçersiz kılınabileceği anlamına gelir .

getType();Nesne (Köpek, Evcil Hayvan, Polis Köpeği) türüne göre nasıl çalıştığını aşağıdaki örneği görebilirsiniz .

Üç köpeğiniz olduğunu varsayın

  1. Köpek - Bu süper Sınıf.

  2. Evcil Köpek - Evcil Köpek Köpek uzanır.

  3. Polis köpeği - polis köpeği evcil köpek uzatır.

    public class Dog{ 
       public String getType () {
          System.out.println("NormalDog");
          return "NormalDog";
       }
     }
    
    /**
     * Pet Dog has an extra method dogName()
     */   
    public class PetDog extends Dog{ 
       public String getType () {
          System.out.println("PetDog");
          return "PetDog";
       }
       public String dogName () {
          System.out.println("I don't have Name !!");
          return "NO Name";
       }
     }
    
    /**
     * Police Dog has an extra method secretId()
     */
    public class PoliceDog extends PetDog{
    
     public String secretId() {
        System.out.println("ID");
        return "ID";
     }
    
     public String getType () {
         System.out.println("I am a Police Dog");
         return "Police Dog";
     }
    }

Çok biçimlilik: Java'daki tüm yöntemler varsayılan olarak sanaldır. Bu, yöntem nihai veya statik olarak bildirilmedikçe, kalıtımda kullanıldığında herhangi bir yöntemin geçersiz kılınabileceği anlamına gelir (Açıklama, Sanal Tablolar Konseptine Aittir).

Sanal Tablo / Dağıtım Tablosu: Bir nesnenin dağıtım tablosu, nesnenin dinamik olarak bağlı yöntemlerinin adreslerini içerir. Yöntem çağrıları, yöntemin adresini nesnenin gönderim tablosundan getirerek gerçekleştirilir. Dağıtım tablosu aynı sınıfa ait tüm nesneler için aynıdır ve bu nedenle genellikle bunlar arasında paylaşılır.

public static void main (String[] args) {
      /**
       * Creating the different objects with super class Reference
       */
     Dog obj1 = new Dog();
`         /**
           *  Object of Pet Dog is created with Dog Reference since                
           *  Upcasting is done automatically for us we don't have to worry about it 
           *  
           */
     Dog obj2 = new PetDog();
`         /**
           *  Object of Police Dog is created with Dog Reference since                
           *  Upcasting is done automatically for us we don't have to worry       
           *  about it here even though we are extending PoliceDog with PetDog 
           *  since PetDog is extending Dog Java automatically upcast for us 
           */
      Dog obj3 = new PoliceDog();
}



 obj1.getType();

Baskılar Normal Dog

  obj2.getType();

Baskılar Pet Dog

 obj3.getType();

Baskılar Police Dog

Downcasting'in programcı tarafından manuel olarak yapılması gerekir

Eğer çağırmak çalıştığınızda secretID();üzerinde yöntemini obj3hangi PoliceDog objectbunlarla başvurulan Doghangi beri hatayı atar hiyerarşisinde bir süper sınıf obj3erişimi yok secretId()yöntemle. Bu yöntemi çağırmak için bu obj3'ü manuel olarak PoliceDog

  ( (PoliceDog)obj3).secretID();

hangi baskılar ID

Benzer şekilde dogName();, PetDogsınıftaki yöntemi çağırmak için , obj2'ye başvurulduğundan ve yönteme erişimi olmadığından aşağı obj2doğru indirmeniz gerekir.PetDogDogdogName();

  ( (PetDog)obj2).dogName();

Neden böyle, upcasting otomatik, ancak downcasting manuel olmalı? Bakın, upcasting asla başarısız olamaz. Farklı Köpekler bir grup var ve bunların türlerine bir hepsini downcast istiyorsanız, o zaman bir şans bu Köpekler bazılarının aslında farklı türlerden oldukları yani, yani var PetDog, PoliceDogve süreç atma yoluyla, başarısız ClassCastException.

Nesnelerinizi süper sınıf türüne yönlendirdiyseniz, nesnelerinizi el ile indirmeniz gerekir .

Not: Burada atıfta bulunarak, nesnelerinizin bellek adresini değiştirdiğinizde bellek adresini değiştirmediğiniz anlamına gelir, yine de aynı kalır, bu durumda bunları belirli bir türe gruplandırırsınız Dog


'Polimorfizm yöntem çağrıları sırasında otomatik downcast kullanır.' Hayır değil. Kullanılan mekanizma belirtilmemiştir, ancak en alışılmış mekanizma -vtable- böyle bir şey yapmaz. Nesne koduna bakın. Mahzun yok.
Lorne Marquis

Neden olmasın? Doğru olan budur, işe yaramayacağı bir örnek verebilir misiniz?
Nagarjuna Yelisetty

1
Neden olmasın? Doğru olan budur .. 'Polimorfizm yöntem çağrıları sırasında otomatik downcast kullanıyor' ifadesini verebilir misiniz? başarısız olur mu yoksa doğru olmaz mı?
Nagarjuna Yelisetty

Bu sizin çekişmeniz. Bunu kanıtlamak size kalmış. Nesne kodunda downcast'in nerede oluştuğunu gösterin. 'Neden olmasın' sorusunun cevabı gerekli değil çünkü. Vtable, yöntem dağıtımıyla ilgilenir ve değişken zaten tüm nesneyi gösterir.
Lorne Marquis

1
'Bildiğim kadarıyla ifadelerim doğrudur ve her durumda geçerlidir' bir kanıt değildir. Bu sadece bir iddiadır. Soruyorum size kanıtlamak için sizin ifadeleri. Sen yapmıyorsun. Aslında sadece kendinizi tekrarlıyorsunuz. Ve zaten birkaç çürütme sağladım. Ayrıca bir karar prosedürü de sağladım. Bir yöntem çağrısı için nesne kodunda bir downcast bulabilirsiniz, haklısın ve yanılıyorum. Bilim böyle yapılır. Yap. Ve 'cesaretle dokümantasyona bağlı olduğumu' iddia etmek açık bir yanlış beyan. Bunu yapma.
Lorne Marquis

12

Bu soruyu çok uzun zaman önce sordum ama bu sorunun yeni kullanıcıları için biliyorum. Lütfen instanceof operatörünün yayınlanması, indirilmesi ve kullanımı hakkında tam açıklama içeren bu makaleyi okuyun

  • Manuel olarak yukarı doğru sürmeye gerek yoktur, kendi başına gerçekleşir:

    Mammal m = (Mammal)new Cat(); eşittir Mammal m = new Cat();

  • Ancak altyazı her zaman manuel olarak yapılmalıdır:

    Cat c1 = new Cat();      
    Animal a = c1;      //automatic upcasting to Animal
    Cat c2 = (Cat) a;    //manual downcasting back to a Cat

Neden böyle, upcasting otomatik, ancak downcasting manuel olmalı? Bakın, upcasting asla başarısız olamaz. Ancak bir grup farklı hayvanınız varsa ve hepsini bir kediyi mahvetmek istiyorsanız, o zaman bu hayvanlardan bazılarının aslında köpek olmaları ve ClassCastException atarak işlemin başarısız olma olasılığı vardır. Burada, bir nesnenin bazı Sınıf örneği olup olmadığını sınayan "instanceof" adlı kullanışlı bir özellik bulunmalıdır .

 Cat c1 = new Cat();         
    Animal a = c1;       //upcasting to Animal
    if(a instanceof Cat){ // testing if the Animal is a Cat
        System.out.println("It's a Cat! Now i can safely downcast it to a Cat, without a fear of failure.");        
        Cat c2 = (Cat)a;
    }

Daha fazla bilgi için lütfen bu makaleyi okuyun


iyi nokta: Memeli m = (Memeli) yeni Cat (); Memeli m = yeni Cat ();
Catbuilts

6

Bu yöntemi upcasting için daha iyi deneyin, anlaşılması kolaydır:

/* upcasting problem */
class Animal
{ 
    public void callme()
    {
        System.out.println("In callme of Animal");
    }
}

class Dog extends Animal 
{ 
    public void callme()
    {
        System.out.println("In callme of Dog");
    }

    public void callme2()
    {
        System.out.println("In callme2 of Dog");
    }
}

public class Useanimlas 
{
    public static void main (String [] args) 
    {
        Animal animal = new Animal ();
        Dog dog = new Dog();
        Animal ref;
        ref = animal;
        ref.callme();
        ref = dog;
        ref.callme();
    }
}

ve son satırda şunlar olabilir: ((Köpek) ref) .callme2 (); // Dog sınıfının küçültme / daraltma ve callme2 () yöntemi erişimi için.
udarH3

6

Belki bu tablo yardımcı olur. callme()Sınıf Parentveya sınıf yöntemini çağırma Child. İlke olarak:

UPCASTING -> Gizleme

AĞIRLIK -> Ortaya Çıkarma

resim açıklamasını buraya girin

resim açıklamasını buraya girin

resim açıklamasını buraya girin


4

1.- Çıkarma.

Bir çıkma yaparken, bir alt türün bir nesnesine işaret eden bir tür etiket tanımlarsınız (daha rahat hissediyorsanız Tip ve alt tip sınıf ve alt sınıf olarak adlandırılabilir ...).

Animal animalCat = new Cat();

Bu tür bir etiket olan animalCat, yalnızca Animal türünün işlevselliğine (yöntemlerine) sahip olacağı anlamına gelir, çünkü onu Cat türü olarak değil, Animal türü olarak ilan ettik.

Bunu "doğal / örtük / otomatik" bir şekilde, derleme zamanında veya çalışma zamanında yapmamıza izin verilir, çünkü Cat işlevselliğinin bir kısmını Hayvan'dan miras alır; örneğin, () taşı. (En azından kedi bir hayvandır, değil mi?)

2. Aşağı indirme.

Ancak, Cat tipindeki hayvan etiketimizden Cat'in işlevselliğini almamız gerektiğinde ne olur ?.

Bir Cat nesnesini işaret eden animalCat etiketini oluşturduğumuz için, animalCat etiketimizden Cat nesnesinin yöntemlerini akıllıca güzel bir şekilde çağırmanın bir yoluna ihtiyacımız var.

Böyle bir prosedür Downcasting olarak adlandırdığımız şeydir ve bunu sadece çalışma zamanında yapabiliriz.

Bazı kodların zamanı:

public class Animal {
    public String move() {
        return "Going to somewhere";
    }
}

public class Cat extends Animal{
    public String makeNoise() {
        return "Meow!";
    }   
}

public class Test {

    public static void main(String[] args) {
        
    //1.- Upcasting 
    //  __Type_____tag________object
        Animal animalCat = new Cat();
    //Some animal movement
        System.out.println(animalCat.move());
        //prints "Going to somewhere"
        
    //2.- Downcasting   
    //Now you wanna make some Animal noise.
        //First of all: type Animal hasn't any makeNoise() functionality.
        //But Cat can do it!. I wanna be an Animal Cat now!!
        
        //___________________Downcast__tag_____ Cat's method
        String animalNoise = ( (Cat) animalCat ).makeNoise();
        
        System.out.println(animalNoise);
        //Prints "Meow!", as cats usually done.
        
    //3.- An Animal may be a Cat, but a Dog or a Rhinoceros too.
        //All of them have their own noises and own functionalities.
        //Uncomment below and read the error in the console:
        
    //  __Type_____tag________object
        //Cat catAnimal = new Animal();
        
    }

}

2

Ebeveyn: Araba
Çocuk: Figo
Araba c1 = yeni Figo ();

=====
Upcasting: -
Yöntem: c1 nesnesi, "Figo" sınıfı "new" ile belirtildiği için c1 Sınıfı Yöntemlerine (Figo - Metot geçersiz kılınmalıdır) atıfta bulunacaktır.
Örnek Değişkeni: Nesne c1, Declaration Class ("Car") örnek değişkenine atıfta bulunur.

Declaration sınıfı üst öğe olduğunda ve alt öğe oluşturulduğunda "Upcasting" örtük döküm gerçekleşir.

======
Downcasting: -
Figo f1 = (Figo) c1; //
Yöntem: c1 nesnesi, "Figo" sınıfıyla ilk c1 nesnesi oluşturulduğundan, f1 nesnesi Sınıf Yöntemi'ne (figo) atıfta bulunacaktır. ancak bir kez aşağı döküm yapıldıktan sonra, sadece "Figo" sınıfında mevcut olan metotlar, f1 değişkeni ile de ifade edilebilir.
Örnek Değişkeni: f1 nesnesi, c1 nesnesinin Declaration sınıfının örnek değişkenine değinmez (c1 için declaration sınıfı CAR'dır), ancak aşağı dökümde Figo sınıfının örnek değişkenlerine atıfta bulunur.

======
Kullanım: Object Child Class olduğunda ve bildirim sınıfı Parent olduğunda ve Child sınıfı, üst sınıftan değil, kendi sınıfının Instance değişkenine erişmek istediğinde "Downcasting" ile yapılabilir.


1

üst bölme, nesneyi bir süper tipe dökmek anlamına gelirken, alt bölme bir alt tipe dökmek anlamına gelir.

Java'da otomatik olarak yapıldığı için yayıncılık gerekli değildir. Ve genellikle örtük döküm olarak adlandırılır. Başkalarına açıklığa kavuşturmak için belirtebilirsiniz.

Böylece yazma

Animal a = (Animal)d;

veya

Animal a = d;

tam olarak aynı noktaya ve her iki durumda da potansiyel müşteriler yürütülecektir callme()dan Dog.

Hayvan yerine anesne tanımladığınız için downcasting gereklidir . Şu anda bunun bir olduğunu biliyorsunuz Dog, ama java'nın garantisi yok. Aslında çalışma zamanında farklı olabilir ve java bir atar ClassCastException, bu olur. Tabii ki bu çok örnek bir örnek değil. Eğer dökme olmaz ise ahiç Animalçünkü, java bile uygulamayı derlemek olamazdı Animalyöntemi yoktur callme2().

Senin örnekte, kodu ulaşamaz callme()ait Animaldan UseAnimlas(çünkü Dogyöntem aşağıdaki gibidir olacağını sürece bunun üzerine yazma):

class Dog extends Animal 
{ 
    public void callme()
    {
        super.callme();
        System.out.println("In callme of Dog");
    }
    ... 
} 

0

Downcasting'e nesne oluşturabiliriz. Bu tipte de. : temel sınıf yöntemlerini çağırma

Animal a=new Dog();
a.callme();
((Dog)a).callme2();
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.