Smalltalk 中的 OO 和 Java 之间的主要区别是什么?
Smalltalk 中的 OO 和 Java 之间的主要区别是什么?
请注意,我是一名 Java 程序员,试图通过探索 Smalltalk 来拓展自己的视野。目前我对Smalltalk几乎一无所知,除了它比Java更纯粹之外。因此,我更喜欢显示各种 Java 概念如何映射到相应的 Smalltalk 概念,然后介绍 Java 中根本不存在的 Smalltalk 概念的答案。
What are the key differences between OO in Smalltalk and Java?
Please note that I am a Java programmer trying to expand his horizons by exploring Smalltalk. Currently I know almost nothing about Smalltalk except that it's purer than Java. Therefore I'll prefer the answer that shows how various Java concepts map to corresponding Smalltalk concepts and then introduces the Smalltalk concepts that don't exist in Java at all.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
消息传递
Smalltalk 使用消息传递,而不是方法调用。这种区别很微妙,但却非常强大。
一些术语:给定
foo bar: baz
,#bar:
是一个选择器,foo 是一个接收器名为#bar:
的消息(# 表示一个符号,很像 Common Lisp 会说'bar
(或者更合适的是:bar
) ),baz
是一个参数或参数。当该行执行时,将向foo
发送带有参数baz
的消息#:bar:
。到目前为止,这还算正常。在 Java 中,它看起来像foo.bar(baz);
。在Java中,运行时系统会找出
foo
的实际类型,找到最合适的方法,然后运行它。Smalltalk 中的情况看起来几乎相同。当您向对象发送消息时,它会在其方法字典中搜索名称与消息选择器的名称相匹配的方法。如果找不到,它将在其超类的方法字典中搜索,依此类推。很正常的事情。
如果找不到任何匹配的方法,它会向自己发送
#doesNotUnderstand:
消息,并以原始消息作为参数。 (是的,发送的消息是一个对象。)但是#doesNotUnderstand:
也只是一个方法。您可以覆盖它。例如,您可以让一个对象响应某些消息集,同时将其收到的任何其他消息转发到某个委托对象。覆盖#doesNotUnderstand: 嘿,很快,您就拥有了一个无需维护即可保持其协议与委托同步的代理。
简单的语法
不,我不是在开玩笑。 Smalltalk 的整个语法可能有 15 行长。 JLS 是……不是。为什么要关心?简单的语法使得分解一段代码变得很容易。元编程!重构!
无语法 for:
(n < 3) ifTrue: ['yes'] ifFalse: ['no']
1 to: 10 do: [:i |脚本显示: i asString]
[i := i / 0] ifError: ['oops!']
[i := i / 0]确保:[stream close]
并注意所有这些
[]
- 具有干净语法的一流闭包。Message passing
Smalltalk uses message passing, not method invocation. The distinction is subtle, but enormously powerful.
Some terminology: Given
foo bar: baz
,#bar:
is a selector, foo is the receiver of a message called#bar:
(the # indicates a symbol, much like Common Lisp would say'bar
(or even more appropriately,:bar
)), andbaz
is an argument or parameter. When the line's executed,foo
is sent the message#:bar:
with argumentbaz
. So far, it's pretty normal. In Java it would look likefoo.bar(baz);
.In Java, the runtime system would figure out
foo
's actual type, find the most appropriate method, and run it.Things look almost the same in Smalltalk. When you send an object a message, it searches in its method dictionary for a method whose name matches that of the selector of the message. If it can't find one, it searches in its superclass' method dictionary, and so on. Pretty normal stuff.
If it can't find any matching method, it sends itself the
#doesNotUnderstand:
message, with the original message as a parameter. (Yes, a message send is an object.) But#doesNotUnderstand:
is also just a method. You can override it.For instance, you can have an object that responds to some set of messages while forwarding any other messages it receives to some delegate object. Override
#doesNotUnderstand:
and hey presto, you have a proxy that will need no maintenance to keep its protocol in sync with the delegate.Trivial syntax
No, I'm not joking. Smalltalk's entire grammar's maybe 15 lines long. The JLS is... not. Why care? A simple syntax makes it simple to tear a chunk of code apart. Metaprogramming! Refactoring!
No syntax for:
(n < 3) ifTrue: ['yes'] ifFalse: ['no']
1 to: 10 do: [:i | Transcript show: i asString]
[i := i / 0] ifError: ['oops!']
[i := i / 0] ensure: [stream close]
And notice all those
[]
s - first-class closures with a clean syntax.this
的特殊第一个参数。this
.Java 和 Smalltalk 之间的一个关键区别是 Smalltalk 具有一流的类(没有双关语)。
Smalltalk 中的类是一个对象。与
static
方法和变量最接近的是类端方法和变量,如 弗兰克·希勒 (Frank Shearer) 提及。但一旦使用继承,这种差异就更加深刻。在java中类端继承不存在,而在Smalltalk中是可能的。
如果类
A
继承自B
,并且如果您有a
和b
,它们是A 的实例
和B
,在Smalltalk中,b类
继承自a类
。在 Java 中,情况并非如此,其中a getClass()
和b getClass()
返回Class
的实例,它们与每个实例无关其他。现在假设类
A
实现了单例模式:它有一个类端字段instance
和一个 getter 方法instance
。B
类是另一个具有自己的instance
字段的对象。因此,A 实例
和B 实例
将返回不同的对象。从 OO 的角度来看,这显然是 Smalltalk 和 Java 之间的主要区别之一。
其他差异包括元类、扩展方法、鸭子类型与静态类型的存在、
doesNotUnderstand
的具体化以及其他一些使 Smalltalk 或 Java 中的编码完全不同的事情。当然,Smalltalk 具有 Java 所缺乏的封闭性。
另请参阅 为什么 Java 不允许重写静态方法?
A key difference between Java and Smalltalk is that Smalltalk has first-class class (no pun intended).
A class in Smalltalk is an object. The closest thing to
static
method and variable is then class-side method and variable, as mentioned by Frank Shearer.But this difference is more profound as soon as inheritance is used. In java class-side inheritance does not exists, while it is possible in Smalltalk.
If class
A
inherits fromB
, and if you havea
andb
which are instances ofA
andB
, in Smalltalk,b class
inherits froma class
. This would not be the case in Java wherea getClass()
andb getClass()
return instances ofClass
, which are not related with each other.Let's say now that class
A
implements the singleton pattern: it has a class-side fieldinstance
and an getter methodinstance
. ClassB
is another object with its owninstance
field. As a consequence,A instance
andB instance
will return different object.This is clearly one of the major difference between Smalltalk and Java from a OO standpoint.
Other difference include the existence of metaclasses, extension methods, duck typing vs static typing, reification of
doesNotUnderstand
and few other things that make coding in Smalltalk or Java completely different.And of course, Smalltalk has closure which Java still lacks.
See also Why doesn’t Java allow overriding of static methods ?
如果您积极尝试探索 Smalltalk,那么您需要知道如何阅读 Smalltalk -
"我可以阅读 C++ 和 Java,但我无法阅读 Smalltalk" pdf
If you are actively trying to explore Smalltalk then you need to know how to read Smalltalk -
"I Can Read C++ and Java But I Can’t Read Smalltalk" pdf
Java 中不存在但近年来变得越来越流行的 Smalltalk 概念是块。块是匿名函数的一种形式,包括定义它们的上下文。重要的是,块也是对象。 Smalltalk 实际上缺乏任何类型的内置
if
语句或for
循环或类似的东西,但设法仅通过消息传递和块来创建相同的效果。One Smalltalk concept that doesn't exist in Java but has become increasingly popular in recent years is blocks. Blocks are a form of anonymous functions that include the context they were defined in. Importantly, blocks are also objects. Smalltalk actually lacked any kind of built-in
if
-statement orfor
-loop or anything like that, but managed to create the same effect just with message-passing and blocks.在 Smalltalk 中,一切都是对象,而在 Java 中,像小整数这样的东西仍然不是第一类对象。另外,继续讨论数字,在 Smalltalk 中,由于其纯粹的面向对象性质和强大的反射能力,我们永远不需要关心数字的大小,例如整数是小还是大,以及当小整数溢出到大时会发生什么。
In Smalltalk everything is the object while in Java things like small integers are still not the first class objects. Also, to continue with numbers, in Smalltalk due to its pure OO nature and strong reflective capabilities we never need to care about the number size, like if an integer is small or large and what happens when small integer overflows to large.
当@Janko Mivšek 意味着一切时,他真的意味着一切。 :)
即使在消息发送之前,您所做的也是创建一个作为上下文的对象。
另外,smalltalk 中没有访问修饰符(私有/受保护/公共)
在某些 Smalltalk 实现中没有包,并且在大多数 Smalltalk 实现中包不具有与 Java 相同的语义。
在smalltalk中,你没有像for、if、try/catch这样的控制结构...很酷的事情是你不需要它们,因为在smalltalk中你有块闭包。
在smalltalk中,你没有静态成员,而是有对象类(你可以向类发送消息,也可以将类保存在变量中)。
在smalltalk中,你没有嵌套类。
...
When @Janko Mivšek mean everything he really mean everything. :)
Even up to message send, what your are doing is creating an object that is the context.
Also what you don't have in smalltalk is access modifier (private/ protected / public)
You don't have package in some Smalltalk implementation and in most Smalltalk implementation package don't have the same semantic than Java.
In smalltalk you don't have control structure like for, if, try/catch... The cool things is that you don't need them because you have block closure in smalltalk.
In smalltalk you don't have static member instead you have Class that are object(you can send message to class, you also can hold class in a variable).
In smalltalk you don't have nested class.
...