Java 如果从hashmap返回值,为什么向下转换不会引发异常

Java 如果从hashmap返回值,为什么向下转换不会引发异常,java,Java,我有一些课要上 public class Container { static Map<String , Fruits> mp = new HashMap<String, Fruits>(); public static Map<String, Fruits> getMp() { return mp; } } 延伸水果的苹果类 public class Apple extends Fruits { privat

我有一些课要上

public class Container {
    static Map<String , Fruits> mp = new HashMap<String, Fruits>();
    public static Map<String, Fruits> getMp() {
        return mp;
    }
}
延伸水果的苹果类

public class Apple extends Fruits {
    private String color;
    private String shape;
    public String getColor() {
        return color;
    }
    public void setColor(String color) {
        this.color = color;
    }
    public String getShape() {
        return shape;
    }
    public void setShape(String shape) {
        this.shape = shape;
    }   
}
主类

public static void main(String[] args) {
    Apple a = new Apple();
    a.setColor("red");
    a.setShape("round");

    Container.getMp().put("fruits1",a);
    System.out.println(Container.getMp().get("fruits1").getShape());
    Apple b =(Apple) Container.getMp().get("fruits1");//does not throw runtime exception

    Fruits f = new Fruits();
    Apple as = (Apple) f;//throw runtime exception

}
我的问题是,在这两种情况下,我都在贬低苹果的水果,但当值来自hashmap时,它不会抛出异常。我对此很困惑。请有人能解释一下背后的原因

Apple b = (Apple) Container.getMp().get("fruits1");
这不会抛出
ClassCastException
,因为运行时对象的类型是
Apple
,这是您以前创建并放在映射中的

Fruits f = new Fruits();
Apple as = (Apple) f;

抛出
ClassCastException
,因为在运行时,
f
也是一个
Fruits
对象,但不是
Apple
当您
从映射中获取
Apple
时,最初放置在映射中的对象是一个
Apple
。因此,将映射返回的
结果向下投射到
苹果
是可行的——在运行时,对象实际上是一个
苹果

但是,
f
是一个
Fruits
,而不是一个
Apple
,因此在这里向下转换到
Apple
会抛出一个
ClassCastException
。对象
f
不是
Apple
,因此强制转换失败


它与物体是否来自地图无关;这完全取决于对象的运行时类型。

如果我这样做会怎么样。Container.getMp()。对象
a
已经是一个
Apple
,因此在将其放入地图之前将其强制转换为
Fruits
,不会影响您是否可以将
get
的返回强制转换为
Apple
——无论您如何强制转换,它在运行时都是一个
Apple
对象,因此,您在此处对
Apple
的转换仍然会成功。@Roshan您创建的每个对象始终引用其原始地址,因此即使您向下转换对象,它也始终指向原始对象,但会失去其子类的功能。在第一种情况下,您是从容器中检索Apple对象(在构造函数中,您调用了new Apple())。在第二种情况下,您初始化了一个新的水果(水果f=新水果())。苹果是水果(因为它是一个子类),但水果不是苹果,所以这就是为什么你在这两种说法中做的事情都不一样。首先,你将
苹果
投给
苹果
,这很好,因为它已经是
苹果
。第二,你将
水果
投给
苹果
,这很好你不能这样做,因为
水果不一定是
苹果
,但
苹果
总是
水果
,所以你可以将
苹果
抛给
水果
。谢谢@ControlAltDel。
Fruits f = new Fruits();
Apple as = (Apple) f;