我正在学习Smalltalk的基础知识。有一个super
关键字,用于从子类方法中的超类调用方法:
Object subclass: # A
test
^1
A subclass: # B
test
^2
callSuper
^super test
因此B new callSuper
评估为1
。
行。这很清楚。
现在,我正在为B
类定义一堆类方法:
createNew1
^super new
createNew2
^self new
create
^self
createSuper
^super
他们分别评估a B
,a B
,B
和错误(这表明super
不是转换为子类,而是一种消息调度程序)。
为什么我得到B
类的实例,尽管有super
个关键字? a B
和B
对象之间有什么区别?我开始认为B
对象是类static
的一个特殊的单一实例(就像B
属性在其他语言中实现一样),但仍然 - 我已经检查过了它的类是B
,子类是A
。
类方法中super
关键字的语义是什么?它与对象方法中的语义有何不同?通过在类方法中调用self
可以获得什么对象?
答案 0 :(得分:4)
self
和super
始终引用同一个对象,即当前接收者。唯一的区别是self
开始在接收器的类中查找以下方法send,并在定义方法的超类中查找super
。
有关详细信息,请参阅Pharo by Example的第5章。
答案 1 :(得分:4)
你对第一个例子的回答是错误的。 B new callSuper
返回1.Lukas为您提供了super语义的确切定义。它基本上是'self'的别名,它修改了发送给它的消息的方法查找。 self message
将开始在接收器的类中查找方法,super message
将开始在类的超类中搜索,该类定义包含super message
表达式的方法(因此接收器的类在这种情况下不相关)。
在您的第二个示例中,super new
和self new
最终调用相同的方法(在行为层次结构中的某处定义),因为这是两种情况下最接近new的方法定义。但是,如果将createNew方法重命名为new,则new ^self new
将是无限循环,而new ^super new
则调用Behavior方法。
答案 2 :(得分:3)
self和super都是一样的,因为类是一个对象......
#createNew1& #createNew2是等价的。正如Lukas所解释的那样,超级仅仅意味着“在我的超类而不是我的班级中开始查找方法”。由于你没有在A或B中定义#new,你将查找超类,最终找到行为>> #new是否从A或B开始。#new首先调用#basicNew,它创建了返回B的新实例(即“a B”)。
在#create& #createSuper,因为你没有查找任何东西,self和super再次等同并且意味着“返回当前对象”(你指的是后者有什么错误?)。现在这部分令人困惑。由于Smalltalk中的所有内容都是一个对象,因此这包括类本身。所以在这种情况下,“当前对象”是B,它是元类“B类”的唯一实例。如果你真的对理解感兴趣,我会一遍又一遍地阅读Pharo By Example的第13章,直到它有意义(我仍然没有达到这一点,哈哈)。
答案 3 :(得分:2)
尽管所有其他答案在技术上都是正确的,但我会自己回答这个问题。那是因为我知道了元类,似乎我脑子里有super
的正确语义,但我仍然得到了意想不到的结果。
事实证明我在Smalltalk中误解了继承的基础以及如何调用方法。
我在想这样的代码......
Object subclass: #A
test
^'A'
getTest
^self test
A subclass: # B
test
^'B'
runTest
^super getTest
...表达式B new runTest
被计算为'A'
- 这意味着,来自超类的方法在upcasted对象中进行评估。
但事实并非如此。
它被评估为'B'
,因为没有向上转换,当我们在超类方法中调用任何方法时 - 搜索从对象的真实类开始,而不是从哪个评估方法来的类。
因此,调用^self new
和^super new
,而不是在任何classess中定义new
,会产生相同的效果 - 因为它们最终都会调用行为的 new
在self
。
答案 4 :(得分:0)
是的,我想你现在明白了...
当您从B班发送^ super new时,您仍然将消息发送给B类,这只是消息是(超级新)...
所以你创建了一个B
实例
当然,除非你定义
A class>>new
^A basicNew