Каковы основные отличия между OO в Smalltalk и Java?
Обратите внимание на то, что я - программист Java, пытающийся развернуть его горизонты путем исследования Smalltalk. В настоящее время я почти ничего не знаю о Smalltalk за исключением того, что это более чисто, чем Java. Поэтому я предпочту ответ, который показывает, как различные понятия Java отображаются на соответствующие понятия Smalltalk, и затем представляет понятия Smalltalk, которые не существуют в Java вообще.
В Smalltalk все является объектом, в то время как в Java такие вещи, как маленькие целые числа, все еще не являются объектами первого класса. Кроме того, продолжая тему чисел, в Smalltalk из-за его чистой ОО-природы и сильных отражательных возможностей нам никогда не нужно заботиться о размере числа, например, о том, является ли целое число маленьким или большим, и что происходит, когда маленькое целое число переполняется до большого.
Smalltalk использует передачу сообщений, а не вызов методов. Различие тонкое, но чрезвычайно сильное.
Некоторая терминология: Учитывая foo bar: baz
, #bar:
- селектор , foo - получатель сообщения называется #bar:
(# обозначает символ, подобно тому, как Common Lisp сказал бы 'bar
(или, что более уместно, : bar
)), и baz
- это аргумент или параметр . При выполнении строки foo
отправляется сообщение #: bar:
с аргументом baz
. Пока это вполне нормально. В Java это будет выглядеть как foo.bar (baz);
.
В Java исполняющая система определит фактический тип foo
, найдет наиболее подходящий метод и запустит его.
В Smalltalk все выглядит почти примерно так же. Когда вы отправляете объекту сообщение, он ищет в своем словаре методов метод, имя которого совпадает с именем селектора сообщения. Если он не может его найти, он ищет в словаре методов своего суперкласса и так далее. Довольно нормальные вещи.
Если не удается найти подходящий метод, он отправляет себе сообщение #doesNotUnderstand:
с исходным сообщением в качестве параметра. (Да, отправленное сообщение - это объект.) Но #doesNotUnderstand:
также является просто методом. Вы можете отменить это.
Например, у вас может быть объект, который реагирует на некоторый набор сообщений, при этом перенаправляя любые другие сообщения, которые он получает, некоторому объекту-делегату. Переопределите #doesNotUnderstand:
и, пожалуйста, у вас есть прокси-сервер, который не нуждается в обслуживании, чтобы поддерживать синхронизацию его протокола с делегатом.
Нет, я не шучу. Вся грамматика Smalltalk состоит из 15 строк. JLS ... нет. Зачем заботиться? Простой синтаксис позволяет легко разделить кусок кода. Метапрограммирование! Рефакторинг!
Нет синтаксиса для:
(n <3) ifTrue: ['yes'] ifFalse: ['no']
1 to: 10 do: [: я | Транскрипт показывает: i asString]
[i: = i / 0] ifError: ['oops!']
[i: = i / 0] sure: [stream close]
И обратите внимание на все эти []
s - первоклассные замыкания с чистым синтаксисом.
Когда @Janko Mivšek имеет в виду все, он действительно имеет в виду все. :)
Даже вплоть до отправки сообщения, то, что вы делаете, это создаете объект, который является контекстом.
Также, чего у вас нет в smalltalk, так это модификаторов доступа (private/ protected / public). У вас нет пакета в некоторых реализациях Smalltalk, и в большинстве реализаций Smalltalk пакет не имеет той же семантики, что и Java.
В Smalltalk у вас нет управляющих структур, таких как for, if, try/catch... Самое интересное, что они вам не нужны, потому что в smalltalk есть закрытие блока.
В smalltalk у вас нет статических членов, вместо этого у вас есть класс, который является объектом (вы можете послать сообщение классу, вы также можете хранить класс в переменной).
В smalltalk у вас нет вложенных классов.
...
Ключевое различие между Java и Smalltalk состоит в том, что Smalltalk имеет первоклассный класс (без каламбура).
Класс в Smalltalk - это объект. Наиболее близким к статическому
методу и переменной является тогда метод и переменная на стороне класса, как упоминал Фрэнк Ширер.
Но это различие становится более глубоким, когда используется наследование. В java наследования на стороне классов не существует, тогда как в Smalltalk это возможно.
Если класс A
наследуется от B
, и если у вас есть a
и b
, которые являются экземплярами A
и B
, в Smalltalk b-класс
наследуется от класса
. Этого не будет в Java, где a getClass ()
и b getClass ()
возвращают экземпляры Class
, которые не связаны друг с другом.
Предположим теперь, что класс A
реализует одноэлементный шаблон: у него есть поле на стороне класса экземпляр
и экземпляр метода получения
. Класс B
- это еще один объект со своим собственным полем экземпляра
. Как следствие, экземпляр
и экземпляр B
будут возвращать разные объекты.
Это одно из основных различий между Smalltalk и Java с точки зрения объектно-ориентированного программирования.
Другое отличие включает в себя наличие метаклассов, методов расширения, утиную типизацию по сравнению со статической типизацией, реификацию doesNotUnderstand
и несколько других вещей, которые делают кодирование на Smalltalk или Java совершенно другим.
И, конечно же, в Smalltalk есть закрытие, которого пока нет в Java.
См. Также Почему Java не допускает переопределения статических методов?
пытается расширить свои горизонты путем изучая Smalltalk
Если вы активно пытаетесь изучить Smalltalk, то вам нужно знать, как читать Smalltalk -
Одна концепция Smalltalk, которой нет в Java, но которая становится все более популярной в последние годы это блоки. Блоки - это форма анонимных функций, которые включают контекст, в котором они были определены. Важно отметить, что блоки также являются объектами. В Smalltalk фактически отсутствовало какое-либо встроенное выражение if,
или for
-loop или что-то в этом роде, но ему удавалось создать тот же эффект только с помощью передачи сообщений и блоков.
object isBig ifTrue: [self runIntoObject:object]
ifFalse: [self katamariBall absorbObject:object].
1 to: 10 do: [:number | number print]
this
.