Java 中的向下转型

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/380813/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 14:03:29  来源:igfitidea点击:

Downcasting in Java

javacasting

提问by Warrior

Upcasting is allowed in Java, however downcasting gives a compile error.

Java 中允许向上转换,但是向下转换会产生编译错误。

The compile error can be removed by adding a cast but would anyway break at the runtime.

可以通过添加强制转换来消除编译错误,但无论如何都会在运行时中断。

In this case why Java allows downcasting if it cannot be executed at the runtime?
Is there any practical use for this concept?

在这种情况下,如果 Java 不能在运行时执行,为什么它允许向下转换?
这个概念有什么实际用途吗?

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");
  }
}

采纳答案by Joachim Sauer

Downcasting is allowed when there is a possibility that it succeeds at run time:

当有可能在运行时成功时,向下转换是允许的:

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

In some cases this will not succeed:

在某些情况下,这不会成功:

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

When a cast (such as this last one) fails at runtime a ClassCastExceptionwill be thrown.

当强制转换(例如最后一个)在运行时失败时,ClassCastException将抛出一个。

In other cases it will work:

在其他情况下,它会起作用:

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

Note that some casts will be disallowed at compile time, because they will never succeed at all:

请注意,某些强制转换在编译时将被禁止,因为它们根本不会成功:

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

回答by Rolf Rander

I believe this applies to all statically typed languages:

我相信这适用于所有静态类型语言:

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

The typecast effectively says: assume this is a reference to the cast class and use it as such. Now, lets say o is reallyan Integer, assuming this is a String makes no sense and will give unexpected results, thus there needs to be a runtime check and an exception to notify the runtime environment that something is wrong.

类型转换有效地表示:假设这是对转换类的引用并以此方式使用它。现在,假设 o确实是一个整数,假设这是一个字符串是没有意义的,并且会给出意想不到的结果,因此需要有一个运行时检查和一个异常来通知运行时环境有问题。

In practical use, you can write code working on a more general class, but cast it to a subclass if you know what subclass it is and need to treat it as such. A typical example is overriding Object.equals(). Assume we have a class for Car:

在实际使用中,您可以编写处理更通用类的代码,但如果您知道它是什么子类并且需要将其视为子类,则可以将其转换为子类。一个典型的例子是覆盖 Object.equals()。假设我们有一个 Car 类:

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

回答by Rolf Rander

Using your example, you could do:

使用您的示例,您可以执行以下操作:

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();
}

回答by matt b

In this case why Java allows downcasting if it cannot be executed at the runtime?

在这种情况下,如果 Java 不能在运行时执行,为什么它允许向下转换?

I believe this is because there is no way for the compiler to know at compile-time if the cast will succeed or not. For your example, it's simple to see that the cast will fail, but there are other times where it is not so clear.

我相信这是因为编译器无法在编译时知道强制转换是否成功。对于您的示例,很容易看出强制转换将失败,但在其他情况下则不太清楚。

For instance, imagine that types B, C, and D all extend type A, and then a method public A getSomeA()returns an instance of either B, C or D depending on a randomly generated number. The compiler cannot know which exact run-time type will be returned by this method, so if you later cast the results to B, there is no way to know if the cast will succeed (or fail). Therefore the compiler has to assume casts will succeed.

例如,假设类型 B、C 和 D 都扩展了类型 A,然后一个方法public A getSomeA()根据随机生成的数字返回 B、C 或 D 的实例。编译器无法知道此方法将返回哪种确切的运行时类型,因此如果稍后将结果转换为B,则无法知道转换是否成功(或失败)。因此编译器必须假设强制转换会成功。

回答by Rob Kennedy

We can all see that the code you provided won't work at run time. That's because we know that the expression new A()can neverbe an object of type B.

我们都可以看到您提供的代码在运行时不起作用。这是因为我们知道,表达new A()可以永远是类型的对象B

But that's not how the compiler sees it. By the time the compiler is checking whether the cast is allowed, it just sees this:

但这不是编译器的看法。当编译器检查是否允许强制转换时,它只会看到:

variable_of_type_B = (B)expression_of_type_A;

And as others have demonstrated, that sort of cast is perfectly legal. The expression on the right could very well evaluate to an object of type B. The compiler sees that Aand Bhave a subtype relation, so with the "expression" view of the code, the cast might work.

正如其他人所证明的那样,这种类型的演员是完全合法的。右边的表达式可以很好地评估为类型的对象B。编译器看到AB具有子类型关系,因此使用代码的“表达式”视图,转换可能会起作用。

The compiler does not consider the special case when it knows exactlywhat object type expression_of_type_Awill really have. It just sees the static type as Aand considers the dynamic type could be Aor any descendant of A, including B.

编译器不考虑特殊情况,当它确切知道expression_of_type_A将真正具有什么对象类型时。它只是将静态类型视为A并认为动态类型可以是A或 的任何后代A,包括B.

回答by Alok Sharma

@ Original Poster - see inline comments.

@ 原始海报 - 见内嵌评论。

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");
    }
}

回答by Uday Reddy

Downcast works in the case when we are dealing with an upcasted object. Upcasting:

当我们处理向上转换的对象时,向下转换有效。上行:

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

So now this objValuevariable can always be downcasted to intbecause the object which was cast is an Integer,

所以现在这个objValue变量总是可以向下转换,int因为被转换的对象是一个Integer

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

but because objValueis an Object it cannot be cast to Stringbecause intcannot be cast to String.

但因为objValue是一个对象,所以不能被强制转换为,String因为int不能被强制转换为String

回答by Drishti

Downcasting is very useful in the following code snippet I use this all the time. Thus proving that downcasting is useful.

在我一直使用的以下代码片段中,向下转换非常有用。因此证明向下转换是有用的。

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

I store String in the Linked List. When I retrieve the elements of Linked List, Objects are returned. To access the elements as Strings(or any other Class Objects), downcasting helps me.

我将字符串存储在链接列表中。当我检索链接列表的元素时,返回对象。要将元素作为字符串(或任何其他类对象)访问,向下转换对我有帮助。

Java allows us to compile downcast code trusting us that we are doing the wrong thing. Still if humans make a mistake, it is caught at runtime.

Java 允许我们编译低级代码,相信我们做错了。尽管如此,如果人类犯了错误,它会在运行时被捕获。

回答by ZohebSiddiqui

Consider the below example

考虑下面的例子

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");
}
}

here we create the object of subclass Bone and assigned it to super class AOne reference and now superclass reference does not know about the method method2 in the subclass i.e Bone during compile time.therefore we need to downcast this reference of superclass to subclass reference so as the resultant reference can know about the presence of methods in the subclass i.e Bone

这里我们创建了子类 Bone 的对象并将其分配给超类 AOne 引用,现在超类引用在编译时不知道子类中的方法 method2,即 Bone。因此我们需要将此超类引用向下转换为子类引用,以便结果引用可以知道子类中方法的存在,即 Bone

回答by Aliaksandr Shpak

Downcasting transformation of objects is not possible. Only

对象的向下转换是不可能的。仅有的

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

is posible

是可能的

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();
        }
    }

}