【华为鸿蒙开发技术】面向对象编程基础类与对象的详解
仓颉编程语言是一种面向全场景应用开发的通用编程语言,可以兼顾开发效率和运行性能,并提供良好的编程体验,主要具有如下特点:
语法简明高效:仓颉编程语言提供了一系列简明高效的语法,旨在减少冗余书写、提升开发效率,例如插值字符串、主构造函数、Flow 表达式、match、if-let、while-let 和重导出等语法,让开发者可以用较少编码表达相关逻辑。
多范式编程:仓颉编程语言支持函数式、命令式和面向对象等多范式编程,融合了高阶函数、代数数据类型、模式匹配、泛型等函数式语言的先进特性,还有封装、接口、继承、子类型多态等支持模块化开发的面向对象语言特性,以及值类型、全局函数等简洁高效的命令式语言特性。开发者可以根据开发偏好或应用场景,选用不同的编程范式。
类型安全:仓颉编程语言是静态强类型语言,通过编译时类型检查尽早识别程序错误,降低运行时风险,也便于代码维护。同时,仓颉编译器提供了强大的类型推断能力,可以减少类型标注工作,提高开发效率。
内存安全:仓颉编程语言支持自动内存管理,并在运行时进行数组下标越界检查、溢出检查等,确保运行时内存安全。
高效并发:仓颉编程语言提供了用户态轻量化线程(原生协程),以及简单易用的并发编程机制,保证并发场景的高效开发和运行。
兼容语言生态:仓颉编程语言支持和 C 等主流编程语言的互操作,并采用便捷的声明式编程范式,可实现对其他语言库的高效复用和生态兼容。
领域易扩展:仓颉编程语言提供了基于词法宏的元编程能力,支持在编译时变换代码,此外,还提供了尾随 lambda、属性、操作符重载、部分关键字可省略等特性,开发者可由此深度定制程序的语法和语义,有利于内嵌式领域专用语言(Embedded Domain Specific Languages,EDSL)的构建。
助力 UI 开发:UI 开发是构建端侧应用的重要环节,基于仓颉编程语言的元编程和尾随 lambda 等特性,可以搭建声明式 UI 开发框架,提升 UI 开发效率和体验。
内置库功能丰富:仓颉编程语言提供了功能丰富的内置库,涉及数据结构、常用算法、数学计算、正则匹配、系统交互、文件操作、网络通信、数据库访问、日志打印、解压缩、编解码、加解密和序列化等功能。
类(Class)是面向对象编程(OOP)中的重要概念,允许程序员通过定义类来创建对象并实现继承和多态性。仓颉语言支持使用类来实现面向对象编程。
类的定义
类的定义以关键字 class
开头,后跟类名和一对花括号。类的定义体可以包含成员变量、成员函数、构造函数、静态成员变量和静态成员函数等。
class Rectangle {
let width: Int64
let height: Int64
public init(width: Int64, height: Int64) {
this.width = width
this.height = height
}
public func area() -> Int64 {
width * height
}
}
在上面的例子中,我们定义了一个名为 Rectangle
的类,该类有两个成员变量 width
和 height
,一个构造函数和一个计算面积的成员函数。
类成员变量
类成员变量可以是实例成员变量或静态成员变量。实例成员变量在对象创建时实例化,而静态成员变量在类加载时实例化。
class Rectangle {
let width = 10
static let height = 20
}
静态成员变量可以通过类名直接访问,而实例成员变量需要通过对象来访问。
构造函数
构造函数用于初始化对象。类可以有多个构造函数,这些构造函数可以是普通构造函数或主构造函数。
class Rectangle {
let width: Int64
let height: Int64
public init(width: Int64) {
this.width = width
this.height = width
}
public init(width: Int64, height: Int64) {
this.width = width
this.height = height
}
}
在这个例子中,Rectangle
类有两个构造函数,分别接受不同的参数。
终结器
终结器是在对象被垃圾回收时调用的特殊函数,用于释放资源。终结器的名字固定为 ~init
。
class C {
var p: CString
init(s: String) {
p = unsafe { LibC.mallocCString(s) }
}
~init() {
unsafe { LibC.free(p) }
}
}
类的继承
类可以继承其他类,从而复用父类的属性和方法。使用 class B <: A
的形式表示类 B
继承自类 A
。
open class A {
let a: Int64 = 10
}
class B <: A {
let b: Int64 = 20
}
在上面的例子中,类 B
继承了类 A
,因此 B
可以访问 A
的成员变量和方法。
覆盖和重定义
子类可以覆盖父类的非抽象实例成员函数,覆盖时需要使用 override
关键字。静态函数可以被子类重定义,使用 redef
关键字。
open class A {
public open func f() {
println("I am superclass")
}
}
class B <: A {
public override func f() {
println("I am subclass")
}
}
open class C {
public static func foo() {
println("I am class C")
}
}
class D <: C {
public redef static func foo() {
println("I am class D")
}
}
创建对象
定义类之后,可以通过调用其构造函数来创建对象。
let r = Rectangle(10, 20)
创建对象后,可以通过对象访问实例成员变量和实例成员函数。
类的限制
类支持单继承,即一个类只能继承一个父类。类不能继承自身或同一层次的其他类。
class A <: A {} // 错误,类不能继承自身
class 成员属性
class 的成员属性(property)是 class 成员变量的一种特殊形式,它们通常提供了对 class 内部状态的安全访问方式。成员属性可以定义 getter 和 setter,分别用于读取和修改属性的值。
class 成员属性定义时,使用关键字 var 定义成员变量,并在定义体中使用 get 和 set 关键字定义 getter 和 setter。下例中,Rectangle 定义了一个成员属性 area,并提供了 getter 和 setter。
class Rectangle {
var width: Int64
var height: Int64
var area: Int64 {
get {
width * height
}
set(newArea) {
// Assuming width remains unchanged, calculate new height
height = newArea / width
}
}
public init(width: Int64, height: Int64) {
self.width = width
self.height = height
}
}
上例中,定义了一个成员属性 area,并提供了 getter 和 setter。getter 返回 width 和 height 的乘积,setter 根据传入的新值调整 height 的值。
注意:成员属性的 getter 和 setter 可以选择性地实现。如果只需要只读属性,可以只实现 getter;如果需要读写属性,则需要同时实现 getter 和 setter。
class Rectangle {
var width: Int64
var height: Int64
var area: Int64 {
get {
width * height
}
// No setter, read-only property
}
public init(width: Int64, height: Int64) {
self.width = width
self.height = height
}
}
class 扩展
class 可以通过扩展(extension)添加新的功能。扩展可以添加新的成员变量、成员函数、属性等,但不能修改已有的成员变量和成员函数。使用关键字 extension 来定义扩展。
class Rectangle {
var width: Int64
var height: Int64
public init(width: Int64, height: Int64) {
self.width = width
self.height = height
}
public func area() -> Int64 {
return width * height
}
}
extension Rectangle {
public func perimeter() -> Int64 {
return 2 * (width + height)
}
}
上例中,通过扩展为 Rectangle 添加了一个新的成员函数 perimeter,用于计算矩形的周长。
注意:扩展中不能定义静态成员变量和静态初始化器,只能定义实例成员变量和成员函数。
抽象类和接口
抽象类和接口是定义抽象行为的两个重要概念。抽象类使用 abstract
关键字修饰,不能直接实例化,必须通过子类实现其抽象成员函数。
abstract class Shape {
abstract func area() -> Int64
abstract func perimeter() -> Int64
}
接口使用 interface
关键字定义,接口中的所有成员函数都是抽象的。类可以通过 implements
关键字实现接口。
interface Drawable {
func draw()
}
class Rectangle : Drawable {
var width: Int64
var height: Int64
public init(width: Int64, height: Int64) {
self.width = width
self.height = height
}
public func draw() {
println("Drawing a rectangle")
}
}
上例中,定义了一个接口 Drawable,并实现了 draw 方法的 Rectangle 类。接口中的成员函数在实现类中必须实现。
注意:一个类可以实现多个接口,但只能继承一个类。
总结:
-
类的定义和实例化:使用
class
关键字定义类,构造函数用来初始化类的成员变量。实例化时通过new
关键字创建对象。 -
成员函数:类中可以定义成员函数,用于操作和访问类的成员变量。成员函数可以是实例成员函数或静态成员函数。
-
类的继承:使用
extends
关键字实现类的继承,子类可以继承父类的属性和方法,并可以重载父类的方法。 -
多态:通过继承和方法重载实现多态,允许使用基类的引用来调用子类的重载方法。
-
成员属性:使用
var
定义成员变量,并使用get
和set
关键字定义 getter 和 setter,提供对成员变量的安全访问。 -
类的扩展:使用
extension
关键字扩展类,添加新的成员变量和成员函数,但不能修改已有的成员变量和成员函数。 -
抽象类和接口:使用
abstract
关键字定义抽象类,不能直接实例化;使用interface
关键字定义接口,接口中的所有成员函数都是抽象的。类可以通过implements
关键字实现接口。
这些概念和机制共同构成了面向对象编程(OOP)的基础,帮助开发者设计和实现灵活、可维护的代码。
- 点赞
- 收藏
- 关注作者
评论(0)