class Person { void f() {} }
class Student extends Person { void f() {} }
后期绑定/铸造所以,当我执行下面的代码:困惑在Java中
Person p = new Student();
((Person) p).f();
为什么f()
功能在学生上课的时候变量被投作为一个人叫什么名字?我明白为什么f()
函数被调用时,它只是p.f()
,但我想我只是困惑什么演员做。
class Person { void f() {} }
class Student extends Person { void f() {} }
后期绑定/铸造所以,当我执行下面的代码:困惑在Java中
Person p = new Student();
((Person) p).f();
为什么f()
功能在学生上课的时候变量被投作为一个人叫什么名字?我明白为什么f()
函数被调用时,它只是p.f()
,但我想我只是困惑什么演员做。
这是Object Oriented:Polymorphism的基石之一。你有各种各样的Person实体,每个实体都以自己的方式做f()。它是该对象的实际实例,而不是f()的那个实例。
你总是可以将子类型转换为类型这种转换总是允许在java中,但是因为实例是子类型的子类型方法将被执行。
您可以了解更多信息 检查Here在Java中,有两种类型的引用变量铸造:
是的,您需要直接或间接地实现接口,以便将类对象引用分配给接口类型。
当调用方法时,由于ploymorphsim,它将始终在对象类型上执行,而不是引用类型。
这里的上传无关紧要。重写的方法将始终被调用(如果存在)。
同样的方法 - 学生中的 - 将被调用,无论您是否将学生转换为人员。
上传一个引用(从子类到超类)不提供真正的功能(实际上通常在内部是无操作的)。另一方面,向下转换会告诉JVM,您相信超类是指定的子类,如果不是转换错误将会引发。 (我会给出gefei的信用来指出上面的遗漏:演员ALSO告诉编译器类型,并且编译器使用这些信息来知道对象(假设)有什么方法和字段。这并不是严格的编译一个Java程序到字节码,但它确实允许编译器执行通常的编译时间有效性检查。)
@gefei(阅读ClassCastException [这里](http://docs.oracle.com/javase/1.5.0/docs/api/)的描述。) –
但是,你的downvote的主题是你声称JVM确实看不到演员。它的确如此。 –
好吧,你是对的,当向下转换为一个不是对象或其祖先的真实类型的类时,那么jvm会抛出一个异常。我只是在约束的背景下思考。 – gefei
在您的示例中的演员完全没用。编译器知道p
的类型是Person
。更有趣的将是一个狭窄投:
Person p = getPerson();
if (p instanceof Student) {
Student s = (Student) p;
// do something Student-specific with s
}
在Java中铸造引用类型不不改变物体的性质;它只告诉编译器可以对该对象做出什么假设。在运行时,对象的实际类型用于确定调用的方法。 (请注意,原始类型不适用;将int
转换为byte
将更改数据。)
试试这对线(来自ClassCastException的描述):Object x = new Integer(0); System.out.println((String)x);' –
好的。我认为铸造一个物体会改变物体的类型而不是参考。不过,我明白向下转换和向上转换。谢谢您的帮助。 – sbl03
投射对象对对象本身或对对象的引用都没有影响。它所做的是通知Java验证者关于为对象假设的新类型。但是这个假设只有在通过检查适当的超类 - 子类关系来验证投射本身之后才有效。这可以在验证时完成(实际上是在加载类时),或者可以在单个对象上动态完成。 –