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
Downcasting in Java
提问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 ClassCastException
will 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 A
and B
have a subtype relation, so with the "expression" view of the code, the cast might work.
正如其他人所证明的那样,这种类型的演员是完全合法的。右边的表达式可以很好地评估为类型的对象B
。编译器看到A
并B
具有子类型关系,因此使用代码的“表达式”视图,转换可能会起作用。
The compiler does not consider the special case when it knows exactlywhat object type expression_of_type_A
will really have. It just sees the static type as A
and considers the dynamic type could be A
or 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 objValue
variable can always be downcasted to int
because the object which was cast is an Integer
,
所以现在这个objValue
变量总是可以向下转换,int
因为被转换的对象是一个Integer
,
int oldIntValue = (Integer) objValue;
// can be done
but because objValue
is an Object it cannot be cast to String
because int
cannot 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();
}
}
}