Java'da indirgeme


179

Java'da yukarı yayınlamaya izin verilir, ancak aşağı yayınlama derleme hatası verir.

Derleme hatası, bir döküm ekleyerek kaldırılabilir, ancak çalışma zamanında yine de kesilir.

Bu durumda Java, çalışma zamanında çalıştırılamıyorsa neden devre dışı bırakmaya izin verir?
Bu kavram için pratik bir kullanım var mı?

public class demo {
  public static void main(String a[]) {
      B b = (B) new A(); // compiles with the cast, 
                         // but runtime exception - java.lang.ClassCastException
  }
}

class A {
  public void draw() {
    System.out.println("1");
  }

  public void draw1() {
    System.out.println("2");
  }
}

class B extends A {
  public void draw() {
    System.out.println("3");
  }
  public void draw2() {
    System.out.println("4");
  }
}

9
Örnek bir kod snippet'i ve hata, bunu kavramları öğrenmeye çalışan insanlar için daha iyi bir soru haline getirecektir.
Bob Cross

3
Bob'un yorumu için +1. Soru hiç net değil.
Jon Skeet

Yukarıdaki örneği zaten iyi yanıtları olan velocityreviews.com/forums/t151266-downcasting-problem.html adresinden alınmıştır .
PhiLho

2
@PhiLho - Joel'in ana amacı tüm büyük soru ve cevapları tek bir ortak çatı altında toplamaktı. Soru / kod / cevapların başka bazı sitelerde önceden yayınlanmış olması önemli değildir. Umarım anlarsın, aksi halde Joel'in podcast'lerini dinle.
Omnipotent

Lütfen kod parçacıklarının dört boşlukla girintili olması için bunu düzenleyin. Bu biçimlendirmeyi düzeltir.
ince

Yanıtlar:


298

Çalışma süresinde başarılı olma olasılığı olduğunda indirime izin verilir:

Object o = getSomeObject(),
String s = (String) o; // this is allowed because o could reference a String

Bazı durumlarda bu başarılı olmaz:

Object o = new Object();
String s = (String) o; // this will fail at runtime, because o doesn't reference a String

Bir döküm (bu sonuncusu gibi) çalışma zamanında başarısız olduğunda a ClassCastExceptionatılır.

Diğer durumlarda işe yarayacaktır:

Object o = "a String";
String s = (String) o; // this will work, since o references a String

Bazı yayınların derleme zamanında izin verilmeyeceğini unutmayın, çünkü hiçbir zaman başarılı olamayacaklardır:

Integer i = getSomeInteger();
String s = (String) i; // the compiler will not allow this, since i can never reference a String.

Object o = new Object(); String s = (String) o;Benim için iyi çalışıyor ..: O Nasıl?
Asif Mushtaq

@UnKnown: Olmamalı. Bu sürümü gerçekten derleyip çalıştırdığınızı bir kez daha kontrol edin ve yine de yeniden oluşturabiliyorsanız ayrı bir soru ( SSCCE ile ) gönderin .
Joachim Sauer

@JoachimSauer bu sürümle ne demek istiyorsun? Java 8 kullanıyorum.
Asif Mushtaq

1
@UnKnown: Gönderdiğiniz kodun çalışmaması gerektiği anlamına gelir (derlenir, ancak çalışma zamanında bir istisna atar). Bu yorumlar hata ayıklama alanı değildir. Lütfen ayrı bir soru gönderin.
Joachim Sauer

Döküm çalışma zamanında nasıl başarısız olur? Hedef nesne başvurusunu null olarak ayarlar? Bir istisna atar mı?
18:17 CygnusX1

17

Örneğinizi kullanarak şunları yapabilirsiniz:

public void doit(A a) {
    if(a instanceof B) {
        // needs to cast to B to access draw2 which isn't present in A
        // note that this is probably not a good OO-design, but that would
        // be out-of-scope for this discussion :)
        ((B)a).draw2();
    }
    a.draw();
}

Soyut sınıfımın birden çok sınıf tarafından genişletildiği zaman instanceof'in önemini öğrendim ve soyut sınıf türüne atıfta bulunarak bu sınıfların özel yöntemlerini kullanmak istedim. İnstanceof kullanmıyorum, sınıf kadrosu istisnası vardı
Tarun

16

Bunun statik olarak yazılan tüm diller için geçerli olduğuna inanıyorum:

String s = "some string";
Object o = s; // ok
String x = o; // gives compile-time error, o is not neccessarily a string
String x = (String)o; // ok compile-time, but might give a runtime exception if o is not infact a String

Daktilo etkili bir şekilde diyor ki: bunun cast sınıfına bir atıf olduğunu varsayalım ve böyle kullanın. Şimdi, o olduğunu söylemek sağlar gerçekten böylece çalışma zamanı çek ve şeylerin yanlış olduğunu çalıştırma ortamı bildirmek için bir istisna olması gerekir, bu bir dize hiçbir mantıklı ve beklenmeyen sonuçlar verecektir olduğunu varsayarak, bir tamsayı.

Pratik kullanımda, daha genel bir sınıf üzerinde çalışan kod yazabilirsiniz, ancak bunun hangi alt sınıf olduğunu biliyorsanız ve bu şekilde ele almanız gerekiyorsa bir alt sınıfa dökebilirsiniz. Tipik bir örnek, Object.equals () yöntemini geçersiz kılar. Araba için bir sınıfımız olduğunu varsayın:

@Override
boolean equals(Object o) {
    if(!(o instanceof Car)) return false;
    Car other = (Car)o;
    // compare this to other and return
}

Gerçekten kelimeyi beğendim ve daha belirgin hale getirmek için yayınınızı düzenleyeceğim
Charaf JRA

5

Sağladığınız kodun çalışma zamanında çalışmadığını hepimiz görebiliriz. Biz ifadesi olduğunu biliyoruz olmasıdır new A()olabilir asla türünde bir nesne B.

Ancak derleyici bunu böyle görmüyor. Derleyici, oyuncu kadrosuna izin verilip verilmediğini kontrol ettiğinde bunu görür:

variable_of_type_B = (B)expression_of_type_A;

Diğerlerinin de gösterdiği gibi, bu tür oyuncular tamamen yasaldır. Sağdaki ifade türdeki bir nesneyi çok iyi değerlendirebilir B. Derleyici bunu görür Ave Bbir alt tür ilişkisine sahiptir, bu nedenle kodun "ifade" görünümünde, döküm işe yarayabilir.

Derleyici, hangi nesne türünün gerçekten olacağını tam olarak bildiğinde özel durumu dikkate almaz expression_of_type_A. Sadece statik türü olarak görür ve Adinamik türün de dahil Aherhangi bir torunu olabileceğini düşünür .AB


3

Bu durumda Java, çalışma zamanında çalıştırılamıyorsa neden devre dışı bırakmaya izin verir?

Bunun derleyicinin derleme zamanında oyuncu kadrosunun başarılı olup olmayacağını bilmesinin bir yolu olmadığına inanıyorum. Örneğin, oyuncu kadrosunun başarısız olacağını görmek kolaydır, ancak o kadar net olmadığı başka zamanlar da vardır.

Örneğin, B, C ve D tiplerinin hepsinin A tipini genişlettiğini ve ardından bir yöntemin public A getSomeA()rastgele oluşturulmuş bir sayıya bağlı olarak B, C veya D örneğini döndürdüğünü düşünün . Derleyici, bu yöntemle hangi tam çalışma zamanı türünün döndürüleceğini bilemez, bu nedenle sonuçları daha sonra yayınlarsanız, yayınlamanın Bbaşarılı olup olmayacağını (veya başarısız olacağını) bilmenin bir yolu yoktur. Bu nedenle derleyici, yayınların başarılı olacağını varsaymalıdır.


2

@ Orijinal Poster - satır içi yorumlara bakın.

public class demo 
{
    public static void main(String a[]) 
    {
        B b = (B) new A(); // compiles with the cast, but runtime exception - java.lang.ClassCastException 
        //- A subclass variable cannot hold a reference to a superclass  variable. so, the above statement will not work.

        //For downcast, what you need is a superclass ref containing a subclass object.
        A superClassRef = new B();//just for the sake of illustration
        B subClassRef = (B)superClassRef; // Valid downcast. 
    }
}

class A 
{
    public void draw() 
    {
        System.out.println("1");
    }

    public void draw1() 
    {
        System.out.println("2");
    }
}

class B extends A 
{
    public void draw() 
    {
        System.out.println("3");
    }

    public void draw2() 
    {
        System.out.println("4");
    }
}

2

Downcast, kaldırılmış bir nesne ile uğraşırken çalışır. Upcasting:

int intValue = 10;
Object objValue = (Object) intvalue;

Yani şimdi bu objValuedeğişken her zaman için downcasted edilebilir intdökme oldu nesne bir nedeni Integer,

int oldIntValue = (Integer) objValue;
// can be done 

ancak objValuebir Nesne olduğu için kullanılamaz Stringçünkü intkullanılamaz String.


0

Downcasting aşağıdaki kod pasajında ​​çok yararlı ben bunu her zaman kullanıyorum. Bu nedenle inişlerin yararlı olduğunu kanıtlamak.

private static String printAll(LinkedList c)
{
    Object arr[]=c.toArray();
    String list_string="";
    for(int i=0;i<c.size();i++)
    {
        String mn=(String)arr[i];
        list_string+=(mn);
    }
    return list_string;
}

Dizeyi Bağlantılı Listede saklıyorum. Bağlantılı Liste öğelerini aldığımda, Nesneler döndürülür. Öğelere Dizeler (veya başka herhangi bir Sınıf Nesnesi) olarak erişmek için altyazı bana yardımcı olur.

Java, yanlış bir şey yaptığımıza güvenen downcast kodunu derlememizi sağlar. Yine de insanlar bir hata yaparsa, çalışma zamanında yakalanır.


Java'da genel olmayan koleksiyonlar kullanmak void*, C ++ 'daki işaretçilerin eşdeğeridir . Bana hiç iyi bir fikir gibi gelmiyor.
Jezor

0

Aşağıdaki örneği düşünün

public class ClastingDemo {

/**
 * @param args
 */
public static void main(String[] args) {
    AOne obj = new Bone();
    ((Bone) obj).method2();
}
}

class AOne {
public void method1() {
    System.out.println("this is superclass");
}
}


 class Bone extends AOne {

public void method2() {
    System.out.println("this is subclass");
}
}

burada alt sınıf Bone nesnesini yaratıyoruz ve bunu süper sınıf AOne referansına atadık ve şimdi üst sınıf referansı alt sınıftaki metot2'yi bilmiyor, yani derleme zamanı sırasında Kemik. ortaya çıkan referans, alt sınıftaki yöntemlerin, yani Kemiklerin varlığını bilebilir


AOne biraz kafa karıştırıcı görünüyor. Lütfen sınıf adlarınızı Köpek ve Hayvan gibi bir şeyle değiştirmeyi düşünün
Kartik Chugh

0

Java'da küçültme yapmak ve çalışma zamanı istisnalarını önlemek için aşağıdaki kodun bir referansını alın:

if (animal instanceof Dog) {
  Dog dogObject = (Dog) animal;
}

Burada Hayvan ana sınıf ve Köpek çocuk sınıftır.
instanceof , bir referans değişkeninin belirli bir nesne referansı türü içerip içermediğini kontrol etmek için kullanılan bir anahtar kelimedir.


0

Nesneleri küçümseme dönüşümü mümkün değildir. Sadece

DownCasting1 _downCasting1 = (DownCasting1)((DownCasting2)downCasting1);

mümkün

class DownCasting0 {
    public int qwe() {
        System.out.println("DownCasting0");
        return -0;
    }
}

class DownCasting1 extends DownCasting0 {
    public int qwe1() {
        System.out.println("DownCasting1");
        return -1;
    }
}

class DownCasting2 extends DownCasting1 {
    public int qwe2() {
        System.out.println("DownCasting2");
        return -2;
    }
}

public class DownCasting {

    public static void main(String[] args) {

        try {
            DownCasting0 downCasting0 = new DownCasting0();
            DownCasting1 downCasting1 = new DownCasting1();
            DownCasting2 downCasting2 = new DownCasting2();

            DownCasting0 a1 = (DownCasting0) downCasting2;
            a1.qwe(); //good

            System.out.println(downCasting0 instanceof  DownCasting2);  //false
            System.out.println(downCasting1 instanceof  DownCasting2);  //false
            System.out.println(downCasting0 instanceof  DownCasting1);  //false

            DownCasting2 _downCasting1= (DownCasting2)downCasting1;     //good
            DownCasting1 __downCasting1 = (DownCasting1)_downCasting1;  //good
            DownCasting2 a3 = (DownCasting2) downCasting0; // java.lang.ClassCastException

            if(downCasting0 instanceof  DownCasting2){ //false
                DownCasting2 a2 = (DownCasting2) downCasting0;
                a2.qwe(); //error
            }

            byte b1 = 127;
            short b2 =32_767;
            int b3 = 2_147_483_647;
//          long _b4 = 9_223_372_036_854_775_807; //int large number max 2_147_483_647
            long b4 = 9_223_372_036_854_775_807L;
//          float _b5 = 3.4e+038; //double default
            float b5 = 3.4e+038F; //Sufficient for storing 6 to 7 decimal digits
            double b6 = 1.7e+038;
            double b7 = 1.7e+038D; //Sufficient for storing 15 decimal digits

            long c1 = b3;
            int c2 = (int)b4;

            //int       4 bytes     Stores whole numbers from -2_147_483_648 to 2_147_483_647
            //float     4 bytes     Stores fractional numbers from 3.4e−038 to 3.4e+038. Sufficient for storing 6 to 7 decimal digits
            float c3 = b3; //logic error
            double c4 = b4; //logic error


        } catch (Throwable e) {
            e.printStackTrace();
        }
    }

}
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.