2012-09-06 151 views
0
class Person { void f() {} } 
class Student extends Person { void f() {} } 

后期绑定/铸造所以,当我执行下面的代码:困惑在Java中

Person p = new Student(); 
((Person) p).f(); 

为什么f()功能在学生上课的时候变量被投作为一个人叫什么名字?我明白为什么f()函数被调用时,它只是p.f(),但我想我只是困惑什么演员做。

+0

试试这对线(来自ClassCastException的描述):Object x = new Integer(0); System.out.println((String)x);' –

+0

好的。我认为铸造一个物体会改变物体的类型而不是参考。不过,我明白向下转换和向上转换。谢谢您的帮助。 – sbl03

+1

投射对象对对象本身或对对象的引用都没有影响。它所做的是通知Java验证者关于为对象假设的新类型。但是这个假设只有在通过检查适当的超类 - 子类关系来验证投射本身之后才有效。这可以在验证时完成(实际上是在加载类时),或者可以在单个对象上动态完成。 –

回答

1

这是Object Oriented:Polymorphism的基石之一。你有各种各样的Person实体,每个实体都以自己的方式做f()。它是该对象的实际实例,而不是f()的那个实例。

1

你总是可以将子类型转换为类型这种转换总是允许在java中,但是因为实例是子类型的子类型方法将被执行。

您可以了解更多信息 检查Here在Java中,有两种类型的引用变量铸造:

  • 溯造型:如果您有指子类型对象的引用变量,你可以指定它到 子类型的参考变量。您必须进行明确演员才能完成此操作,结果为 ,您可以使用此新参考 变量访问子类型的成员。
  • 上传:您可以显式或隐式地将引用变量指定给超类型引用变量。这是一种固有的安全操作,因为该分配限制了新变量的访问能力。

是的,您需要直接或间接地实现接口,以便将类对象引用分配给接口类型。

1

当调用方法时,由于ploymorphsim,它将始终在对象类型上执行,而不是引用类型。

0

这里的上传无关紧要。重写的方法将始终被调用(如果存在)。

1

同样的方法 - 学生中的 - 将被调用,无论您是否将学生转换为人员。

上传一个引用(从子类到超类)不提供真正的功能(实际上通常在内部是无操作的)。另一方面,向下转换会告诉JVM,您相信超类是指定的子类,如果不是转换错误将会引发。 (我会给出gefei的信用来指出上面的遗漏:演员ALSO告诉编译器类型,并且编译器使用这些信息来知道对象(假设)有什么方法和字段。这并不是严格的编译一个Java程序到字节码,但它确实允许编译器执行通常的编译时间有效性检查。)

+0

@gefei(阅读ClassCastException [这里](http://docs.oracle.com/javase/1.5.0/docs/api/)的描述。) –

+0

但是,你的downvote的主题是你声称JVM确实看不到演员。它的确如此。 –

+0

好吧,你是对的,当向下转换为一个不是对象或其祖先的真实类型的类时,那么jvm会抛出一个异常。我只是在约束的背景下思考。 – gefei

0

在您的示例中的演员完全没用。编译器知道p的类型是Person。更有趣的将是一个狭窄投:

Person p = getPerson(); 
if (p instanceof Student) { 
    Student s = (Student) p; 
    // do something Student-specific with s 
} 

在Java中铸造引用类型不改变物体的性质;它只告诉编译器可以对该对象做出什么假设。在运行时,对象的实际类型用于确定调用的方法。 (请注意,原始类型不适用;将int转换为byte将更改数据。)