ArkTS基础语法 |(3)类和接口

ArkTS基础语法 |(3)类和接口

在学习HarmonyOS开发的核心语言ArkTS时,整理了一份基础语法笔记,方便日后回顾。

一、类的基础定义与实例化

类是ArkTS面向对象编程的核心载体,用于封装数据(字段)和行为(方法)。

类声明会引入一个新类型,并定义其字段、方法和构造函数,核心类成员包含实例字段实例方法构造函数

定义类后,可通过关键字new对象字面量两种方式创建类的实例。

new 适合带构造函数的类,对象字面量适合无自定义构造函数的简单类。

1. 关键字 new 创建实例(带构造函数)
TypeScript 复制代码
// 定义包含构造函数、实例字段、实例方法的Person类
class Person {
  name: string = '';   // 实例字段 显式初始化
  surname: string = '';   // 实例字段 显式初始化
  // 构造函数:初始化实例字段
  constructor (n: string, sn: string) {
    this.name = n;
    this.surname = sn;
  }
  // 实例方法:拼接姓名
  fullName(): string {
    return this.name + ' ' + this.surname;
  }
}
// new关键字创建实例并调用方法
let p = new Person('John', 'Smith');
console.info(p.fullName());   // 输出:John Smith
2. 对象字面量创建实例(无自定义构造函数)
TypeScript 复制代码
// 定义简单的Point类 仅包含实例字段
class Point {
  x: number = 0;
  y: number = 0;
}
// 对象字面量创建实例 直接赋值字段
let p: Point = {x: 42, y: 42};

注意 :对象字面量仅能在类型可推导的上下文中使用,且赋值的字段需与类的字段完全匹配。

二、类的字段

字段是类中声明的变量,用于存储数据,ArkTS中将类的字段分为实例字段静态字段 ,同时要求所有字段必须显式初始化 ,且支持通过getter/setter实现属性的受控访问。

1. 实例字段与静态字段
实例字段
  • 属于类的每个实例,每个实例拥有独立的实例字段集合。

  • 必须通过类的实例访问,不能通过类名直接访问。

  • 声明时需显式初始化,或在构造函数中完成初始化。

静态字段
  • 使用关键字static 声明,属于类本身,所有实例共享同一个静态字段。

  • 必须通过类名访问,不能通过实例访问。

  • 声明时需显式初始化。

TypeScript 复制代码
// 示例:实例字段与静态字段的使用
class Student {
  // 实例字段:每个学生的独立姓名
  name: string = '';
  // 静态字段:所有学生的共同学校(共享值)
  static school: string = 'HarmonyOS大学';
  constructor(n: string) {
    this.name = n;
  }
}
// 创建两个实例
let s1 = new Student('小李');
let s2 = new Student('小何');

// 通过实例访问实例字段
console.log(s1.name);   // 输出:小李
// 通过类名访问静态字段
console.log(Student.school);   // 输出:HarmonyOS大学

// 修改静态字段 所有实例共享修改后的值
Student.school = '鸿蒙大学';
console.log(Student.school);   // 输出:鸿蒙大学
2. 字段初始化规则

ArkTS要求所有字段必须在声明时或构造函数中显式初始化 (与标准TypeScript的strictPropertyInitialization模式一致),未初始化的字段会导致编译错误 ,该规则可减少运行时错误,提升程序执行性能。

3. getter和setter

getter/setter用于对类的属性进行受控访问,可在属性赋值/获取时增加逻辑校验,替代直接的字段访问。

在类中可单独定义getter、单独定义setter,或二者组合定义。

TypeScript 复制代码
// 示例:getter/setter的使用
class Circle {
  private _radius: number = 0;   // 私有字段 仅类内部可访问
  // getter:获取半径 增加非负校验
  get radius(): number {
    return this._radius < 0 ? 0 : this._radius;
  }
  // setter:设置半径 过滤负数
  set radius(r: number) {
    this._radius = r >= 0 ? r : 0;
  }
}
let c = new Circle();
c.radius = -5;   // 赋值负数 被setter过滤
console.log(c.radius);   // 输出:0
c.radius = 10;
console.log(c.radius);   // 输出:10

三、类的方法

方法是类中封装的行为逻辑,ArkTS中将类的方法分为实例方法静态方法 ,二者的访问范围、调用方式存在明显区别。

1. 实例方法
  • 属于类的实例,必须通过类的实例调用。

  • 可访问实例字段静态字段,包括类的私有字段。

  • 是类最常用的方法类型,用于实现实例的具体行为。

TypeScript 复制代码
// 示例:实例方法计算矩形面积
class RectangleSize {
  // 私有实例字段 仅类内部可访问
  private height: number = 0;
  private width: number = 0;
  // 构造函数初始化私有字段
  constructor(height: number, width: number) {
    this.height = height;
    this.width = width;
  }
  // 实例方法:计算面积 可访问私有字段
  calculateArea(): number {
    return this.height * this.width;
  }
}
// 实例化后调用实例方法
let square = new RectangleSize(10, 10);
console.log(square.calculateArea());   // 输出:100
2. 静态方法
  • 使用关键字static 声明,属于类本身 ,必须通过类名调用。

  • 仅能访问静态字段/其他静态方法,无法访问实例字段(因无具体实例)。

  • 用于实现类的公共行为,与实例无关。

TypeScript 复制代码
// 示例:静态方法的定义与调用
class Tool {
  // 静态方法:实现通用的字符串拼接逻辑
  static concatStr(a: string, b: string): string {
    return a + '-' + b;
  }
}
// 通过类名直接调用静态方法
console.info(Tool.concatStr('ArkTS', 'HarmonyOS'));   // 输出:ArkTS-HarmonyOS
3. 方法重载签名

方法重载允许为同一个方法 定义多个不同的签名 (参数类型/个数不同),实现方法的多场景调用,需遵循重载签名在前、实现签名在后的规则,实现签名需兼容所有重载签名的参数类型。

注意 :若两个重载签名的名称和参数列表完全相同,会导致编译错误。

TypeScript 复制代码
// 示例:方法重载签名
class C {
  // 重载签名1:参数为number类型
  foo(x: number): void;
  // 重载签名2:参数为string类型
  foo(x: string): void;
  // 实现签名:兼容number | string类型,编写具体逻辑
  foo(x: number | string): void {
    console.log('参数值:', x);
  }
}
let c = new C();
c.foo(123);     // 匹配重载签名1
c.foo('aa');    // 匹配重载签名2

四、类的继承

ArkTS支持单继承 ,即一个类只能继承一个基类(父类/超类),同时支持实现多个接口

子类(派生类)会继承父类的字段和方法(构造函数除外),并可新增字段/方法,或重写 父类的方法。

1. 继承的语法格式
TypeScript 复制代码
class 子类名 extends 父类名 implements 接口列表 {
  // 子类的字段、方法、构造函数
}
2. 核心特性

(1) 继承内容 :子类继承父类的实例字段、静态字段、实例方法、静态方法,不继承构造函数

(2) 方法重写 :子类可重写父类的方法,重写的方法必须与原方法参数类型一致,返回类型为原类型或其子类型。

(3) 父类访问 :通过关键字super访问父类的方法和构造函数,子类构造函数的第一条语句必须是super()(调用父类构造函数)。

(4) 接口实现 :包含implements子句的类,必须实现接口中所有未定义默认实现的方法。

3. 关键示例
(1)子类继承与super调用
TypeScript 复制代码
// 父类:矩形
class RectangleSize {
  width: number = 0;
  height: number = 0;
  constructor(width: number, height: number) {
    this.width = width;
    this.height = height;
  }
  // 父类方法:计算面积
  calculateArea(): number {
    return this.width * this.height;
  }
}
// 子类:正方形 继承自矩形
class Square extends RectangleSize {
  // 子类构造函数:必须先调用super()
  constructor(side: number) {
    super(side, side);   // 调用父类构造函数
  }
}
// 子类实例化 继承父类方法
let square = new Square(5);
console.log(square.calculateArea());   // 输出:25
(2)方法重写
TypeScript 复制代码
class Animal {
  name: string = '';
  constructor(n: string) {
    this.name = n;
  }
  // 父类方法
  say(): string {
    return '动物的叫声';
  }
}
// 子类:狗 重写父类say方法
class Dog extends Animal {
  constructor(n: string) {
    super(n);
  }
  // 方法重写:参数类型一致\返回类型一致
  say(): string {
    return this.name + ':汪汪汪';
  }
}
let dog = new Dog('旺财');
console.log(dog.say());   // 输出:旺财:汪汪汪

五、构造函数

构造函数用于初始化类的实例状态,是创建实例时自动执行的方法。

1. 基础语法
TypeScript 复制代码
constructor ([参数列表]) {
  // 初始化逻辑,通常为实例字段赋值
}
2. 核心规则

(1) 默认构造函数 :若类未显式定义构造函数,编译器会自动创建空参数的默认构造函数,使用字段类型的默认值初始化实例。

(2) 子类构造函数 :子类必须通过super()显式调用父类的构造函数,且super()必须是子类构造函数体的第一条语句

(3) 显式初始化:构造函数是实例字段初始化的重要位置,未在声明时初始化的字段,必须在构造函数中完成。

(4) 无返回值 :构造函数无需指定返回值类型,也不会返回任何值。

3. 构造函数重载签名

与方法重载类似,构造函数也支持重载,通过多个不同的重载签名指定构造函数的不同调用方式,实现签名需兼容所有重载签名

TypeScript 复制代码
// 示例:构造函数重载
class C {
  // 重载签名1:参数为number类型
  constructor(x: number);
  // 重载签名2:参数为string类型
  constructor(x: string);
  // 实现签名:兼容number | string类型
  constructor(x: number | string) {
    console.log('构造函数参数:', x);
  }
}
// 匹配不同的重载签名创建实例
let c1 = new C(123);     // 重载签名1
let c2 = new C('abc');   // 重载签名2

六、可见性修饰符

ArkTS为类的字段和方法提供了可见性修饰符 ,用于控制类成员的访问范围,实现封装性。 修饰符包括privateprotectedpublic默认可见性为public

1. 公有(public)
  • 最宽松的修饰符,默认所有成员均为public

  • public修饰的成员,在程序任何可访问该类的地方都能访问(类内部、实例、子类)。

2. 私有(private)
  • 最严格的修饰符。

  • private修饰的成员,仅能在声明该成员的类内部访问,类外部、子类均无法访问。

3. 受保护(protected)
  • 介于publicprivate之间。

  • protected修饰的成员,类内部和子类中可访问,类外部无法访问。

4. 完整示例
TypeScript 复制代码
// 父类
class Base {
  public a: string = '';      // 公有
  private b: string = '';     // 私有
  protected c: string = '';   // 受保护
  constructor() {
    this.a = 'public';
    this.b = 'private';
    this.c = 'protected';
  }
  // 类内部可访问所有修饰符的成员
  showBase() {
    console.log(this.a, this.b, this.c);
  }
}
// 子类
class Derived extends Base {
  showDerived() {
    console.log(this.a);   // public可访问
    // console.log(this.b);   // 编译错误,private子类不可访问
    console.log(this.c);   // protected子类可访问
  }
}
// 实例化
let base = new Base();
let derived = new Derived();

// 类外部访问
console.log(base.a);   // public可访问
// console.log(base.b);   // 编译错误 private外部不可访问
// console.log(base.c);   // 编译错误 protected外部不可访问

七、对象字面量

对象字面量是创建类实例的便捷方式,通过 {属性名: 值} 的形式直接初始化实例,同时也可用于初始化泛型Record类型 ,是ArkTS中创建对象的常用语法。

1. 类实例的对象字面量
TypeScript 复制代码
// 定义简单的Point类 仅包含实例字段
class Point {
  x: number = 0;
  y: number = 0;
}
// 对象字面量创建实例 直接赋值字段
let p: Point = {x: 42, y: 42};

核心要求是字段与类完全匹配类型可推导

2. Record类型的对象字面量

泛型Record<K, V>用于将键类型K 映射到值类型V ,常通过对象字面量初始化,其中K仅支持字符串类型数值类型 (不包括BigInt),V可为任意类型。

TypeScript 复制代码
// 示例:Record类型的对象字面量

// 定义Record类型:键为string 值为number
let userAge: Record<string, number> = {
  'John': 25,
  'Mary': 21,
  'Tom': 23
};
// 访问值
console.log(userAge['John']);   // 输出:25
console.log(userAge.Mary);      // 输出:21

// 键为数值类型的Record
let score: Record<number, string> = {
  100: '优秀',
  80: '良好',
  60: '及格'
};
console.log(score[80]);   // 输出:良好

八、抽象类

带有abstract 修饰符的类称为抽象类,抽象类是对一组具体类的通用特性抽象 ,无法直接实例化,主要用于作为父类被子类继承,同时支持定义抽象方法

1. 核心特性

(1)不可实例化 :直接通过new创建抽象类实例会导致编译错误。

(2)可被继承 :抽象类的子类可以是抽象类,也可以是非抽象类,非抽象子类可实例化

(3)可包含普通成员:抽象类中可定义普通的实例字段、静态字段、实例方法、静态方法。

(4)可包含构造函数 :抽象类的构造函数可用于初始化子类的公共字段,子类通过super()调用。

2. 抽象方法

带有abstract 修饰符的方法称为抽象方法,仅能在抽象类中声明

核心特性:

(1)仅声明,无实现:抽象方法只有方法签名,没有方法体。

(2)子类必须实现:抽象类的非抽象子类,必须实现父类中所有的抽象方法。

(3)不可单独存在 :非抽象类中声明抽象方法会导致编译错误。

3. 完整示例
TypeScript 复制代码
// 抽象类:形状
abstract class Shape {
  color: string = '';
  // 抽象类的构造函数
  constructor(c: string) {
    this.color = c;
  }
  // 普通方法:已有实现
  showColor(): void {
    console.log('形状颜色:', this.color);
  }
  // 抽象方法:仅声明 无实现 子类必须重写
  abstract calculateArea(): number;
}
// 非抽象子类:圆形 继承抽象类
class Circle extends Shape {
  radius: number = 0;
  constructor(c: string, r: number) {
    super(c);   // 调用抽象类构造函数
    this.radius = r;
  }
  // 必须实现父类的抽象方法
  calculateArea(): number {
    return Math.PI * this.radius * this.radius;
  }
}
// 实例化子类(抽象类无法实例化)
let circle = new Circle('red', 5);
circle.showColor();   // 输出:形状颜色:red
console.log(circle.calculateArea());   // 输出:78.53981633974483

// let shape = new Shape('blue');   // 编译错误:抽象类无法创建实例

// 编译错误:非抽象类声明抽象方法
// class Test {
//   abstract test(): void;
// }

九、接口

接口通过interface关键字声明,是代码协定的定义方式 ,用于约定类的属性和方法,实现多态特性

任何类只要实现了接口的所有成员,就可被视为该接口的类型。

ArkTS中接口支持继承约定对象结构约定对象方法 等特性。

1. 接口的基础定义

接口通常包含属性声明方法声明,无具体实现,仅定义"规范",实现接口的类必须严格遵循该规范。

TypeScript 复制代码
// 示例:基础接口定义

// 接口1:约定颜色属性
interface Style {
  color: string;   // 属性声明
}
// 接口2:约定方法
interface AreaSize {
  calculateAreaSize(): number;   // 方法声明
  someMethod(): void;            // 方法声明
}
2. 接口的属性声明

接口的属性可以是普通字段gettersetter ,或getter+setter组合。

其中普通字段是getter/setter对的便捷写法,二者完全等价。

TypeScript 复制代码
// 示例:接口属性的两种等价声明

// 方式1:普通字段形式(便捷写法)
interface Style {
  color: string;
}

// 方式2:getter+setter形式
interface Style {
  get color(): string;
  set color(x: string);
}

// 类实现接口的两种方式
class StyledRectangle implements Style {
  // 方式1:直接声明字段
  color: string = '';
}
class StyledCircle implements Style {
  // 方式2:通过getter/setter实现
  private _color: string = '';
  get color(): string { return this._color; }
  set color(x: string) { this._color = x; }
}
3. 接口继承

接口支持多继承 ,即一个接口可以继承多个其他接口,继承后的接口会包含被继承接口的所有成员,并可新增自己的成员。

TypeScript 复制代码
// 示例:接口继承

// 父接口1
interface Style {
  color: string;
}
// 父接口2
interface Size {
  width: number;
  height: number;
}
// 子接口:继承Style和Size 新增border属性
interface StyledSize extends Style, Size {
  border: number;
}
// 实现子接口的类 需实现所有父接口+子接口的成员
class Rectangle implements StyledSize {
  color: string = '';
  width: number = 0;
  height: number = 0;
  border: number = 0;
}
4. 接口约定对象结构与方法

ArkTS中通过接口严格约定对象的结构方法类型,是定义自定义对象类型的核心方式,适用于非类实例的普通对象。

核心规则:

  • 接口内属性之间不加逗号 ,对象内属性之间加逗号
  • 对象的属性/方法必须与接口一一对应,不可多也不可少。
(1)接口定义对象结构
TypeScript 复制代码
// 定义接口:约定User对象的属性名和类型(属性间无逗号)
interface User {
  name: string
  age: number
  isVip: boolean
}

// 基于接口创建对象:属性与接口一一对应(属性间加逗号)
let user1: User = {
  name: '小鸣',
  age: 20,
  isVip: true
};

// 访问对象属性
console.log(user1.name);   // 输出:小鸣
console.log(user1.age);   // 输出:20
(2)接口约定对象方法

对象方法用于描述对象的行为,接口中通过箭头函数约定方法的参数类型和返回值类型,实现对象时需严格遵循该约定。

  • 无参数方法:方法名: () => 返回值类型

  • 无返回值方法:返回值类型为void

  • 带参数方法:方法名: (参数1:类型1, 参数2:类型2) => 返回值类型

TypeScript 复制代码
// 示例:接口约定对象方法

// 定义接口:约定属性和方法
interface User {
  name: string
  // 无参数、无返回值方法
  sayName: () => void
  // 带1个string参数 返回string类型方法
  getAgeDesc: (prefix: string) => string
  // 带2个参数 返回number类型方法
  sum: (a: number, b: number) => number
}

// 基于接口实现对象
let user2: User = {
  name: '小何',
  // 实现无参数方法
  sayName: () => {
    console.log('我的名字是' + user2.name);
  },
  // 实现带参数方法
  getAgeDesc: (prefix: string) => {
    return prefix + '20岁';
  },
  // 实现多参数方法
  sum: (a: number, b: number) => {
    return a + b;
  }
};

// 调用对象方法
user2.sayName();   // 输出:我的名字是小何
let desc = user2.getAgeDesc('年龄:');
console.log(desc);   // 输出:年龄:20岁
console.log(user2.sum(10, 20));   // 输出:30
5. 抽象类与接口的区别

抽象类和接口均无法直接实例化,且都用于实现代码的抽象和复用,但二者在设计目的、语法规则上有本质区别。

在ArkTS中,抽象类和接口的核心区别如下表:

特性 抽象类(abstract class) 接口(interface)
继承/实现规则 类仅能单继承一个抽象类 类可实现多个接口
成员实现 可包含方法的具体实现,也可包含抽象方法 无任何方法实现,仅声明方法/属性
静态成员 可包含静态字段、静态方法、静态代码块 不可包含任何静态成员
构造函数 可定义构造函数,子类通过super()调用 不可定义构造函数
设计目的 类的抽象,捕捉子类的通用特性 行为的抽象,定义代码协定
字段/属性 可声明实例字段并初始化 仅声明属性类型,不可初始化
相关推荐
UnicornDev1 天前
【HarmonyOS 6】底部悬浮导航的迷你栏适配(API23)
华为·harmonyos·arkts·鸿蒙
笔触狂放2 天前
【项目】基于ArkTS的老年人智能应用开发(1)
harmonyos·arkts·鸿蒙
UnicornDev3 天前
【HarmonyOS 6】底部悬浮导航的沉浸光感适配(API23)
华为·harmonyos·arkts·鸿蒙·鸿蒙系统
UnicornDev8 天前
【HarmonyOS 6】设置页面 UI 设计
ui·华为·harmonyos·arkts·鸿蒙
UnicornDev11 天前
【HarmonyOS 6】基于API23的底部悬浮导航
华为·harmonyos·arkts·鸿蒙·鸿蒙系统
积水成渊,蛟龙生焉12 天前
鸿蒙手势处理篇(滑动冲突、基础手势、组合手势)
华为·arkts·鸿蒙·滑动冲突·手势冲突·基础手势·组合手势
纯爱掌门人12 天前
聊聊 HarmonyOS 上的应用内通知授权弹窗
前端·harmonyos·arkts
UnicornDev14 天前
【HarmonyOS 6】练习记录页面 UI 设计
ui·华为·harmonyos·arkts·鸿蒙
哈__15 天前
新手入门harmonyOS开发:手把手教你用ArkTS实现一个天气应用
harmonyos·arkts
积水成渊,蛟龙生焉16 天前
鸿蒙装饰器V2详解
华为·harmonyos·arkts·鸿蒙·ark