惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

量子位
P
Privacy International News Feed
Security Latest
Security Latest
Spread Privacy
Spread Privacy
NISL@THU
NISL@THU
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
The Last Watchdog
The Last Watchdog
S
Schneier on Security
Engineering at Meta
Engineering at Meta
Google Online Security Blog
Google Online Security Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Know Your Adversary
Know Your Adversary
Cyberwarzone
Cyberwarzone
C
Cyber Attacks, Cyber Crime and Cyber Security
G
GRAHAM CLULEY
A
Arctic Wolf
博客园 - 聂微东
I
Intezer
腾讯CDC
罗磊的独立博客
T
Tailwind CSS Blog
WordPress大学
WordPress大学
宝玉的分享
宝玉的分享
L
Lohrmann on Cybersecurity
人人都是产品经理
人人都是产品经理
C
Cybersecurity and Infrastructure Security Agency CISA
博客园 - 【当耐特】
P
Palo Alto Networks Blog
Simon Willison's Weblog
Simon Willison's Weblog
W
WeLiveSecurity
N
News and Events Feed by Topic
SecWiki News
SecWiki News
S
Security Affairs
T
Threat Research - Cisco Blogs
The GitHub Blog
The GitHub Blog
F
Fortinet All Blogs
T
Troy Hunt's Blog
N
News and Events Feed by Topic
P
Proofpoint News Feed
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
酷 壳 – CoolShell
酷 壳 – CoolShell
M
MIT News - Artificial intelligence
I
InfoQ
Hacker News: Ask HN
Hacker News: Ask HN
T
The Blog of Author Tim Ferriss
Schneier on Security
Schneier on Security
Hacker News - Newest:
Hacker News - Newest: "LLM"
Vercel News
Vercel News
博客园 - 三生石上(FineUI控件)
D
Darknet – Hacking Tools, Hacker News & Cyber Security

博客园 - thammer

03 — std::vector 进阶篇 02 — 迭代器基础 01 — std::vector 基础篇 Day 17:Promise 基础 Day 16 - 读懂 TypeScript 声明文件(.d.ts) Day 15 - ArkTS 模块系统 Day 14 - ArkTS 错误处理 Day 13 - ArkTS 类型系统进阶 Day 12 - 泛型与阶段三总结 Day 11 - Interface 与类型契约 Day 10 - 继承与多态 Day 08 - 函数进阶与阶段总结 Day 07 - 函数类型与高阶函数 Day 06 - 函数基础 Day 05 - 数组和元组深入 Day 04 - 循环与迭代 Day 03 - 条件控制 Day 02 - 运算符与表达式 Day 01 - 变量与类型基础 Day 00 - 环境准备 C++虚函数 C++ 多继承 C++成员访问权限以及继承权限 C++ 成员初始化机制总结笔记
Day 09 - Class 基础
thammer · 2026-04-14 · via 博客园 - thammer

目标:掌握ArkTS类的定义、访问修饰符、Getter/Setter、静态成员
预计时间:1.5-2小时
前置知识:Day 01-05 基础语法、Day 06-08 函数


第一部分:类的定义(对标 C++ class/struct)

1.1 为什么需要类

问题引入:假设你要管理一组传感器数据,每个传感器有ID、名称、当前读数。不用类的话怎么写?

// 不用类:数据分散,容易出错
let sensorId: number = 1001;
let sensorName: string = "温度传感器-A1";
let sensorValue: number = 25.5;

let sensor2Id: number = 1002;
let sensor2Name: string = "湿度传感器-B2";
let sensor2Value: number = 60.0;

// 操作数据的函数也要分别处理
function updateSensorValue(value: number): void {
  sensorValue = value; // 只能操作全局变量
}

问题

  • 变量名容易冲突(sensorId vs sensor2Id
  • 数据和操作分离,维护困难
  • 无法创建多个结构相同的对象

解决方案:将数据和行为封装在一起 →


1.2 基本类定义

class Sensor {
  // 属性声明:必须显式声明类型和初始值
  id: number;
  name: string;
  currentValue: number;

  // 构造函数
  constructor(id: number, name: string, initialValue: number) {
    this.id = id;
    this.name = name;
    this.currentValue = initialValue;
  }

  // 成员方法
  updateValue(newValue: number): void {
    this.currentValue = newValue;
  }

  getStatus(): string {
    return `${this.name}: ${this.currentValue}`;
  }
}

// 创建实例
let tempSensor: Sensor = new Sensor(1001, "温度传感器", 25.5);
let humiSensor: Sensor = new Sensor(1002, "湿度传感器", 60.0);

// 调用方法
tempSensor.updateValue(26.0);
console.log(`结果:${tempSensor.getStatus()}`); // "温度传感器: 26"

对比C++

class Sensor {
public:
    int id;
    std::string name;
    double currentValue;
    
    Sensor(int id, const std::string& name, double initialValue)
        : id(id), name(name), currentValue(initialValue) {}
    
    void updateValue(double newValue) {
        currentValue = newValue;
    }
    
    std::string getStatus() const {
        return name + ": " + std::to_string(currentValue);
    }
};

// 创建实例
Sensor tempSensor(1001, "温度传感器", 25.5);
tempSensor.updateValue(26.0);

关键差异

  • C++ 用 ClassName(params) 构造,ArkTS 用 new ClassName(params)
  • C++ 用初始化列表 : id(id), name(name),ArkTS 在构造函数内用 this.id = id

1.3 属性必须有初始值

ArkTS严格要求:类属性必须有初始值,或在构造函数中赋值。

class Device {
  // ✅ 方式1:声明时初始化
  id: number = 0;
  name: string = "";

  // ✅ 方式2:在构造函数中赋值
  serialNumber: string;

  constructor(serial: string) {
    this.serialNumber = serial; // 必须在这里赋值
  }
}

// ❌ 错误:属性没有初始值,也没有在构造函数中赋值
class BadDevice {
  id: number; // 错误!没有初始值
  name: string; // 错误!没有初始值
  // constructor 缺失或没有给属性赋值
}

对比C++

  • C++ 成员可以在构造函数初始化列表中赋值
  • C++ 基本类型不初始化会有垃圾值,但不会编译错误
  • ArkTS 强制要求明确初始化,更安全

第二部分:访问修饰符(对标 C++ public/private/protected)

2.1 public —— 默认就是public

重要区别:ArkTS 类成员默认就是 public,这与 C++ 默认 private 正好相反!

class Device {
  // 这三行等价,都声明为 public
  id: number;
  public name: string;
  public status: string;

  constructor(id: number, name: string) {
    this.id = id;
    this.name = name;
    this.status = "offline";
  }

  // 方法默认也是 public
  turnOn(): void {
    this.status = "online";
  }
}

let dev: Device = new Device(1001, "灯-001");
console.log(`结果:${dev.id}`); // ✅ 可以访问
console.log(`结果:${dev.name}`); // ✅ 可以访问
dev.turnOn(); // ✅ 可以调用

对比C++

class Device {
    // C++ 默认是 private!
    int id;              // private
    std::string name;    // private
    
public:
    // 必须显式声明 public 才能外部访问
    void turnOn() { /* ... */ }
};

Device dev(1001, "灯-001");
// dev.id;     // ❌ 编译错误,id 是 private

记忆口诀:ArkTS 默认"开放",C++ 默认"封闭"。


2.2 private —— 私有成员

class SecureDevice {
  public id: number;
  public name: string;

  // private 成员:只能在类内部访问
  private _password: string;
  private _isLocked: boolean = true;

  constructor(id: number, name: string, password: string) {
    this.id = id;
    this.name = name;
    this._password = password;
  }

  // public 方法可以访问 private 成员
  public unlock(password: string): boolean {
    if (password === this._password) {
      this._isLocked = false;
      return true;
    }
    return false;
  }

  public operate(): string {
    if (this._isLocked) {
      return "设备已锁定,无法操作";
    }
    return "执行操作...";
  }

  // private 方法:内部辅助逻辑
  private _logAccess(): void {
    console.log(`结果:${this.name} 被访问`);
  }
}

let device: SecureDevice = new SecureDevice(1001, "安全设备", "123456");
console.log(`结果:${device.id}`); // ✅ OK
// console.log(device._password);          // ❌ 错误!private
// console.log(device._isLocked);          // ❌ 错误!private
// device._logAccess();                    // ❌ 错误!private

device.unlock("123456");
console.log(`结果:${device.operate()}`); // "执行操作..."

命名惯例:private 成员通常用 _ 前缀(如 _password),便于区分。

对比C++:用法完全相同,只是 ArkTS 需要显式写 private


2.3 protected —— 子类可访问

class BaseDevice {
  public id: number;
  private _secret: string = "secret";

  // protected:类内部和子类可以访问,外部不能
  protected firmwareVersion: string = "1.0.0";

  protected _updateFirmware(version: string): void {
    this.firmwareVersion = version;
  }
}

// 子类(Day 10 会详细讲继承)
class SmartLight extends BaseDevice {
  updateToV2(): void {
    // ✅ 子类可以访问 protected 成员
    this._updateFirmware("2.0.0");
    console.log(`结果:固件更新到 ${this.firmwareVersion}`);
  }
}

let light: SmartLight = new SmartLight();
light.updateToV2(); // ✅ OK
// light._updateFirmware("3.0");  // ❌ 错误!外部不能访问 protected
// light.firmwareVersion;          // ❌ 错误!外部不能访问 protected

预告extends 继承语法将在 Day 10 详细讲解,这里只需理解 protected 的访问范围。


第三部分:属性进阶

3.1 readonly 属性 —— 只读属性

问题引入:设备的ID一旦创建就不应该改变,怎么限制?

class DeviceConfig {
  readonly id: number; // 只读属性
  readonly createdAt: number; // 只读属性
  name: string;

  constructor(id: number, name: string) {
    this.id = id; // ✅ 构造函数中可以赋值
    this.createdAt = Date.now(); // ✅ 构造函数中可以赋值
    this.name = name;
  }

  updateName(newName: string): void {
    this.name = newName; // ✅ OK
    // this.id = 999;                // ❌ 错误!readonly 属性不能修改
  }
}

let config: DeviceConfig = new DeviceConfig(1001, "配置-001");
console.log(`结果:ID=${config.id}, 创建时间=${config.createdAt}`);
// config.id = 1002;  // ❌ 编译错误

对比C++

class DeviceConfig {
public:
    const int id;           // const 成员 = readonly
    const long long createdAt;
    std::string name;
    
    DeviceConfig(int id, const std::string& name)
        : id(id), createdAt(std::time(nullptr)), name(name) {}
};

共同点:都只能在构造函数中初始化,之后不能修改。


第四部分:Getter / Setter(对标 C++ 手写getter/setter,但语法更优雅)

4.1 基本语法

C++ 风格:手动写 get/set 方法。

class CppStyleDevice {
  private _brightness: number = 0;

  getBrightness(): number {
    return this._brightness;
  }

  setBrightness(value: number): void {
    this._brightness = value;
  }
}

let dev: CppStyleDevice = new CppStyleDevice();
dev.setBrightness(80);
console.log(`结果:${dev.getBrightness()}`);

ArkTS 风格:使用 get / set 关键字,像访问属性一样调用。

class DimmableLight {
  private _brightness: number = 0;

  // getter:像属性一样读取
  get brightness(): number {
    return this._brightness;
  }

  // setter:像属性一样赋值
  set brightness(value: number) {
    this._brightness = value;
  }
}

let light: DimmableLight = new DimmableLight();
light.brightness = 80; // 调用 setter
console.log(`结果:${light.brightness}`); // 调用 getter,输出 80

优势:使用方代码更简洁,像直接访问属性,但内部可以添加逻辑。


4.2 数据验证 —— 在setter中添加验证

class ValidatedLight {
  private _brightness: number = 0;
  private _isOn: boolean = false;

  get brightness(): number {
    return this._brightness;
  }

  // setter 中加入验证逻辑
  set brightness(value: number) {
    if (value < 0 || value > 100) {
      console.log("错误:亮度必须在0-100之间");
      return;
    }
    this._brightness = value;
    this._isOn = value > 0;
  }

  get isOn(): boolean {
    return this._isOn;
  }
}

let light: ValidatedLight = new ValidatedLight();
light.brightness = 80; // ✅ 正常设置
console.log(`结果:亮度=${light.brightness}, 状态=${light.isOn}`);

light.brightness = 150; // ❌ 输出错误信息,不会设置
console.log(`结果:亮度=${light.brightness}`); // 仍然是 80

4.3 计算属性 —— 在getter中返回计算值

class PowerDevice {
  private _brightness: number = 0;
  private readonly _maxPower: number = 50; // 最大功率50W

  get brightness(): number {
    return this._brightness;
  }

  set brightness(value: number) {
    this._brightness = Math.max(0, Math.min(100, value));
  }

  // 计算属性:根据亮度计算功耗
  get powerConsumption(): number {
    return (this._brightness / 100) * this._maxPower;
  }

  // 计算属性:根据亮度估算寿命剩余百分比
  get estimatedLifeRemaining(): number {
    // 假设满亮度寿命10000小时,每降低10%亮度寿命增加20%
    let factor: number = 1 + (100 - this._brightness) / 10 * 0.2;
    return 100 / factor;
  }
}

let device: PowerDevice = new PowerDevice();
device.brightness = 80;
console.log(`结果:功耗=${device.powerConsumption}W`); // 40W
console.log(`结果:寿命剩余=${device.estimatedLifeRemaining}%`); // 计算值

4.4 私有属性 + 公开访问器模式

这是封装的最佳实践:

class TemperatureSensor {
  private _celsius: number = 0;

  // 摄氏度读写
  get celsius(): number {
    return this._celsius;
  }

  set celsius(value: number) {
    if (value < -273.15) {
      console.log("错误:温度不能低于绝对零度");
      return;
    }
    this._celsius = value;
  }

  // 华氏度只读(计算属性)
  get fahrenheit(): number {
    return this._celsius * 9 / 5 + 32;
  }

  // 开尔文只读(计算属性)
  get kelvin(): number {
    return this._celsius + 273.15;
  }
}

let sensor: TemperatureSensor = new TemperatureSensor();
sensor.celsius = 25;
console.log(`结果:${sensor.celsius}°C = ${sensor.fahrenheit}°F = ${sensor.kelvin}K`);
// sensor.fahrenheit = 100;  // ❌ 错误!没有 setter

4.5 Getter/Setter 的局限性与最佳实践

局限性 1:属性与访问器不能同名

ArkTS 限制:类的属性(无论访问修饰符)和 getter/setter 不能使用相同的标识符名。

// ❌ 错误:Duplicate identifier 'port'
class Device {
  private port: number = 25; // 属性叫 port

  get port(): number {
    ...
  } // ❌ 重名!编译错误

  set port(value: number) {
    ...
  } // ❌ 重名!
}

// ✅ 正确:属性使用下划线前缀
class Device {
  private _port: number = 25; // 属性加下划线

  get port(): number { // getter 无下划线
    return this._port;
  }

  set port(value: number) { // setter 无下划线
    this._port = value;
  }
}

局限性 2:Setter 禁止返回类型注解

class Light {
  private _brightness: number = 0;

  // ❌ 错误:ArkTS 不允许写 :void
  set brightness(value: number): void {
    this._brightness = value;
  }

  // ✅ 正确:必须省略返回类型
  set brightness(value: number) {
    this._brightness = value;
  }
}

局限性 3:Setter 无法返回值

Setter 不能返回任何值,调用方无法直接知道设置是否成功:

class ValidatedLight {
  private _brightness: number = 0;

  set brightness(value: number) {
    if (value < 0 || value > 100) {
      console.log("错误:亮度超出范围");
      return; // 只能直接返回,不能返回 false
    }
    this._brightness = value;
  }
}

let light = new ValidatedLight();
light.brightness = 150; // 设置失败,但调用方无法知道

解决方案:如果需要知道操作结果,使用普通方法代替 setter:

class BetterLight {
  private _brightness: number = 0;

  // 用方法代替 setter,可以返回 boolean
  setBrightness(value: number): boolean {
    if (value < 0 || value > 100) {
      return false; // 返回失败
    }
    this._brightness = value;
    return true; // 返回成功
  }

  get brightness(): number {
    return this._brightness;
  }
}

let light = new BetterLight();
let ok = light.setBrightness(150);
if (!ok) {
  console.log("设置失败");
}

最佳实践建议

场景 推荐方案
简单属性读写,无需验证 直接暴露 public 属性
需要验证/计算,但不需要返回结果 使用 getter/setter
需要知道操作是否成功 使用普通方法,返回 boolean
只读计算属性 只提供 getter,不提供 setter

第五部分:Static 成员(对标 C++ static)

5.1 静态属性 —— 类级别共享数据

问题引入:如何统计创建了多少个设备实例?

class DeviceManager {
  // 静态属性:所有实例共享同一个变量
  static instanceCount: number = 0;
  static readonly MAX_DEVICES: number = 100;

  // 实例属性:每个实例独立
  id: number;
  name: string;

  constructor(name: string) {
    if (DeviceManager.instanceCount >= DeviceManager.MAX_DEVICES) {
      throw new Error("设备数量已达上限");
    }
    this.id = ++DeviceManager.instanceCount;
    this.name = name;
  }
}

let d1: DeviceManager = new DeviceManager("设备-A");
let d2: DeviceManager = new DeviceManager("设备-B");
let d3: DeviceManager = new DeviceManager("设备-C");

console.log(`结果:实例1 ID=${d1.id}`); // 1
console.log(`结果:实例2 ID=${d2.id}`); // 2
console.log(`结果:实例3 ID=${d3.id}`); // 3
console.log(`结果:总实例数=${DeviceManager.instanceCount}`); // 3
console.log(`结果:上限=${DeviceManager.MAX_DEVICES}`); // 100

对比C++

class DeviceManager {
public:
    static int instanceCount;
    static const int MAX_DEVICES = 100;
    
    DeviceManager(const std::string& name) {
        id = ++instanceCount;
        this->name = name;
    }
    
    int id;
    std::string name;
};

// C++ 必须在类外初始化静态成员
int DeviceManager::instanceCount = 0;

重要注意:静态属性如果不初始化,值为 undefined,不是默认值!

class Test {
  static num: number; // 未初始化,值是 undefined,不是 0!
  static str: string; // 未初始化,值是 undefined,不是 ""!
  static flag: boolean; // 未初始化,值是 undefined,不是 false!
}

console.log(Test.num); // undefined
console.log(Test.str); // undefined
console.log(Test.flag); // undefined

建议:静态属性始终显式初始化,避免意外。


5.2 静态方法 —— 通过类名调用

class MathUtils {
  // 静态方法:不依赖实例状态
  static clamp(value: number, min: number, max: number): number {
    return Math.max(min, Math.min(max, value));
  }

  static degToRad(degrees: number): number {
    return degrees * Math.PI / 180;
  }

  static radToDeg(radians: number): number {
    return radians * 180 / Math.PI;
  }
}

// 直接通过类名调用,不需要创建实例
let clamped: number = MathUtils.clamp(150, 0, 100);
console.log(`结果:限制在0-100之间:${clamped}`); // 100

let rad: number = MathUtils.degToRad(180);
console.log(`结果:180度 = ${rad}弧度`); // 3.14159...

5.3 实用场景 —— 计数器、工厂方法

class DeviceFactory {
  private static _serialCounter: number = 0;

  // 工厂方法:创建带自动序列号的设备
  static createDevice(name: string): DeviceInfo {
    DeviceFactory._serialCounter++;
    return new DeviceInfo(
      DeviceFactory._serialCounter,
      `${name}-${DeviceFactory._serialCounter}`
    );
  }

  static getTotalCreated(): number {
    return DeviceFactory._serialCounter;
  }
}

class DeviceInfo {
  constructor(
    public id: number,
    public name: string
  ) {
  }
}

// 使用工厂方法创建设备
let dev1: DeviceInfo = DeviceFactory.createDevice("传感器");
let dev2: DeviceInfo = DeviceFactory.createDevice("传感器");
let dev3: DeviceInfo = DeviceFactory.createDevice("执行器");

console.log(`结果:${dev1.name}`); // "传感器-1"
console.log(`结果:${dev2.name}`); // "传感器-2"
console.log(`结果:${dev3.name}`); // "执行器-3"
console.log(`结果:总计创建=${DeviceFactory.getTotalCreated()}`); // 3

第六部分:小结与练习

6.1 知识点对比总结表(ArkTS vs C++)

概念 C++ ArkTS 关键差异
类定义 class class 相同
构造函数 ClassName(params) constructor(params) 关键字不同
构造函数重载 ✅ 支持 ❌ 不支持 ArkTS 只能用默认参数模拟
属性初始化 初始化列表 构造函数内 this.x = x 语法不同
默认访问修饰符 private public 重要区别
public public: public(可省略) ArkTS默认就是public
private private: private 用法相同,但ArkTS一对一声明
protected protected: protected 用法相同
readonly/const const成员 readonly 关键字不同
参数属性简写 ❌ ArkTS不支持 TypeScript支持,ArkTS禁止
getter/setter 手动方法 get/set关键字 ArkTS语法更优雅但有局限
setter返回类型 任意 ❌ 禁止写返回类型 ArkTS特殊限制
属性与访问器重名 ✅ 允许 ❌ 禁止 ArkTS限制:Duplicate identifier
静态成员 static static ArkTS可在类内初始化
静态属性默认值 自动初始化 undefined ArkTS不初始化则为undefined

6.2 练习题

练习1:选择题

  1. ArkTS类成员默认的访问修饰符是?

    • A. private
    • B. public
    • C. protected
    • D. 没有默认值
  2. 以下哪个是ArkTS合法的readonly属性用法?

    • A. readonly x: number = 0; 声明时初始化
    • B. 在构造函数中赋值
    • C. 以上都是
    • D. 以上都不是
  3. ArkTS枚举的限制是?

    • A. 不能用于switch语句
    • B. 不能同时包含数字和字符串成员
    • C. 必须显式指定所有值
    • D. 最多只能有10个成员
练习1答案

答案:1.B 2.C 3.B

题号 答案 解析
1 B ArkTS 类成员默认就是 public,与 C++ 默认 private 相反
2 C readonly 属性可以在声明时初始化,也可以在构造函数中赋值,之后不能修改
3 B ArkTS 枚举禁止混合类型(不能同时有数字和字符串成员)

练习2:代码补全

补全以下类定义,实现一个带验证的邮箱配置类:

class EmailConfig {
  readonly id: number;
  address: string; // public 属性
  // 补全:smtpServer 是 private,字符串类型
  ______
  ______: ______;
  // 补全:_port 是 private,number类型,默认25(注意:属性名用_port,避免与getter/setter重名)
  ______
  ______: ______ = ______;

  constructor(
    id: number,
    address: string,
    server: string
  ) {
    this.id = id;
    this.address = address;
    this.smtpServer = server;
  }

  // 补全:port的getter(注意:getter名叫port,属性名叫_port)
  get ______(): ______ {
    return this._port;
  }

  // 补全:port的setter,验证范围1-65535
  set ______(value: ______) {
    if (value < 1 || value > 65535) {
      console.log("端口范围错误");
      return;
    }
    this._port = value;
  }
}
练习2答案
class EmailConfig {
  readonly id: number;
  address: string;
  private smtpServer: string;
  private _port: number = 25;

  constructor(
    id: number,
    address: string,
    server: string
  ) {
    this.id = id;
    this.address = address;
    this.smtpServer = server;
  }

  get port(): number {
    return this._port;
  }

  set port(value: number) {
    if (value < 1 || value > 65535) {
      console.log("端口范围错误");
      return;
    }
    this._port = value;
  }
}

练习3:编程题 - 实现一个计数器类

要求:

  1. 类名 Counter
  2. 静态属性 totalCounters 记录创建的实例总数
  3. 实例属性 id(readonly)、namecount
  4. 方法 increment() 增加count
  5. 方法 decrement() 减少count(不能小于0)
  6. 方法 reset() 重置count为0
  7. getter value 返回当前count
练习3答案
class Counter {
  static totalCounters: number = 0;
  readonly id: number;
  name: string;
  count: number = 0;

  constructor(id: number, name: string, count: number = 0) {
    Counter.totalCounters++;
    this.id = id;
    this.name = name;
    this.count = count;
  }

  increment(): void {
    this.count++;
  }

  decrement(): void {
    if (this.count > 0) {
      this.count--;
    }
  }

  reset(): void {
    this.count = 0;
  }

  get value(): number {
    return this.count;
  }
}

练习5:编程题 - 温度转换类

实现 Temperature 类:

  1. private属性 _celsius: number
  2. getter/setter celsius
  3. getter fahrenheit(只读,计算属性)
  4. getter kelvin(只读,计算属性)
  5. setter验证:celsius不能低于-273.15
练习5答案
class Temperature {
  private _celsius: number = 0;

  constructor(c: number) {
    if (c < -273.15) {
      console.log("温度不能低于绝对零度,初始化为0");
      this._celsius = 0;
      return;
    }
    this._celsius = c;
  }

  get celsius(): number {
    return this._celsius;
  }

  set celsius(c: number) {
    if (c < -273.15) {
      console.log("温度不能低于绝对零度");
      return;
    }
    this._celsius = c;
  }

  get fahrenheit(): number {
    return this._celsius * 9 / 5 + 32;
  }

  get kelvin(): number {
    return this._celsius + 273.15;
  }
}

练习6:编程题 - 单例模式(静态方法应用)

实现 ConfigManager 类:

  1. private static属性 _instance: ConfigManager | null = null
  2. public static方法 getInstance(): ConfigManager,返回唯一实例
  3. 实例属性 settings: Map<string, string>
  4. 实例方法 set(key: string, value: string): void
  5. 实例方法 get(key: string): string | undefined
练习6答案
class ConfigManager {
  private static _instance: ConfigManager | null = null;
  private settings: Map<string, string>;

  private constructor() {
    this.settings = new Map<string, string>();
  }

  static getInstance(): ConfigManager {
    if (ConfigManager._instance === null) {
      ConfigManager._instance = new ConfigManager();
    }
    return ConfigManager._instance;
  }

  set(key: string, value: string): void {
    this.settings.set(key, value);
  }

  get(key: string): string | undefined {
    return this.settings.get(key);
  }
}

练习7:编程题 - 带权限检查的设备类

实现 SecureDevice 类:

  1. readonly属性 deviceId: number
  2. private属性 _accessCode: string_isAuthorized: boolean = false
  3. 构造函数接收 deviceId 和 accessCode
  4. 方法 authorize(code: string): boolean,验证code是否正确
  5. 方法 operate(): string,只有授权后才能操作
  6. protected属性 _firmwareVersion: string = "1.0.0"
  7. protected方法 _updateFirmware(version: string): void
练习7答案
class SecureDevice {
  readonly deviceId: number;
  protected _firmwareVersion: string = "1.0.0";
  private _accessCode: string;
  private _isAuthorized: boolean = false;

  constructor(deviceId: number, accessCode: string) {
    this.deviceId = deviceId;
    this._accessCode = accessCode;
  }

  authorize(code: string): boolean {
    this._isAuthorized = (code === this._accessCode);
    return this._isAuthorized;
  }

  operate(): string {
    if (!this._isAuthorized) {
      return "鉴权失败,禁止操作";
    }
    return `设备 ${this.deviceId} 操作成功`;
  }

  protected _updateFirmware(version: string): void {
    if (version !== this._firmwareVersion) {
      this._firmwareVersion = version;
    }
  }
}

练习8:综合题 - 设备管理器

结合所学知识,实现一个简单的设备管理系统:

// 1. 定义设备类型枚举(字符串枚举)
enum DeviceType {
SENSOR = "sensor",
ACTUATOR = "actuator",
CONTROLLER = "controller"
}

// 2. 实现 Device 基类
//    - readonly id, name
//    - protected type: DeviceType
//    - private _isActive: boolean = false
//    - getter/setter active(setter中记录日志)
//    - 抽象方法 activate()/deactivate()(用空方法模拟)

// 3. 实现 DeviceManager 类
//    - static属性 devices: Device[] = []
//    - static方法 register(device: Device): void
//    - static方法 findById(id: number): Device | undefined
//    - static方法 getActiveCount(): number
//    - static方法 listAll(): string[]
练习8答案
enum DeviceType {
SENSOR = "sensor",
ACTUATOR = "actuator",
CONTROLLER = "controller"
}

class Device {
  readonly id: number;
  readonly name: string;
  protected type: DeviceType;
  private _isActive: boolean = false;

  constructor(id: number, name: string, type: DeviceType) {
    this.id = id;
    this.name = name;
    this.type = type;
  }

  get active(): boolean {
    return this._isActive;
  }

  set active(value: boolean) {
    console.log(`设备 ${this.id} 状态变为: ${value ? "激活" : "未激活"}`);
    this._isActive = value;
  }

  activate(): void {
    console.log(`设备 ${this.id} 正在激活...`);
    this.active = true;
  }

  deactivate(): void {
    console.log(`设备 ${this.id} 正在关闭...`);
    this.active = false;
  }
}

class DeviceManager {
  static devices: Device[] = [];

  static register(device: Device): void {
    if (DeviceManager.findById(device.id) === undefined) {
      DeviceManager.devices.push(device);
    }
  }

  static findById(id: number): Device | undefined {
    for (let i = 0; i < DeviceManager.devices.length; i++) {
      if (DeviceManager.devices[i].id === id) {
        return DeviceManager.devices[i];
      }
    }
    return undefined;
  }

  static getActiveCount(): number {
    let count = 0;
    for (let i = 0; i < DeviceManager.devices.length; i++) {
      if (DeviceManager.devices[i].active) {
        count++;
      }
    }
    return count;
  }

  static listAll(): string[] {
    let list: string[] = [];
    for (let i = 0; i < DeviceManager.devices.length; i++) {
      let d = DeviceManager.devices[i];
      list.push(`${d.id}: ${d.name} - ${d.active ? "激活" : "未激活"}`);
    }
    return list;
  }
}

附录:ArkTS Class 速查表

// 基础类定义
class MyClass {
  // 属性必须有初始值或在构造函数中赋值
  publicProp: number = 0;
  private _privateProp: string = "";
  protected protectedProp: boolean = false;
  readonly readOnlyProp: number;

  constructor(initialValue: number) {
    this.readOnlyProp = initialValue;
  }

  // 方法
  publicMethod(): void {
  }

  private _privateMethod(): void {
  }

  protected protectedMethod(): void {
  }
}

// 注意:ArkTS 不支持参数属性简写!
// 以下写法在 TypeScript 中合法,但在 ArkTS 中会报错:
// class ShortClass {
//     constructor(
//         public id: number,      // ❌ ArkTS 错误:arkts-no-ctor-prop-decls
//         private _secret: string,
//         readonly createdAt: number
//     ) {}
// }

// ✅ ArkTS 正确写法:先声明属性,再赋值
class ShortClass {
  id: number;
  private _secret: string;
  readonly createdAt: number;

  constructor(id: number, secret: string, createdAt: number) {
    this.id = id;
    this._secret = secret;
    this.createdAt = createdAt;
  }
}

// Getter / Setter
// 注意:ArkTS 中属性与 getter/setter 不能同名!
// 属性用 _前缀,getter/setter 用无前缀名
class WithAccessor {
  private _value: number = 0; // 属性名:_value

  get value(): number { // getter 名:value(不能叫 _value)
    return this._value;
  }

  set value(v: number) { // setter 名:value(不能叫 _value)
    this._value = v;
  }
}

// 静态成员
class StaticDemo {
  static count: number = 0;
  static readonly MAX: number = 100;

  static getCount(): number {
    return StaticDemo.count;
  }
}