Swift中static和class的区别

241 阅读3分钟

在Swift中,staticclass关键字都用于定义类型层面的成员(方法和属性),但它们在适用范围、继承性及使用场景上有显著差异。以下是详细说明:


1. 核心区别

特性staticclass
适用范围类、结构体、枚举仅类
是否允许重写不可重写(隐式 final可被子类重写
存储属性支持支持不支持(仅计算属性和方法)

2. 使用示例

类的场景

class Parent {
    // 可被子类重写的类方法
    class func dynamicMethod() {
        print("Parent's dynamic method")
    }
    
    // 不可重写的类方法(等价于 final class)
    static func staticMethod() {
        print("Parent's static method")
    }
    
    // 类计算属性(可重写)
    class var dynamicProperty: Int { 100 }
    
    // 静态存储属性(不可重写)
    static let staticProperty: Int = 200
}

class Child: Parent {
    // 重写父类的类方法
    override class func dynamicMethod() {
        print("Child's dynamic method")
    }
    
    // 重写父类的类计算属性
    override class var dynamicProperty: Int { 200 }
    
    // ❌ 以下代码会报错:static成员不可重写
    // override static func staticMethod() { ... }
}

结构体/枚举的场景

struct MyStruct {
    // 结构体的类型方法(只能用 static)
    static func myMethod() {
        print("Struct's static method")
    }
}

enum MyEnum {
    // 枚举的类型属性(只能用 static)
    static var myProperty: Int { 42 }
}

协议中的实现

protocol MyProtocol {
    static func protocolMethod()
}

class MyClass: MyProtocol {
    // 使用 class 实现协议方法(允许子类重写)
    class func protocolMethod() {
        print("Class's protocol implementation")
    }
}

struct MyStruct: MyProtocol {
    // 使用 static 实现协议方法
    static func protocolMethod() {
        print("Struct's protocol implementation")
    }
}

3. 场景对比

场景推荐关键字原因
需要子类重写的方法class支持动态派发和多态‌24
结构体/枚举的类型成员static唯一可用选项‌16
类的不可变类型常量static内存高效,全局唯一‌15
类的存储类型属性staticclass无法修饰存储属性‌35
需禁止子类修改的类方法static编译时绑定,不可重写‌

4. 原理说明

  • static关键字
    适用于所有类型(类、结构体、枚举),定义的成员隐式标记为 final,禁止重写。对于类,static成员等价于 final class,确保类型成员的行为在编译期确定。

  • class关键字
    仅用于类,允许子类通过 override 重写。由于Swift的类继承特性,class成员在运行时动态派发(除非被标记为 final 或由编译器优化)。

  • 存储属性的限制
    class不能修饰存储属性,因为类的类型存储属性需要在全局唯一地址存储,而 static通过编译期确定的全局存储实现这一目标。

  • 内存分配‌:static 属性在类型加载时分配内存,全局唯一;class 方法通过虚函数表动态派发‌。

  • 语法等价性‌:static var 在类中等价于 final class var,均禁止重写‌。


5. 总结

  • 使用 class 需要支持子类重写(仅类可用)。
  • 使用 static 需要跨类型通用(类、结构体、枚举)或禁止重写。
  • 协议中声明类型成员时,统一用 static,由具体类型决定是否可重写(类用 class,结构体/枚举用 static)。