类方法和实例方法有什么区别?

463

类方法和实例方法有什么区别?

实例方法是访问器(获取器和设置器),而类方法基本上包括其他所有内容吗?

18个回答

683

就像其他大多数答案所说的那样,实例方法使用类的一个实例,而类方法可以仅使用类名。在Objective-C中定义它们如下:

@interface MyClass : NSObject

+ (void)aClassMethod;
- (void)anInstanceMethod;

@end

然后它们可以像这样使用:

[MyClass aClassMethod];

MyClass *object = [[MyClass alloc] init];
[object anInstanceMethod];

一些现实世界中类方法的例子是Foundation类中的便捷方法,如NSString的+stringWithFormat:或NSArray的+arrayWithArray:。实例方法将是NSArray的-count方法。


7
好的回答。还值得注意的是,你会看到一种特殊的简写符号来描述方法。例如,+[NSString stringWithFormat:] 是 NSString 类的类方法 +stringWithFormat:;-[NSArray objectAtIndex:] 是实例方法。具有多个选择器部分的方法被写成像 -[NSMutableDictionary setObject:forKey:] 等等。在Cocoa响应、文档和Xcode中经常会看到这种表示法。 - Quinn Taylor
154
许多其他语言中称类方法为“静态”方法。回答原始问题,访问器是实例方法,因为它们设置和获取特定实例的状态。在上面的示例中,NSArray count返回特定实例中对象的数量。 - Brian Pan
2
而类方法可以仅使用类名或类对象。 - user102008
2
抱歉我有点激动...但我刚学会了它们的区别和潜力。类方法很棒,单例类也是!哇,我爱上它们了!<3 - Pavan
2
@BrianPan 静态方法和类方法并不相同。它们很相似,但它们被命名不同的原因是它们的工作方式不同。例如,静态方法不能被覆盖。 - Sulthan

196
所有技术细节在其他回答中已经很好地涵盖了。我想分享一个简单的比喻,我认为很好地说明了类和实例之间的区别:
一个就像一栋房子的蓝图:你只有一个蓝图,通常你不能仅凭蓝图做太多事情。
一个实例(或一个对象)是基于蓝图建造的实际房屋:你可以从同一蓝图中建造许多房屋。你可以在每个房子里涂上不同的颜色,就像你可以独立地改变每个类实例的属性,而不影响其他实例一样。

10
@JohannesFahrenkrug 在这里很好地解释了类和对象的概念。实际问题不是“类方法和实例方法之间的区别”吗? - Shekhu
@Aiden 谢谢。是的,你说得对,问题实际上是关于实例方法和类方法的区别。然而,OP的问题表明他并不真正清楚类与实例的概念。一旦这个概念清晰了,其他部分就会迎刃而解。 - Johannes Fahrenkrug
1
类与类的实例之间的完美解释。对于新手来说,类是一个奇怪的概念,这个解释以最基本的方式进行了说明。 - Alex McPherson
1
@JohannesFahrenkrug 的解释真的很好,让我思考两者的区别以及何时使用它们。 - ChenSmile
1
这是一个非常好的解释 :) - Praveenkumar
1
好比喻。请有人给这个家伙一年的披萨供应。 - GeneCode

105

像其他答案所说的那样,实例方法作用于一个对象并且可以访问其实例变量,而类方法作用于整个类,且没有访问特定实例变量的权限(除非您将该实例作为参数传递)。

一个很好的类方法示例是计数器类型的方法,它返回类的实例总数。类方法以+开头,而实例方法以-开头。 例如:

static int numberOfPeople = 0;

@interface MNPerson : NSObject {
     int age;  //instance variable
}

+ (int)population; //class method. Returns how many people have been made.
- (id)init; //instance. Constructs object, increments numberOfPeople by one.
- (int)age; //instance. returns the person age
@end

@implementation MNPerson
- (id)init{
    if (self = [super init]){
          numberOfPeople++;
          age = 0;
    }    
    return self;
}

+ (int)population{ 
     return numberOfPeople;
}

- (int)age{
     return age;
}

@end

main.m:

MNPerson *micmoo = [[MNPerson alloc] init];
MNPerson *jon = [[MNPerson alloc] init];
NSLog(@"Age: %d",[micmoo age]);
NSLog(@"%Number Of people: %d",[MNPerson population]);

输出: 年龄:0 人数:2

另一个例子是,如果你有一个希望用户能够调用的方法,有时将其定义为类方法是很好的选择。例如,如果你有一个名为MathFunctions的类,你可以这样做:

+ (int)square:(int)num{ 
      return num * num;
}

那么用户将会调用:

[MathFunctions square:34];

而无需实例化该类!

您还可以使用类函数返回自动释放的对象,例如NSArray的

+ (NSArray *)arrayWithObject:(id)object

这个方法接收一个对象,将其放入数组中,并返回一个自动释放的版本的数组,不需要进行内存管理,非常适用于临时数组等情况。

我希望你现在了解何时和/或为什么应该使用类方法!


1
micmoo,我可以建议您将“static int numberOfPeople = 0;”放在代码格式化文本中吗?在我注意到它在示例代码上方之前,我感到困惑。除此之外,这是一个非常简洁的答案。 - mobibob
2
请原谅我的新手困惑,但为什么您需要实例变量“age”和实例方法“age”?使用@synthetize不会创建实例变量“age”的getter和setter吗? - selytch
@selytch,“age”必须被定义为属性才能使用synthesize。 - micah94

38

实例方法适用于类的实例(即对象),而类方法适用于类本身。

在C#中,类方法被标记为静态的。未标记为静态的方法和属性是实例方法。

class Foo {
  public static void ClassMethod() { ... }
  public void InstanceMethod() { ... }
}

1
啊,抱歉,我刚注意到这是一个 Obj-C 的问题。希望我的回答仍然适用,但请投反对票或投票删除。 - Robert Horvick
6
没问题。你的回答的第一部分作为面向对象编程的一般原则是正确的,并且绝对适用于Objective-C。如果你不想看到这样的问题,你可以将"objective-c"添加到你的标签忽略列表中,但是任何参与肯定是受欢迎的。 :-) - Quinn Taylor

16

你问题的答案并不特定于objective-c语言,然而在不同的编程语言中,类方法也可以被称为静态方法。

类方法和实例方法之间的区别是:

类方法

  • 操作类变量(无法访问实例变量)
  • 不需要实例化对象即可应用
  • 有时可能成为代码异味(对OOP编程新手来说,作为在OO环境中进行结构化编程的支撑)

实例方法

  • 操作实例变量和类变量
  • 必须有一个已实例化的对象才能进行操作

实例方法可以操作类变量吗? - 蘇健豪

16

我认为理解这个问题的最好方式是看一下allocinit。正是这个解释让我理解了它们之间的区别。

类方法

类方法应用于整个类。如果您查看alloc方法,那么在方法声明之前的+表示这是一个类方法。这是一个类方法,因为它应用于类来创建该类的特定实例。

实例方法

您使用实例方法来修改该类的特定实例,而不是修改整个类。例如,init(在方法声明之前用-表示)是一个实例方法,因为您通常会在使用alloc创建该类之后修改该类的属性。

示例

NSString *myString = [NSString alloc];
你正在调用类方法alloc来生成该类的实例。注意消息的接收者是一个类。
[myString initWithFormat:@"Hope this answer helps someone"];
您正在修改名为myStringNSString实例,通过在该实例上设置一些属性。请注意,消息的接收者是一个实例(类NSString的对象)。

你说的“检查alloc方法”是什么意思?你能指出文档中的具体位置吗?(编辑)--> 啊,没事了,在NSObject文档中,在“任务”下面有写 - https://developer.apple.com/library/ios/documentation/cocoa/reference/foundation/classes/nsobject_class/reference/reference.html - Ethan Parker
你不需要真正理解它的作用就能掌握这个,只需要知道它被应用于类中。简单来说:alloc为对象分配足够的内存,init将修改那些内存地址中的内容以定义对象的状态。除非有空间可以修改对象,否则我们无法修改对象,因此我们在类上使用alloc,它将决定为我们提供该空间。 - Adam Waite

6

类方法通常用于创建该类的实例。

例如,[NSString stringWithFormat:@"SomeParameter"]; 返回一个带有发送给它的参数的 NSString 实例。因此,由于它是返回其类型对象的类方法,它也被称为便利方法。


6
所以如果我理解正确的话,class方法不需要你分配该对象的实例来使用/处理它。一个class方法是自包含的,可以独立于任何类的对象状态而运行。一个class方法应该为它所有的工作分配内存,并在完成后进行释放,因为该类的任何实例都无法释放前面调用类方法时分配的任何内存。
一个instance方法则完全相反。除非你分配该类的一个实例,否则你无法调用它。就像一个普通的类,它有一个构造函数并且可以有一个析构函数(清理所有分配的内存)。
在大多数情况下(除非您正在编写可重用库),您不需要一个class变量。

1
需要使用类方法的一个明显情况是创建实例。您必须能够在没有任何实例的情况下创建实例,否则第一个实例将永远无法创建。这就是为什么+alloc是并且必须是一个类方法的原因。 - gnasher729

4

实例方法操作类的实例(即“对象”)。类方法与类相关联(大多数语言使用关键字 static 来表示这些方法)。


3
在Objective-C中,所有的方法都以"-"或"+"字符开头。示例:
@interface MyClass : NSObject
// instance method
- (void) instanceMethod;

+ (void) classMethod;
@end

"+"和"-"字符分别指定方法是类方法还是实例方法
如果我们调用这些方法,差异就会变得很清晰。这里的方法在MyClass中声明。 实例方法需要类的一个实例:
MyClass* myClass = [[MyClass alloc] init];
[myClass instanceMethod];

MyClass内部,其他方法可以使用self调用MyClass的实例方法:

-(void) someMethod
{
    [self instanceMethod];
}

但是,类方法必须在类本身上调用:

[MyClass classMethod];

或者:

MyClass* myClass = [[MyClass alloc] init];
[myClass class] classMethod];

这不会起作用:

// Error
[myClass classMethod];
// Error
[self classMethod];

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接