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


Answers:


673

就像大多数其他答案所说的那样,实例方法使用类的实例,而类方法只能与类名一起使用。因此,在Objective-C中对它们进行了定义:

@interface MyClass : NSObject

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

@end

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

[MyClass aClassMethod];

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

一些真实世界的类方法的例子是很多基础类,如方便的方法NSString+stringWithFormat:NSArray+arrayWithArray:。实例方法将是NSArray-count方法。


7
好答案。还值得注意的是,您将看到用于描述方法的特殊速记符号。例如,+ [NSString stringWithFormat:]是NSString上的类方法+ stringWithFormat:。-[NSArray objectAtIndex:]是一个实例方法。具有多个选择器部分的方法以-[NSMutableDictionary setObject:forKey:]等形式编写。在Cocoa响应,文档和Xcode中,您经常会看到这种表示法。
Quinn Taylor

149
我要补充一点,在许多其他语言中,类方法被称为“静态”方法。为了回答最初的问题,访问器是实例方法,因为它们正在设置并获取特定实例的状态。在上面的示例中,NSArray计数返回特定实例中的对象数。
布莱恩·潘

2
“而类方法只能与类名一起使用。” 或类对象
user102008 2011年

2
对不起,我很兴奋……但是我才了解到这种差异及其潜力。类方法摇滚,单例类也是如此!ufff我坠入爱河了!<3
Pavan 2012年

2
@BrianPan静态方法和类方法不同。它们相似,但命名不同的原因是它们的工作方式不同。例如,静态方法不能被覆盖。
Sulthan 2013年

190

所有技术细节均已很好地涵盖在其他答案中。我只想分享一个简单的类比,我认为它很好地说明了类和实例之间的区别:

在此处输入图片说明

堂课就像一栋房子的蓝图:您只有一个蓝图,并且(通常)仅凭蓝图就不能做那么多。

在此处输入图片说明

一个实例(或对象)是实际的房子,你构建基于蓝图:您可以从同一个蓝图建造大量房屋。然后,您可以在每个房屋中为墙壁涂上不同的颜色,就像可以独立更改类的每个实例的属性而不会影响其他实例一样。


6
@JohannesFahrenkrug在这里很好地解释了类和对象的概念difference between class method and an instance method
Shekhu 2015年

1
类与类实例的完美解释。对于新手来说,上课是一个奇怪的概念,这从根本上解释了它。
Alex McPherson

1
@JohannesFahrenkrug确实是一个很好的解释,这让我开始思考如何比较差异以及何时使用两者
ChenSmile

1
如此出色的解释:)
Praveenkumar

1
打个比方。请有人给这个家伙一年的比萨饼。
GeneCode'7

102

就像其他答案所说的那样,实例方法在对象上运行并可以访问其实例变量,而类方法在整个类上运行且不能访问特定实例的变量(除非您将实例作为对象传递给参数)。

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

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 2010年

2
请原谅我的新手困惑,但是为什么同时需要实例变量“ age”和实例方法“ age”?不会使用@synthetize创建实例变量“ age”的getter和setter吗?
selytch

@selytch“ age”必须定义为属性才能使用合成。
micah94 2014年

36

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

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

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

1
Argh-对不起,我刚刚注意到这是一个Obj-C问题。希望我的答案仍然适用,但请投下反对票或投票删除。
罗伯特·霍维克

6
没有伤害。作为一般的OOP原则,答案的第一部分是正确的,并且肯定适用于Objective-C。您可以将“ objective-c”添加到标签列表中,如果您不想看到这样的问题,则可以忽略,尽管欢迎任何参与。:-)
奎因·泰勒

16

您问题的答案并非特定于Objective-C,但是在不同语言中,Class方法可能称为静态方法。

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

类方法

  • 对类变量进行操作(它们无法访问实例变量)
  • 不需要实例化对象即可应用
  • 有时可能是代码的味道(一些不熟悉OOP的人用作拐杖在OO环境中进行结构化编程)

实例方法

  • 操作实例变量和类变量
  • 必须具有实例化对象才能进行操作

实例方法可以对类变量进行操作吗?
苏健豪2016年

16

我认为最好的理解方法是看allocinit。正是这种解释使我能够理解差异。

类方法

类方法应用于整个类。如果您检查alloc方法,则该类方法由+方法声明之前的表示。这是一个类方法,因为它被应用于该类以创建该类的特定实例。

实例方法

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

NSString *myString = [NSString alloc];

您正在调用类方法alloc以便生成该类的实例。注意消息的接收者是一个类。

[myString initWithFormat:@"Hope this answer helps someone"];

您正在通过在NSString被调用的实例上myString设置一些属性来对其进行修改。请注意,消息的接收者如何是一个实例(class的对象NSString)。


检查“分配”方法是什么意思?您能指出我在文档中的特定位置吗?(编辑) - >啊请不要介意,是在NSObject的文档它说,在“任务” - developer.apple.com/library/ios/documentation/cocoa/reference/...
伊桑·帕克

您不需要真正理解它的实际作用,只需将其应用于班级即可。简而言之:alloc为对象分配足够的内存,init将修改这些内存地址中的内容以定义对象的状态。除非有空间可以修改它,否则我们无法修改对象,因此我们alloc在类上使用它将决定给我们该空间。
亚当·怀特

6

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

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


6

所以,如果我理解正确。

一种class方法不需要您分配该对象的实例来使用/处理它。甲class方法是自包含的并且可以在不那类的任何对象的状态中的任意依赖性操作。一个class由于该类的任何实例都无法释放在先前对类方法的调用中分配的任何内存,因此期望方法为所有其自己的工作分配内存,并在完成后取消分配。

一个 instance方法是正好相反。除非您分配该类的实例,否则无法调用它。它就像具有构造函数和可以具有析构函数的普通类(清除所有分配的内存)。

在大多数情况下(除非您正在编写可重用的库,否则您不需要class变量。


1
需要类方法的一个明显情况是创建实例。您必须能够创建实例而又没有任何实例,否则将永远无法创建第一个实例。这就是+ alloc是且必须是类方法的原因。
gnasher729 2014年

4

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


3

以一个产生大量汽车的游戏为例。每个汽车都属于CCar类。实例化汽车时,它会调用

[CCar registerCar:self]

因此,CCar类可以列出每个实例化的CCar。假设用户完成了一个关卡,并想要删除所有汽车...您可以:1-遍历您手动创建的每个CCar的列表,然后执行以下操作:whicheverCar.remove(); 或2-向CCar添加removeAllCars方法,即可完成此操作当您致电[CCar removeAllCars]时。即 allCars[n].remove();

或者,例如,您允许用户为整个应用程序指定默认字体大小,该字体大小将在启动时加载并保存。没有class方法,您可能必须做类似的事情

fontSize = thisMenu.getParent().fontHandler.getDefaultFontSize();

使用class方法,您可以摆脱 [FontHandler getDefaultFontSize]

至于removeVowels函数,您会发现像C#这样的语言实际上同时具有某些方法,例如toLower或toUpper。

例如myString.removeVowels()String.removeVowels(myString) (在ObjC中,[String removeVowels:myString])。

在这种情况下,实例可能会调用class方法,因此两者均可用。即

public function toLower():String{
  return String.toLower();
}

public static function toLower( String inString):String{
 //do stuff to string..
 return newString;
}

基本上, myString.toLower() 电话 [String toLower:ownValue]

没有明确的答案,但是如果您想使用一个类方法可以改善您的代码,可以尝试一下,并记住一个类方法只能让您使用其他类方法/变量。


3

类方法

是声明为静态的方法。可以在不创建类实例的情况下调用该方法。类方法只能对类成员操作,而不能对实例成员操作,因为类方法不知道实例成员。除非在该类的实例上调用它们,否则也不能从该类方法内调用该类的实例方法。

实例方法

另一方面,需要先存在该类的实例,然后才能调用它们,因此需要使用new关键字创建一个类的实例。实例方法在类的特定实例上运行。实例方法未声明为静态。


它也可以使用“ alloc”关键字创建,而不仅仅是“ new”。另外,Objective-C不需要实例存在就可以调用实例方法,您可以将消息发送到空指针。
Elviss Strazdins 2015年

3

在Objective-C中,所有方法均以“-”或“ +”字符开头。例:

@interface MyClass : NSObject
// instance method
- (void) instanceMethod;

+ (void) classMethod;
@end

“ +”和“-”字符分别指定方法是a class method还是a instance method

如果我们调用这些方法,区别将很明显。这些方法在中声明MyClass

instance method 需要该类的一个实例:

MyClass* myClass = [[MyClass alloc] init];
[myClass instanceMethod];

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

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

但是,class methods必须在类本身上调用:

[MyClass classMethod];

要么:

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

这行不通:

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

3

分类方法


类方法通常创建该类的新实例或检索该类的某些全局属性。类方法不能在实例上操作或不能访问实例变量。


实例方法


实例方法对类的特定实例进行操作。例如,您实现的访问器方法都是实例方法。您可以使用它们来设置或获取特定对象的实例变量。


调用


要调用实例方法,请将消息发送到该类的实例。

要调用类方法,可以将消息直接发送到类。


来源:IOS-Objective-C-类方法和实例方法


1

类方法不能更改或知道任何实例变量的值。那应该是知道实例方法是否可以是类方法的标准。


-1,因为您可以将实例传递给class方法,并且它将能够更改并知道它是变量的值。
Elviss Strazdins 2015年

1

还要记住,同样的想法也适用于变量。在谈论变量时,您会遇到与静态方法,成员,实例,类等类似的术语,就像处理方法/函数一样。

看来Obj-C社区中的通用术语是变量代表ivar,但我还不是Obj-C的家伙。


1

作为上述答案的更新,我同意实例方法使用类的实例,而类方法只能与类名一起使用。

在Objective-C中实现自动引用计数后,实例方法与类方法之间不再存在任何区别。

例如,[NS StringWithformat:..]类方法和[[NSString alloc] initwihtformat:..]实例方法,在ARC之后都相同


1

注意:这仅是伪代码格式

类方法

它几乎需要做的就是在编译期间。它不需要任何用户输入,也不需要基于实例进行计算。关于它的所有内容都基于类/蓝图-这是唯一的,即您对于一个类没有多个蓝图。编译期间可以有不同的变化吗?不,因此该类是唯一的,因此无论您调用一个类方法多少次,指向它的指针都将是相同的。

PlanetOfLiving: return @"Earth" // No matter how many times you run this method...nothing changes.

实例方法

相反,实例方法在运行时发生,因为只有这样,您才创建了某个实例的实例,该实例可能会在每次实例化时发生变化。

initWithName: @"John" lastName: @"Doe"Age:12 @"cool"
initWithName: @"Donald" lastName: @"Drumpf"Age:5 attitude:@"He started"
initWithName: @"President" lastName: @"Obama"Age:54 attitude: @"Awesome"
//As you can see the value can change for each instance.

如果您来自其他语言,则静态方法与类方法相同。
如果您来自Swift,则类型方法与类方法相同。


0

添加到以上答案

类方法适用于类,我们将其用于通用目的,例如+ stringWithFormat,类的大小,最重要的是用于init等。

NSString *str = [NSString stringWithFormat:@"%.02f%%",someFloat]; 

实例方法将在类的实例上工作,而不是在类上起作用,就像我们有两个人一样,我们想在这里分别使用实例方法来了解每个实例的平衡。因为它不会返回一般响应。例如像确定NSSArray的计数等。

[johnson getAccountBalance];
[ankit getAccountBalance];
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.