为什么在类型转换后Java对象类仍然保持不变?

11

我试图向上转换一个对象。但在运行时,对象的类仍然是一个派生类。

Derived drv = new Derived();

Base base = (Base) drv;

System.out.println("Class : " + base.getClass()); 

//prints -> Class : class packagename.Derived

那为什么类属性没有改变呢?


4
我已经为你制作了一个在ideone上的示例(http://ideone.com/dyvs8S)以便你能够尝试这个概念,但现在来不及了。T.J.的答案是正确的。 - 2rs2ts
@2rs2ts:谢谢,我已经将它添加到我的答案中了,非常感谢。 - T.J. Crowder
3个回答

15

那么为什么类属性没有改变呢?

因为对象本身并没有改变,只是你对它的引用类型发生了变化。强制类型转换对对象本身没有任何影响。

在Java中,与其他一些语言(谢天谢地)不同的是,引用类型很大程度上不会影响你获取方法的哪个版本。例如,考虑这两个类(由2rs2ts提供 - 谢谢!):

class Base {
    public Base() {}
    public void foo() {
        System.out.println("I'm the base!");
    }
}

class Child extends Base {
    public Child() {}
    public void foo() {
        System.out.println("I'm the child!");
    }
}

这段代码:

Child x = new Child();
Base y = (Base) x;
y.foo();

……输出

我是孩子!

因为即使 y 的类型是 Base,我们调用 foo 方法的 对象Child,所以会调用 Child#foo。这里(再次感谢2rs2ts)提供了一个可以测试的示例

尽管你调用的方法(getClass)只能是 Object#getClass,因为它是一个final方法(子类不能覆盖),但这个概念对于多态来说非常重要,我认为这可能是你问题的核心。

引用类型的主要作用是确定您可以访问对象的哪些方面。例如,假设我们将 bar 添加到 Child 中:

class Child extends Base {
    public Child() {}
    public void foo() {
        System.out.println("I'm the child!");
    }
    public void bar() {
        System.out.println("I'm Child#bar");
    }
}

这段代码无法编译:

Child x = new Child();
Base y = (Base) x;
y.bar(); // <=== Compilation error

因为Base没有bar方法,所以我们无法通过类型为Base的引用访问对象的bar方法。


Base base = (Base) drv;并不会将drv指向的Derived类型对象转换为Base类型对象。它只是说明Derived类型对象可以被视为Base类型对象,并且可以执行所有Base类型对象能够执行的操作。 - NoName
@NoName:答案中没有出现“转换”一词。 - T.J. Crowder
@T.J. Crowder:糟糕,你可能误解了我的评论,认为它是对你回答的纠正。我只是在试图澄清强制类型转换的思维方式。 - NoName
1
@NoName:好的。我认为我在实际答案中已经很好地涵盖了这个问题。 - T.J. Crowder

0

在Java中,您无法更改实例的类型。您使用强制转换所做的只是从不同类型的变量引用它。


你的意思是“...一个对象的类型...”吗?一个实例是指向该对象的引用变量。 - NoName
好的...不是。 https://stackoverflow.com/questions/5531254/object-vs-instance https://dev59.com/iHE85IYBdhLWcg3wNwx3 - Andres

0

向上转型不会改变对象的类型。事实上,没有任何东西可以改变Java对象的类型。

这就是面向对象编程的核心:一个对象具有定义好的行为,不能被外部影响。


一个对象具有定义好的行为,其行为无法受到外界的影响。但这句话不太准确 :) - Marko Topolnik
面向对象编程的意图是一回事,Java的语义则是另一回事。特别是,引用转换与对象的定义行为并没有太大关系,它涉及到“引用”和“对象”的区别。 - Marko Topolnik
@T.J. Crowder:不,我们在这里谈论的是向上转型:http://forum.codecall.net/topic/50451-upcasting-downcasting/ - Ray
@Marko Topolnik,最初的问题是,为什么强制转换不会影响getClass()的结果。这与对象的行为有关,不是吗? - Ray
问题可能涉及行为,但答案不是。如果一个类有一个与其超类中的字段同名的公共字段,则向上转型改变结果。用你这样的笼统陈述来解释并没有提供教学价值。 - Marko Topolnik
显示剩余2条评论

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