Swift基础-类和继承

创建自己的类

类与结构相似,因为它们使您可以使用属性和方法创建新类型,但是它们有五个重要的区别,我将一次向您介绍所有这些区别。

类和结构之间的第一个区别是类永远不会带有成员初始化器。这意味着,如果您的类中有属性,则必须始终创建自己的初始化程序。

例如:

class Dog {
    var name: String
    var breed: String

    init(name: String, breed: String) {
        self.name = name
        self.breed = breed
    }
}

创建该类的实例看起来就像是一个结构一样:

let poppy = Dog(name: "Poppy", breed: "Poodle")

类继承

类和结构之间的第二个区别是,您可以基于现有类创建一个类-它继承了原始类的所有属性和方法,并且可以在顶部添加自己的类。

这称为类继承或子类,您从其继承的类称为“父”或“超级”类,新类称为“子”类。

这是Dog我们刚刚创建的类:

class Dog {
    var name: String
    var breed: String

    init(name: String, breed: String) {
        self.name = name
        self.breed = breed
    }
}

我们可以基于一个名为的类创建一个新类Poodle。默认情况下,它将继承Dog相同的属性和初始化程序:

class Poodle: Dog {

}

但是,我们也可以提供Poodle自己的初始化程序。我们知道它将始终具有品种“贵宾犬”,所以我们可以做一个新的初始化器,只需要一个name属性。更好的是,我们可以让Poodle初始值设定项直接调用Dog初始值设定项,以便发生所有相同的设置::

class Poodle: Dog {
    init(name: String) {
        super.init(name: name, breed: "Poodle")
    }
}

出于安全原因,Swift总是让您super.init()从子类中进行调用-以防万一父类在创建时会做一些重要的工作。

覆盖方法

子类可以用其自己的实现替换父方法-这个过程称为Overriding。这是一个Dog带有makeNoise()方法的普通类:

class Dog {
    func makeNoise() {
        print("Woof!")
    }
}

如果我们创建一个Poodle继承自Dog的新类,它将继承该makeNoise()方法。因此,这将显示“ Woof!”:

class Poodle: Dog {
}

let poppy = Poodle()
poppy.makeNoise()

方法重写允许我们更改 Poodle类的makeNoise()实现。

Swift要求我们在重载方法时使用override func而不是仅仅使用func–它阻止您无意中重载方法,并且如果您尝试重载父类中不存在的内容,则会收到错误消息:

class Poodle: Dog {
    override func makeNoise() {
        print("Yip!")
    }
}

进行此更改后,poppy.makeNoise()将打印“ Yip!”而不是“ Woof!”。

Final类

尽管类继承非常有用-实际上苹果平台的大部分都需要您使用它-有时您还是想禁止其他开发人员根据您自己的类来构建他们的类。

Swift为此提供了一个关键字final:当您将一个类声明为final时,其他任何类都不能从该类继承。这意味着他们无法覆盖您的方法来更改您的行为–他们需要以编写类的方式使用您的类。

要使类最终定名,只需将final关键字放在其前面,如下所示:

final class Dog {
    var name: String
    var breed: String

    init(name: String, breed: String) {
        self.name = name
        self.breed = breed
    }
}

复制对象

类和结构之间的第三个区别是如何复制它们。复制结构时,原始结构和复制结构都是不同的-更改一个不会更改另一个。复制类时,原始副本和复制副本都指向同一件事,因此更改一个同时也会更改另一个。

例如,这是一个简单的Singer类,具有一个name具有默认值的属性:

class Singer {
    var name = "Taylor Swift"
}

如果创建该类的实例并打印其名称,则将得到“ Taylor Swift”:

var singer = Singer()
print(singer.name)

现在让我们从第一个变量创建第二个变量并更改其名称:

var singerCopy = singer
singerCopy.name = "Justin Bieber"

由于该方法的类的工作,既singer和singerCopy指向内存中的同一个对象,所以当我们打印歌手的名字,我们再次看到“Justin Bieber”:

print(singer.name)

另一方面,如果Singer是一个结构,那么我们将第二次打印“ Taylor Swift”:

struct Singer {
    var name = "Taylor Swift"
}

反初始化器

类和结构之间的第四个区别是,类可以具有反初始化器 -当类的实例被破坏时运行的代码。

为了说明这一点,这是一个Person带有name属性,简单的初始化程序和打印消息的printGreeting()方法的类:

class Person {
    var name = "John Doe"

    init() {
        print("\(name) is alive!")
    }

    func printGreeting() {
        print("Hello, I'm \(name)")
    }
}

我们将Person在循环中创建该类的一些实例,因为每次循环进行时,都会创建一个新人员,然后将其销毁:

for _ in 1...3 {
    let person = Person()
    person.printGreeting()
}

现在是反初始化器。Person实例销毁时将调用此方法:

deinit {
    print("\(name) is no more!")
}

可变性

类和结构之间的最终区别是它们处理常量的方式。如果您具有带有可变属性的常量结构,则该属性不能更改,因为结构本身是常量。

但是,如果您的常量类具有可变属性,则可以更改该属性。因此,类不需要带有mutating更改属性的方法的关键字。只有结构才需要。

这种差异意味着即使将类创建为常量,也可以更改类的任何变量属性–这是完全有效的代码:

class Singer {
    var name = "Taylor Swift"
}

let taylor = Singer()
taylor.name = "Ed Sheeran"
print(taylor.name)

如果要阻止这种情况发生,则需要使该属性不变:

class Singer {
    let name = "Taylor Swift"
}

总结

  • 1.类和结构相似,它们都可以让您使用属性和方法创建自己的类型。
  • 2.一个类可以从另一个类继承,并获得父类的所有属性和方法。谈论类层次结构是很常见的–一个类基于另一个类,而另一个类本身又基于另一个类。
  • 3.您可以使用final关键字标记一个类,这将阻止其他类从该类继承。
  • 4.通过方法覆盖,子类可以使用新的实现替换其父类中的方法。
  • 5.当两个变量指向同一类实例时,它们都指向同一块内存–一个会改变另一个。
  • 6.类可以具有一个反初始化器,该反初始化器是在销毁该类的实例时运行的代码。
  • 7类并不像构造结构那样强烈地强制执行常量–如果将属性声明为变量,则无论如何创建类实例,都可以对其进行更改。

你可能感兴趣的:(Swift基础-类和继承)