铸造后目标对象采用什么类?
好的,noob问题。 我正在为SCJP学习并得到3个关于对象引用错误的问题,这似乎都表明了同样的误解。 只想确认正确的见解应该是什么。 对,这是问题:
- 1。
1.类CodeWalkFour { 2. public static void main(String [] args){ 3. Car c = new Lexus(); 4. System.out.print(c.speedUp(30)+“”); 5.雷克萨斯l =新雷克萨斯(); 6. System.out.print(l.speedUp(30,40,50)); 7.} 8.} 9.车级{ 10. private int i = 0; 11. int speedUp(int x){ 12.返回i; 13.} 14.} 15.雷克萨斯扩展汽车{ 16. private int j = 1; 17. private int k = 2; 18. int speedUp(int y){ 19.返回j; 20.} 21. int speedUp(int ... z){ 22.返回k; 23.} 24.}
我认为在第3行之后,c将是Car而不是Lexus,因此将调用Car.speedUp方法,而不是Lexus.speedUp方法。 事实certificate,后者被称为。
- 2。
1. class StudentProb { 2. private int studentId = 0; 3. void setStudentID(int sid){ 4. student_id = sid; 5. System.out.println(“学生ID已设置为”+ sid); 6.} 7. public static void main(String args []){ 8. int i = 420; 9.对象ob1; 10. StudentProb st1 = new StudentProb(); 11. ob1 = st1; 12. st1.setStudentID(i); 13.} 14.}
同样的问题。 我认为第11行会使st1成为一个Object,而不再是StudentProb。 编译器如何知道在哪里找到setStudentID?
- 3。
1. LectureHall lh = new LectureHall(); 2.礼堂a1; 3.设施f1; 4。 5. f1 = lh; 6. a1 = f1;
设施是一个界面。 ClassRoom类实现了Facilities,Auditorium和LectureHall是ClassRoom的子类。 同样的问题:我想在第5行之后,f1和lh都是LectureHall。 但f1仍然是设施。 那么铸造究竟在做什么呢?
谢谢大家!
PS:代码格式化不适合我。 随意编辑。
在运行时,每个对象都知道它自己的类是什么,也就是它实际创建的类。 它可以分配给该类或任何超类的变量。 当您执行一个函数时,您将为该对象创建的类获取该函数的“版本”,而不是对于持有该对象引用的变量被声明为的类。
也就是说,以你的Car / Lexus为例。 如果你写“Lexus mycar = new Lexus(); mycar.speedUp();”,执行的是Lexus.speedUp,而不是Car.speedUp。 也许这很明显。 但即使你写“Car mycar = new Lexus(); mycar.speedUp();” 执行的仍然是Lexus.speedUp,因为那是实际对象的类。 您可以将对象重新分配给不同类的不同变量,对象仍然知道它的“真实”类。
基本上,只需将其视为具有隐藏变量的每个对象,该隐藏变量拥有自己的类类型,这就是它用于查找要执行的函数的内容。
在COMPILE时,编译器不知道任何给定对象的类。 就像你写的:
void speed1(Car somecar) { somecar.speedUp(1); }
编译器不知道这里的Car是雷克萨斯还是本田或者是什么。 它只知道它是一辆汽车,因为它不知道这个函数的调用位置和方式。 直到运行时才会知道实际的汽车类型。
这意味着如果你试着写:
void speed1(Object somecar) { somecar.speedUp(1); }
编译器会给出错误。 它无法知道Object是Car,因此它不知道speedUp是一个有效的函数。
即使你写了:
Object mycar=new Lexus(); mycar.speedUp(1);
你会收到一个错误。 作为人类阅读代码,您可以很容易地看到mycar必须是雷克萨斯,因此是汽车,但编译器只是看到mycar被声明为Object,而Object没有speedUp函数。 (我认为,一个足够聪明的编译器可以在这个简单的例子中找出mycar必须是雷克萨斯,但是编译器无法处理它有时或大部分时间可能知道的事情,它必须处理绝对值。)
编辑:在评论中回答问题。
问题3:我看到你在这里感到困惑的地方。 您需要将COMPILE TIME与RUNTIME区分开来。
当您在对象上执行函数时,您将获得该特定于该对象的“真实”类的该函数的“版本”。 就像你写的:
Car car1=new Lexus(); Car car2=new Chrysler(); // assuming you defined this, of course car1.speedUp(1); // executes Lexus.speedUp car2.speedUp(2); // executes Chrysler.speedUp
但这是一个RUNTIME的事情。 在COMPILE时,所有编译器都知道是保存引用的变量的类型。 这可以与对象的“真实”类相同,也可以是对象的任何超类。 在上面两种情况下,都是Car。 由于Car定义了speedUp函数,因此调用car1.speedUp是合法的。 但这里是踢球者:在编译时,Java知道Car有一个speedUp函数,所以对Car对象调用speedUp是合法的。 但是它不知道或关心你将获得哪种speedUpfunction。 也就是说,当你说car2.speedUp时,Java知道car2是Car,因为那是声明的类型。 它不知道 – 记得我们在编译时说,而不是在运行时 – 它不知道它是雷克萨斯还是Chyrsler,只是它是一辆汽车。 直到运行时它才知道它是哪种类型的汽车。
对象始终是特定类的实例,您可以使用任何超类引用实例,但实例不会更改。 我认为第二个剪辑说明了这个最好,你不能写ob1.setStudentID(i);
因为ob1是一个Object
变量,即使实际的类是StudentProb
在您的第3个片段中,第5行无效,因为Facilities是Auditorium的超类,因此您可以将Auditorium实例分配给Facilities变量,但不能反过来。
对象始终保持不变。 如果将其分配给其他类型的其他变量,则无法在不将其转换回原始类型的情况下访问特殊成员。
您只能访问正在使用的变量类型的成员和方法。 但是,此变量引用的对象可以具有更专用的类型。 该对象存储其自己的类型,因此运行时能够识别其真实类型。
这有助于我 – 它可能对你没有帮助,但我会把它扔出去。
可视化将对象投射为在该对象上放置新衣服。 它有不同的外观,但在你放在它上面的任何衣服下面,它仍然是同一个物体。
例如,如果你取一个String并将它强制转换为Object,它就不会成为一个对象 – 但它会穿一件物体的衣服。 你不能在一个对象上调用.length,因为那个方法在“对象”的衣服中不存在,但是如果你调用.equals或.hashCode,你会得到与在字符串上调用它们时相同的答案。他们通过衣服呼唤底层物体。
衣服只是隐藏了课堂上没有的方法。 Object o = new String(); 在新衣服下隐藏String中但不是Object的所有方法,使其看起来像一个Object。
您可以稍后再将对象装扮成String。
你穿的衣服与物品的操作无关,只与外界如何与物体相互作用/观察物体有关。
这可能是一个有点远的类比,但也要注意,如果你的“衣服”有你的对象中不存在的方法,尝试穿这些衣服没有任何意义,所以你不能这样做:
String s=new Object();
因为一个对象无法填写String的套装,所以String的套装有“长度”和“附加”的洞以及许多其他方法,对象根本无法填充 – 就像没有人试图戴手套的人一样。
记住一件事。 子类引用不能包含超类对象。 class A{} class B extends A{}
在这里你可以创建A a=new A(); A a=new B();B b=new B()
A a=new A(); A a=new B();B b=new B()
但是你不能创建B b=new A()