![]() |
1
2
在运行时,每个对象都知道自己的类是什么,也就是说,它实际上是作为类创建的。它可以分配给该类或任何超类的变量。当您执行一个函数时,您会得到创建对象的类的函数的“版本”,而不是包含对象引用的变量声明为的类的版本。 也就是说,以你的车/雷克萨斯为例。如果你写“lexus mycar=new lexus();mycar.speedup();”,执行的是lexus.speedup,而不是car.speedup。也许这很明显。但是即使你写“car mycar=new lexus();mycar.speedup();”执行的仍然是lexus.speedup,因为这是实际对象的类。你可以随意将一个对象重新分配给不同类的不同变量,对象仍然知道它的“真实”类。 基本上,只要把它看作每个对象都有一个隐藏的变量来保存自己的类类型,这就是它用来查找要执行的函数的原因。 在编译时,编译器不知道任何给定对象的类。就像你写的:
编译器不知道这里的车是雷克萨斯还是本田什么的。它只知道它是一辆车,因为它不知道在哪里或如何调用这个函数。实际类型的汽车直到运行时才会知道。 这意味着如果你试图写:
编译器会在这个问题上给出一个错误。它无法知道物体是一辆汽车,所以它不知道加速是一个有效的功能。 即使你写了:
你会得到一个错误。作为一个正在阅读代码的人,你可以很容易地看到mycar必须是一个lexus,因此是一辆车,但是编译器只看到mycar被声明为一个对象,而object没有加速功能。(我想,一个足够聪明的编译器可以在这个小例子中发现我的车一定是一辆雷克萨斯,但是编译器不能处理它有时或大多数时候可能知道的事情,它必须处理绝对的问题。) 编辑:在评论中回答问题。 问题3:我知道你在哪里困惑了。您需要区分编译时间和运行时。 当您在一个对象上执行一个函数时,您会得到该对象的“real”类所特有的函数的“version”。就像你写的:
但这是运行时的事情。在编译时,编译器只知道保存引用的变量的类型。这可以与对象的“真实”类相同,也可以是对象的任何超类。在上述两种情况下,都是汽车。由于car定义了加速功能,因此调用car1.speedup是合法的。但是这里有一个例子:在编译时,Java知道汽车有加速功能,所以调用一个汽车对象的加速是合法的。但它不知道也不关心你会得到哪种加速功能。也就是说,当你说CAR2.SupUpUp时,Java知道CAR2是一辆车,因为这是声明的类型。它不知道——记住我们说的是编译时,而不是运行时——它不知道它是雷克萨斯还是克莱斯勒,只是它是一辆车。直到运行时间,它才知道它是哪种类型的汽车。 |
![]() |
2
2
对象始终是特定类的实例,可以使用任何超级类引用实例,但实例不会更改。我认为第二个截图最能说明这一点,你不能写
在第3个代码片段中,第5行无效,因为设施是礼堂的超类,所以可以将礼堂实例分配给设施变量,但不能反过来分配。 |
![]() |
3
1
对象始终保持不变。如果将其分配给其他类型的其他变量,则在不将特殊成员强制转换回其原始类型的情况下,将无法访问它。 只能访问正在使用的变量类型的成员和方法。但是这个变量引用的对象可以有一个更专门化的类型。对象存储自己的类型,因此运行时能够识别其实际类型。 |
![]() |
4
1
这对我有帮助——也许对你没有帮助,但我会把它扔出去。 想象一下把一个物体投射成在那个物体上穿上新衣服。它有不同的外观,但在你穿的衣服下面,它仍然是同一个物体。 例如,如果你拿一根绳子把它扔到物体上,它就不会变成一个物体——但它穿着一个物体的衣服。不能对对象调用.length,因为该方法不存在于“object's”衣服中,但如果调用.equals或.hashcode,则会得到与在字符串中调用它们时相同的准确答案,因为它们通过衣服调用底层对象。 这些衣服只是隐藏了课堂上没有的方法。object o=new string();隐藏字符串中的所有方法,但不隐藏新衣服下的对象,使其看起来像一个对象。 你可以稍后再把你的物件穿成细绳。 你穿的衣服与物体的操作无关,只与外界如何与物体互动/观察物体无关。 这个比喻可能有点夸张,但也要注意,如果你的“衣服”的方法在你的对象中不存在,那么尝试穿这些衣服是没有意义的,所以你不能这样做:
因为一个物体不能填满绳子的衣服,绳子的衣服上有“长度”和“附加”的洞,还有许多其他物体不能填满的方法——就像没有手的人试图戴手套一样。 |
![]() |
5
0
记住一件事。子类引用不能包含超类对象。
|
![]() |
Gabe Tucker · 无法在golang中分配接口对象指针 2 年前 |
![]() |
randomDud · C#从另一个接口重写接口方法 2 年前 |
![]() |
evilsushi · C#接口不允许成员类满足要求 6 年前 |