Java中将子类对象显式转换为超类的类型

5
考虑以下代码:

代码如下:

public class Test{
  public static void main(String str[]){
     B b = new B();
     A a1 = (A)b;//Explicit type conversion
     A a2 = b;
  }
}
class A{}
class B extends A{}

在上面的代码中有两行:
A a1 = (A)b;//Explicit type conversion
A a2 = b;

等价?如果不是,那么两者之间的区别是什么,如果,那么在Java中是否存在需要将子类对象显式转换为超类对象的任何情况


我有一个场景,需要获取超类java.util.Map(基本java),其中我实际上获取了它的子类spring.framework.LinkedCaseInsensitiveMap,请参见我的帖子:http://stackoverflow.com/q/30378061/2323234 - MRK187
6个回答

10

强制类型转换引用(而非对象)是多余的,一些IDE将建议您放弃它。

如果您这样做

A a1 = (A)b;

你仍然可以这样做

B b2 = (B) A;

将引用强制转换回B类型。

注意:对象不会以任何方式被更改,并且始终为B类型。

在Java中是否有需要使用它的情况?

唯一需要进行向上转型的时间是在方法选择时。

void method(Object o) { }

void method(String s) { }

method("hello");          // calls method(String)
method((Object) "hello"); // calls method(Object)

1
终于我找到了一个可能需要使用它的场景,非常感谢你... - Ankur

3

方法重载时还需要进行类型转换:

package casting;
public class ImplicitCasting {
    public static void main(String[] args) {
        A a = new A();
        B b = new B();
        A a1 = new B();
        methodA(a);      // methodA called
        methodA((A)b);   // methodA called
        methodA(b);      // methodB called
    }

    public static void methodA(A a) {
        System.out.println("methodA called");
    }

    public static void methodA(B b) {
        System.out.println("methodB called");
    }
}

class A{

}

class B extends A{

}       

1

在您的示例中,它们并不相等。

这在其他方式的赋值中变得重要,例如从AB,而您的对象仍然是类型B

例如,请考虑以下序列:

      A a = b;// will work
      a = (A)b;// will work
      B newB = (B)a; //will work
      B newB = a;  //will fail

1
在我看来,楼主明确提到了从子类到超类的转换。虽然这不是一个无效的观点。 - Bhesh Gurung

1

这两种方式没有区别。实际上,你不需要显式地将子类对象强制转换为超类引用。因此,第一种方式绝对是冗余的

JLS - Conversion中可以看到:

5.1.5. 引用扩宽转换

对于任何引用类型S和T,只要S是T的子类型(§4.10),就存在从S到T的引用扩宽转换。

引用扩宽转换在运行时不需要特殊操作,因此在运行时永远不会抛出异常。它们只是以一种可以在编译时证明正确的方式将引用视为具有其他类型。

只有在引用类型无法存储object时才需要显式类型转换。但是,当您创建一个子类对象并使超类引用指向该对象时,编译器永远不会有问题。因为这总是可以在运行时处理的。


那么第一条语句是多余的吗?在Java中没有任何需要它的情况,对吧? - Ankur
@Ankur。没错。一个超类引用可以指向其任何子类对象。这就是多态的全部意义所在。 - Rohit Jain

1
等价吗?如果不是,那么两者之间有什么区别?
唯一的区别在于一个是隐式的,而另一个是显式的(不是必需的),结果是等价的。注意:转换作用于对象的引用,而不是对象本身。
在Java中是否存在需要将子类对象显式转换为超类对象的情况?
Java支持Liskov替换原则,因此不应该出现这种情况。

0

它们是一样的。这是自动向下类型转换的情况。

A a1 = (A)b;//显式类型转换 A a2 = b;

在这两种情况下,a1和a2的类型都是A。因此,B的其他特性无论如何都会丢失。

如果您进行非自动向上类型转换,则会了解到差异。请考虑以下示例。

Vehicle v1 = new Car(); //正确。向上转型或隐式转型

Vehicle v2= new Vehicle();

Car c0 = v1; // 错误的编译时错误“类型不匹配” //需要显式或向下转换 Car c1 = (Car) v1 // 正确。向下转型或显式转型。v1由于第1行而具有Car的知识

Car c2= (Car) v2; //错误的运行时异常ClassCastException,因为v2没有关于Car的知识。

Bus b1 = new BMW(); //错误的编译时错误“类型不匹配”

Car c3 = new BMW(); //正确。向上转型或隐式转型

Car c4 = (BMW) v1; // 错误的运行时异常ClassCastexception

Object o = v1; //v1 只能向上强制转换为其父类 Car c5 = (Car) v1; //由于第一行,v1 可以向下强制转换为 Car


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接