消息和方法之间的区别?


13

在Objective C中,您具有将消息发送到其他对象的概念,并且,这与以C#和Java这样的语言进行的方法调用非常相似。

但是,细微的差别到底是什么?在考虑我的代码时,我应该如何考虑消息传递?

注意:在这里,我只是一名C#/ Java开发人员,试图了解有关Objective C的一些概念。


2
由于它们都是不同的语言,因此差异并不细微。他们是不同的语言。“在考虑我的代码时”?什么代码?在考虑Java或C#时,您不会考虑消息。您考虑方法。您能否阐明具有不相关概念的不相关语言如何具有“细微”差异?
S.Lott

1
请在stackoverflow.com上问您问题
Amir Rezaei

1
这个问题真的应该在StackOverflow上吗?这是关于编程概念的问题,而不是关于我拥有的某些代码的问题。也许我错了,我不知道-边界在模糊……
Vidar

1
@Vidar,这个问题不是主观的。您正在寻找教科书定义。程序员更倾向于发表意见,经验和主观问题。
Stephen Furlani

1
OK-有没有办法让主持人将此问题移至StackOverflow?
维达尔

Answers:


10

消息是选择器的名称,以及该选择器的参数。

选择器是一个符号。

方法是选择器标识的类中的一段代码。

换句话说,[foo bar: baz]说“将@selector(bar:)带有参数调用的消息发送baz到对象foo。您可以将该消息发送到许多不同的对象。

相反,方法 bar:Foo可能看起来像

-(int)bar:(int)n {
  return n + 1;
}

FooTwo可能看起来像

-(int)bar:(int)n {
  return n + 2;
}

(我希望我的语法正确;自从我上次接触Objective-C已经有一段时间了。)

发送消息时,Objective-C内核将消息调度到该消息,foo以确定它是否理解该消息。它根据是否可以找到该选择器标识的方法来决定。

具有相同名称的两种方法和一条消息。

一个对象也可以简单地将一条特定的消息(或一组消息)转发到另一个对象进行处理。在这种情况下,您将消息发送到此代理对象,对象没有与该消息匹配的方法,并且代理将消息转发到其包装的对象。


所以...消息是当您调用dispinterface(a.invoke选择器,args)而方法是当您调用接口(a.methodName)时?难道不是Java,JavaScript和所有动态语言都带有消息,因为一切都通过双重接口发生,而不是直接跳转并偏移到vtable跳转中)?
德米特里(Dmitry)'18

4

从纯粹的理论观点来看,两者之间根本没有区别-有大量的正式证据表明两者是完全等同的,并且任何一个都可以在另一个方面完全实现。

从稍微不太理论的观点来看,存在一个可能的差异:在典型的实现中,虚拟函数表是静态分配的,而每个vtable的内容在编译时是固定的。相比之下,消息查找通常使用某种类似于地图的对象来完成,该对象通常是动态的,这意味着您可以在运行时对其进行修改。这使得在现有类中向消息添加新响应相对容易。不幸的是,在大多数情况下,这仍然是理论上的。首先,你基本上处理自修改代码,大多数人决定是一个非常糟糕的主意一个过去。其次,要使其非常有意义,您非常需要能够将新代码编译到现有类中,以响应您支持的新消息。否则,您几乎可以获得为现有方法动态添加新名称的能力。

正如上一段末所暗示的那样,从实际的角度来看,两者之间几乎没有什么区别。它们只是支持后期绑定的两种(非常轻微)不同的方式。尽管基于消息的查找通常要慢一些,但要使差异真正重要将是非常不寻常的。对于大多数实际目的,它们只是完成同一件事的两种不同方式。


3
您是否有显示证明的参考文献?我想看看。Java的方法调用与Smalltalk的消息发送之间存在巨大差异,这不仅是因为绑定较晚,而且还因为发送方和接收方之间的去耦关系:您无法确定消息的接收方是处理消息还是转发消息例如。
Frank Shearar 2011年

@FrankShearar:对不起,但是没有。我看到的证明是印刷的,很久以前,当OOP和实现它的方法足够新时,有关此类事情的证明对于学者来说很有趣。
杰里·科芬

1

在Objective-C中,消息是后期绑定的。那就是他们在运行时解决。C#通过Dynamic关键字支持类似的构造,该构造也将对象声明为后期绑定。


0

通常,方法调用是在编译时解决的(除非您在Java中使用反射),而Objective C中的消息是在运行时调度的。


2
如果解决方法调用是在编译时解决的,则说明您不使用OOP,而是将语法糖用于以a struct作为第一个参数的重载函数。晚绑定是多态性的必要部分,因此也是OOP的重要组成部分。

2
是。但是,您仍然只能针对在编译时众所周知的东西(在Java中)编写方法调用的代码。如果MyObject或MyInterface没有定义方法foo(),则调用MyObject.foo()将给出错误。ObjC将允许向对象MyObject发送消息“ foo”-如果MyObject没有“ foo”,则它将在运行时爆炸。
Heiko Rupp

我以为Objective C是一种编译语言?
维达尔

1
对于早期/后期绑定(动态类型与结构性类型-在您的示例中,方法调用是在编译时检查的,但不一定是调度的)而言,这是没有实现的。@Vidar:是的,但是它为动态功能增添了魔力。您还可以编译Python。

@Vidar:这不是编译与解释的问题,而是静态与动态的问题。在Java之类的静态OOP语言中,编译器会检查以确保类在编译阶段定义了一个方法。在像Objective-C这样的动态类型语言中,消息是在运行时传递的。
mipadi

-1

消息要么由内核处理,要么由语言本身处理(例如,对于ObjC,有一个很小的汇编代码可以完成)。

例如,在linux内核中,消息是通过系统调用/函数完成的:如果您搜索unix系统编程,则可以找到它们。

方法调用和消息之间的核心区别是:

  • 方法调用仅在您的代码中发生:在ASM中,它由传递的参数的PUSH转换。

  • 内核消息主要是发送到内核的内容,该消息将被跟踪并发回特定进程。我可能会将它们误认为管道,但无论如何:知道已经有了一种机制,可以让您同时运行多个程序并同时进行通信。当然,不要希望这在Windows或其他OS上能以相同的方式工作。


这不是“消息传递”,因为它适用于编程语言。
mipadi
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.