ArkTS 开发指南

写给 Java 开发者的鸿蒙应用开发完整手册 —— 从类型系统到声明式 UI,从状态管理到并发模型

ArkTS · HarmonyOS 6.1 / 开发套件 26.0 Java 21 LTS / 25+ ↔ ArkTS 20 个核心主题 80+ 代码对比

🎯01 · 设计哲学对比

ArkTS 是华为为 HarmonyOS 应用开发量身打造的编程语言,基于 TypeScript 扩展而来。要学好 ArkTS,先理解它与 Java 在设计哲学上的根本分歧。

维度 Java ArkTS
语言谱系C++系,OOP 先行者(1995)JS/TS 超集,面向 UI(2023)
类型系统名义类型,编译期 + 运行期结构化类型,编译期强检查
UI 范式命令式(XML/Compose)声明式 + 装饰器驱动
状态驱动手动调用 setState / observe装饰器自动追踪(@State 等)
并发模型线程 + 锁 + Virtual Thread(21+)TaskPool / Worker(Actor 模型)
异步Virtual Thread / CompletableFuturePromise / async-await(语言级)
运行时JVM(字节码)Ark 运行时(方舟引擎,AOT)
编译产物JAR / class / native imageabc(Ark Byte Code)→ 原生
数据建模Record(16+)/ Sealed(17+)struct / interface(结构化)
泛型类型擦除(JDK 5,运行期擦除)编译期保留(TS 泛型)
内存管理JVM GC(分代,ZGC 21+)Ark GC(并发标记)
核心目标"一次编写,到处运行"多设备协同 + 高性能 UI
💡 最大的思维转变

Java 开发者学 ArkTS 面临三重转变:① 从名义类型到结构化类型(鸭子类型)——Java 21 的 record 让"数据类"更轻,但仍是名义类型,ArkTS 的 interface 是结构匹配;② 从命令式 UI 到声明式 UI(写"是什么"而非"怎么做");③ 从线程到 Actor 模型并发(不共享内存,靠消息传递)——注意 Java 21 的 Virtual Thread 是"更轻的线程",仍共享内存;ArkTS 的 TaskPool/Worker 完全不共享。其中声明式 UI + 状态管理装饰器是最核心的新概念。

ArkTS 与 TypeScript 的关系

ArkTS ≠ TypeScript。ArkTS 在 TS 基础上做了加法(装饰器、ArkUI 原生组件、状态管理)和减法(禁用 any、禁用运行时改对象结构、禁用部分高级类型操作)。理解这一点很重要:

⚙️02 · 开发环境

维度JavaArkTS
IDEIntelliJ / Eclipse / VS CodeDevEco Studio(基于 IntelliJ)
构建工具Maven / Gradlehvigor(内置,类 Gradle)
包管理Maven CentralOHPM(OpenHarmony Package Manager)
运行时JVMArk 运行时(方舟编译器 AOT)
模拟器JVM 直接运行Previewer / 模拟器 / 真机
SDKJDKHarmonyOS SDK
调试jdb / IDE 调试器DevEco 内置调试器

项目结构

📂 ArkTS 项目结构
MyApp/
├── AppScope/
│   └── app.json5                  // 全局应用配置
├── entry/                         // 主模块(HAP)
│   └── src/main/
│       ├── ets/                   // ArkTS 源码
│       │   ├── entryability/
│       │   │   └── EntryAbility.ets
│       │   ├── pages/             // 页面
│       │   │   ├── Index.ets
│       │   │   └── Detail.ets
│       │   ├── components/         // 自定义组件
│       │   ├── model/             // 数据模型
│       │   └── utils/             // 工具类
│       └── resources/             // 资源(图片/字符串/布局)
├── oh-package.json5              // 依赖配置(类似 package.json)
└── build-profile.json5           // 构建配置
✅ DevEco Studio 对 Java 开发者友好

DevEco Studio 基于 IntelliJ 平台,快捷键、界面布局、调试体验与 IntelliJ/Android Studio 高度一致。Java 开发者几乎零成本上手 IDE,可以把精力集中在语言差异上。

👋03 · Hello World

从最简单的页面开始,已经能看到 ArkTS 与 Java 的诸多差异——装饰器、声明式 UI、build() 方法。

☕ Java · Android Activity
public class MainActivity
        extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle s) {
        super.onCreate(s);

        TextView tv = new TextView(this);
        tv.setText("Hello, World!");
        tv.setTextSize(50);

        setContentView(tv);
    }
}
📱 ArkTS · 声明式页面
// pages/Index.ets
@Entry
@Component
struct Index {
  @State message: string = 'Hello, World!'

  build() {
    Column() {
      Text(this.message)
        .fontSize(50)
        .fontWeight(FontWeight.Bold)
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }
}

关键差异

💡 struct 不是 C 的 struct

ArkTS 的 struct 借鉴自 Swift,但语义不同——它是 ArkUI 的组件容器,可以包含状态、方法和 build()。它不是 Java 的 class,但也不是 C 的纯数据 struct。把它理解为"带 UI 渲染能力的值类型"。

📦04 · 类型系统

Java 是名义类型(Nominal Typing)——两个类即使结构完全相同也不能互相赋值;ArkTS 继承 TS 的结构化类型(Structural Typing)——只要结构匹配就能赋值(鸭子类型)。

基本类型对比

概念JavaArkTS
整数byte/short/int/longnumber(统一,底层 64 位浮点)
浮点float/doublenumber
布尔booleanboolean
字符串String(引用)string(值,不可变)
空值nullnull + undefined
任意类型Object禁止 any(ArkTS 限制)
联合类型string | number
字面量类型'red' | 'blue'
类型推断var(Java 10+)/ record(16+)默认推断,无需关键字

变量声明

☕ Java
String name = "Alice";
final int age = 18;
var list = new ArrayList<String>();  // Java 10+

// null 赋值
String s = null;
📱 ArkTS
let name: string = 'Alice'
const age: number = 18
let list: Array<string> = []

// null 和 undefined 是不同的
let s: string | null = null
let u: string | undefined = undefined

// 类型推断(无需写类型)
let x = 42      // 推断为 number
let y = 'hi'    // 推断为 string

// 联合类型(Java 没有)
let id: string | number = 123
id = 'abc'      // ✅ 合法
⚠️ let vs const vs var

let:可变变量(类似 Java 局部变量);const:不可变绑定(类似 Java final);var不要使用(函数作用域,有提升问题)。ArkTS 中一律用 letconst

结构化类型(鸭子类型)

📱 ArkTS · 结构化类型
interface Person {
  name: string
  age: number
}

// 不需要 implements Person!
// 只要结构匹配就能赋值
let p: Person = {
  name: 'Alice',
  age: 18
}

// class 也能赋值给 interface(结构匹配即可)
class User {
  name: string = ''
  age: number = 0
}
let u: Person = new User()  // ✅ 结构匹配
⚠️ ArkTS 禁止 any

TypeScript 允许 let x: any = 1,ArkTS 编译报错。所有变量必须有明确类型(或能被推断)。这是 ArkTS 对 TS 做的"减法"——强制类型安全,不允许逃逸类型系统。如果需要"多种类型",用联合类型 string | number

类型断言 vs 强制转换

☕ Java · 强制转换
Object obj = "hello";
String s = (String) obj;  // 运行时 ClassCastException 风险

if (obj instanceof String) {
    String s2 = (String) obj;
}
📱 ArkTS · 类型断言
let obj: Object = 'hello'
let s = obj as string  // 编译期断言,不检查

// 安全方式:typeof / instanceof
if (typeof obj === 'string') {
  let s2 = obj  // 自动收窄为 string
}

// ArkTS 推荐:用接口定义结构
interface Data { value: number }
let d = obj as Data

null 与 undefined 的区别

Java 只有 null;ArkTS 有 null(显式空值)和 undefined(未初始化/未定义)。ArkTS 默认不允许可空类型,必须显式标注。

📱 ArkTS · 可空类型
// ❌ 默认不允许 null
let name: string = null  // 编译错误

// ✅ 显式标注可空
let name: string | null = null

// 空值合并运算符(类似 Optional.orElse)
let display = name ?? 'unknown'

// 可选链(类似 Optional.map)
let len = name?.length  // name 为 null 时返回 undefined,不报错

🔀05 · 控制流

ArkTS 的控制流与 Java 基本一致(if/elseforwhileswitch),但有些细节差异。

条件语句

☕ Java
if (x > 0) { ... }
else if (x == 0) { ... }
else { ... }

// 条件必须是 boolean
if (obj != null) { ... }

// 三元运算符
String s = x > 0 ? "pos" : "neg";
📱 ArkTS
if (x > 0) { ... }
else if (x === 0) { ... }
else { ... }

// 类型守卫:if 内自动收窄类型
if (obj != null) {
  obj.toString()  // 自动推断为非 null
}

// 三元运算符
let s = x > 0 ? 'pos' : 'neg'
⚠️ === vs ==

Java 用 == 比较基本类型、.equals() 比较对象;ArkTS 用 ===(严格相等,不转换类型)和 ==(宽松相等,会转换类型)。ArkTS 中推荐始终用 ===,避免隐式类型转换导致的 bug。

for 循环

☕ Java
// 经典 for
for (int i = 0; i < 10; i++) { ... }

3// 增强 for
for (String s : list) { ... }

// while
while (cond) { ... }
📱 ArkTS
// 经典 for
for (let i = 0; i < 10; i++) { ... }

// for...of(遍历值)
for (const s of list) { ... }

// for...in(遍历键)
for (const key in obj) { ... }

// while
while (cond) { ... }

// forEach
list.forEach((item, index) => {
  Console.info(`${index}: ${item}`)
})

switch

☕ Java 21+ · switch expression
// Java 14+ switch expression(无穿透)
var kind = switch (day) {
    case "SAT", "SUN" -> "weekend";
    default -> "weekday";
};

// Java 21+ pattern matching for switch(类型匹配)
static String format(Object o) {
    return switch (o) {
        case Integer i -> "int: " + i;
        case String s -> "str: " + s;
        case null -> "null";
        default -> "other";
    };
}
📱 ArkTS · 需 break
// ArkTS 仍是传统 switch(需 break),无 switch expression
switch (day) {
  case 'SAT':
  case 'SUN':       // 穿透
    weekend()
    break
  default:
    weekday()
}

// 类型匹配用可辨识联合 + 字面量收窄
type Shape =
  | { kind: 'circle'; r: number }
  | { kind: 'square'; s: number }

function area(x: Shape): number {
  if (x.kind === 'circle') {
    return Math.PI * x.r ** 2  // 自动收窄为 circle
  }
  return x.s ** 2                 // 收窄为 square
}
💡 Java 21+ 的 pattern matching 接近 ArkTS 的可辨识联合

Java 21 的 switch 模式匹配(JEP 441)让 case Integer i -> 成为现实;ArkTS 用可辨识联合 + 字面量字段收窄达到类似效果。但 ArkTS 没有 switch expression——需要靠 if/else 或穷尽性判断保证分支完整。

模板字符串 —— Java 没有的利器

📱 ArkTS
let name = 'Alice'
let age = 18

// 模板字符串(反引号)
let msg = `Name: ${name}, Age: ${age}`

// 多行字符串
let html = `<div>
  <p>${name}</p>
</div>`

// 表达式嵌入
let result = `Total: ${items.reduce((a, b) => a + b, 0)}`

🔧06 · 函数

ArkTS 函数比 Java 灵活得多——支持可选参数、默认值、箭头函数、函数类型。Java 需要函数式接口(@FunctionalInterface)才能传递函数,ArkTS 直接传递。

☕ Java
// 普通方法
public int add(int a, int b) {
    return a + b;
}

// 函数式接口 + Lambda
@FunctionalInterface
interface IntFunc {
    int apply(int x);
}

IntFunc square = x -> x * x;

// 无默认参数值,需重载
public void log(String msg) { log(msg, "INFO"); }
public void log(String msg, String level) { ... }
📱 ArkTS
// 普通函数
function add(a: number, b: number): number {
  return a + b
}

// 箭头函数(Lambda)
const square = (x: number): number => x * x

// 函数类型直接写
type IntFunc = (x: number) => number
let f: IntFunc = (x) => x * x

// 默认参数 + 可选参数(Java 需重载)
function log(msg: string, level: string = 'INFO'): void { ... }
function greet(name: string, title?: string): void { ... }

// 剩余参数(Java 的 int...)
function sum(...nums: number[]): number {
  return nums.reduce((a, b) => a + b, 0)
}

箭头函数 vs 普通函数 —— this 绑定

这是 Java 开发者最容易困惑的点。Java 的 Lambda 自动捕获 this;ArkTS 的普通函数有自己的 this(动态绑定),箭头函数继承外层 this

📱 ArkTS · this 绑定差异
class Counter {
  count: number = 0

  // ❌ 普通函数:this 不指向 Counter
  bad() {
    setTimeout(function() {
      this.count++  // this 是 undefined 或全局对象!
    }, 1000)
  }

  // ✅ 箭头函数:this 继承自 Counter
  good() {
    setTimeout(() => {
      this.count++  // this 指向 Counter 实例 ✅
    }, 1000)
  }
}
⚠️ 回调中始终用箭头函数

在事件回调、异步回调、setTimeout 等场景中,始终用箭头函数而非普通 function,否则 this 会丢失。这是从 Java 过来最容易踩的坑——Java 的 Lambda 没有这个问题。

🏗️07 · 面向对象

ArkTS 支持 class、interface、继承、多态,但细节与 Java 有显著差异。

☕ Java
public class Animal {
    private String name;

    public Animal(String name) {
        this.name = name;
    }

    public String getName() { return name; }
    public void speak() {
        System.out.println(name);
    }
}

class Dog extends Animal {
    public Dog(String name) { super(name); }

    @Override
    public void speak() {
        System.out.println("Woof");
    }
}

Animal a = new Dog("Rex");
a.speak();  // Woof(多态)
📱 ArkTS
class Animal {
  name: string

  // 构造器参数简写(自动赋值)
  constructor(name: string) {
    this.name = name
  }

  speak(): void {
    Console.info(this.name)
  }
}

class Dog extends Animal {
  constructor(name: string) {
    super(name)
  }

  // override 关键字(ArkTS 要求显式标注)
  override speak(): void {
    Console.info('Woof')
  }
}

let a: Animal = new Dog('Rex')
a.speak()  // Woof(多态)

interface —— 结构化而非名义化

☕ Java · 显式 implements
interface Speaker {
    void speak();
}

class Dog implements Speaker {
    @Override
    public void speak() { ... }
}

// 接口不能有字段,只能有方法
// (Java 8+ 可有 default 方法;17+ 可有私有方法)
📱 ArkTS · 隐式实现
interface Speaker {
  speak(): void
}

class Dog {
  // 不需要 implements Speaker!
  // 有 speak() 方法就自动满足
  speak(): void { ... }
}

let s: Speaker = new Dog()  // ✅ 结构匹配

// interface 可含字段(数据结构定义)
interface User {
  name: string
  age: number
}

访问修饰符

JavaArkTS说明
publicpublic(默认)公开
privateprivate类内可见
protectedprotected子类可见
包内可见(默认)ArkTS 无包级可见性
readonlyreadonly只读(类似 final)
staticstatic静态成员
abstractabstract抽象类/方法

构造器参数简写

📱 ArkTS · 构造器简写
// ArkTS 不支持 TS 的 constructor(public x: number) 简写
// 必须显式声明字段 + 赋值

class User {
  name: string
  age: number

  constructor(name: string, age: number) {
    this.name = name
    this.age = age
  }
}

// 或者用对象字面量 + interface 替代 class
interface User { name: string; age: number }
const user: User = { name: 'Alice', age: 18 }
⚠️ ArkTS 禁止运行时修改对象布局

TS/JS 允许 obj.newProp = x 动态添加属性,ArkTS 禁止。所有属性必须在 class/interface 中预先声明delete obj.prop 也不允许。这让 ArkTS 更接近 Java 的静态类型安全,而非 JS 的动态灵活。

🗂️08 · 集合与数组

JavaArkTS说明
ArrayListArray<T> / T[]动态数组
HashMapMap<K, V>键值对
HashSetSet<T>集合
LinkedList用 Array 替代
Collections.sort()arr.sort()排序
Stream APIarr.filter/map/reduce函数式操作
☕ Java · 集合操作
List<String> list = new ArrayList<>();
list.add("a");
list.add("b");
String first = list.get(0);

Map<String, Integer> map = new HashMap<>();
map.put("a", 1);

// Stream
List<String> result = list.stream()
    .filter(s -> s.length() > 0)
    .map(String::toUpperCase)
    .collect(Collectors.toList());
📱 ArkTS · 数组操作
let list: string[] = ['a', 'b']
list.push('c')
let first = list[0]

let map = new Map<string, number>()
map.set('a', 1)
map.get('a')  // 1

// 函数式操作(链式调用)
let result = list
  .filter(s => s.length > 0)
  .map(s => s.toUpperCase())

// reduce
let total = [1, 2, 3].reduce((a, b) => a + b, 0)

ArkTS 数组特有操作

📱 ArkTS
let arr: number[] = [3, 1, 2]

// 添加/删除
arr.push(4)           // 尾部添加
arr.pop()              // 尾部删除
arr.unshift(0)         // 头部添加
arr.shift()             // 头部删除
arr.splice(1, 1)        // 索引1删1个

// 查找
arr.includes(2)         // true
arr.indexOf(2)           // 2
arr.find(x => x > 1)       // 3(第一个满足条件的)

// 变换
arr.sort((a, b) => a - b) // 排序(原地)
arr.reverse()            // 反转(原地)
let sliced = arr.slice(0, 2)  // 截取(返回新数组)

// 展开(类似 Java 的 list.addAll)
let combined = [...arr, 5, 6]

// 解构赋值
let [a, b, ...rest] = [1, 2, 3, 4]
// a=1, b=2, rest=[3,4]

🔄09 · 状态管理装饰器

这是 ArkTS 最核心的特性,也是 Java 开发者最需要转变思维的地方。在 Java/Android 中,你手动调用 setText() / notifyDataSetChanged() 更新 UI;在 ArkTS 中,你修改状态变量,UI 自动刷新

💡 状态驱动 UI

核心理念:UI = f(state)。你只需管理状态数据,UI 框架负责在状态变化时自动重新渲染 build()。不需要手动操作 DOM/View,不需要 findViewById,不需要 setText

六大状态装饰器

装饰器作用范围Java 类比说明
@State组件内部ViewModel + LiveData组件内可变状态,变化触发本组件刷新
@Prop父→子(单向)函数参数父组件传递的只读数据,子组件不能修改
@Link父↔子(双向)双向数据绑定父子组件共享同一数据源,任一方修改都同步
@Provide祖先→后代依赖注入祖先组件提供数据,任意后代可消费
@Consume后代←祖先@Inject消费祖先 @Provide 的数据
@Observedclass 级Observable标记 class 为可观察,配合 @ObjectLink 实现嵌套对象刷新

@State —— 组件内状态

📱 ArkTS · @State 基础用法
@Component
struct Counter {
  @State count: number = 0

  build() {
    Column() {
      Text(`Count: ${this.count}`)
        .fontSize(30)

      Button('+1')
        .onClick(() => {
          this.count++  // 修改 @State → UI 自动刷新!
        })
    }
  }
}
✅ @State 的魔法

this.count++ 之后,不需要任何手动刷新调用——框架自动重新执行 build(),Text 显示更新为新值。这在 Java/Android 中需要 textView.setText(String.valueOf(count)),在 Jetpack Compose 中需要 mutableStateOf。ArkTS 用一个装饰器就搞定了。

@Prop —— 父传子(单向)

📱 ArkTS · @Prop 单向传递
@Component
struct Parent {
  @State name: string = 'Alice'

  build() {
    Column() {
      Button('改名').onClick(() => {
        this.name = 'Bob'  // 父改 → 子也刷新
      })
      Child({ name: this.name })  // 传递给子组件
    }
  }
}

@Component
struct Child {
  @Prop name: string  // 只读,子组件不能修改

  build() {
    Text(`Hello, ${this.name}`)
  }
}

@Link —— 父子双向同步

📱 ArkTS · @Link 双向绑定
@Component
struct Parent {
  @State count: number = 0

  build() {
    Column() {
      Text(`Parent: ${this.count}`)
      Child({ count: this.count })  // 注意:传 $ 引用
    }
  }
}

@Component
struct Child {
  @Link count: number  // 双向绑定,可修改

  build() {
    Column() {
      Text(`Child: ${this.count}`)
      Button('+1').onClick(() => {
        this.count++  // 子改 → 父也刷新!
      })
    }
  }
}

@Provide / @Consume —— 跨层级传递

类似 Java Spring 的依赖注入——祖先组件 @Provide 数据,任意层级的后代组件 @Consume 消费,无需逐层传递。

📱 ArkTS · 跨层级共享
@Component
struct GrandParent {
  @Provide theme: string = 'dark'

  build() {
    Column() {
      Parent()   // 不需要逐层传 theme
    }
  }
}

@Component
struct DeepChild {
  @Consume theme: string  // 直接消费祖先的数据

  build() {
    Text('Theme:').fontColor(this.theme === 'dark' ? '#fff' : '#000')
  }
}

@Observed + @ObjectLink —— 嵌套对象刷新

@State 只能观察第一层属性变化。如果状态是复杂对象(class 实例),需要 @Observed + @ObjectLink 实现深层监听。

📱 ArkTS · 嵌套对象状态
@Observed
class User {
  name: string
  age: number

  constructor(name: string, age: number) {
    this.name = name
    this.age = age
  }
}

@Component
struct UserCard {
  @ObjectLink user: User  // 监听 User 对象属性变化

  build() {
    Column() {
      Text(`${this.user.name}, ${this.user.age}`)
    }
  }
}

@Component
struct Parent {
  @State user: User = new User('Alice', 18)

  build() {
    Column() {
      UserCard({ user: this.user })
      Button('长大一岁').onClick(() => {
        this.user.age++  // UserCard 自动刷新
      })
    }
  }
}
⚠️ @State 的观察限制

@State 能感知赋值this.count = 1)和简单属性修改(this.obj.name = 'x'),但对数组 push/pop 等变异操作的感知依赖 ArkTS 运行时的拦截。替换整个数组最可靠:this.list = [...this.list, newItem]

🎨10 · 声明式 UI(ArkUI)

Java/Android 的 UI 是命令式的——先创建 View,再设置属性,再添加到布局;ArkTS 的 ArkUI 是声明式的——在 build() 中描述 UI 结构,框架负责创建和管理。

内置组件总览

ArkUI 组件Android 对应说明
TextTextView文本
ImageImageView图片
ButtonButton按钮
TextInputEditText输入框
ColumnLinearLayout(vertical)纵向布局
RowLinearLayout(horizontal)横向布局
StackFrameLayout叠层布局
ListRecyclerView列表
GridGridView网格
ScrollScrollView滚动容器
SwiperViewPager轮播
DividerView(divider)分割线

布局示例

☕ Java · 命令式布局
LinearLayout layout = new LinearLayout(this);
layout.setOrientation(VERTICAL);
layout.setGravity(CENTER);

TextView title = new TextView(this);
title.setText("Title");
title.setTextSize(24);

Button btn = new Button(this);
btn.setText("Click");
btn.setOnClickListener(v -> { ... });

layout.addView(title);
layout.addView(btn);
setContentView(layout);
📱 ArkTS · 声明式布局
build() {
  Column() {
    Text('Title')
      .fontSize(24)
      .margin({ bottom: 16 })

    Button('Click')
      .onClick(() => {
        // 点击事件
      })
  }
  .justifyContent(FlexAlign.Center)
  .width('100%')
  .height('100%')
}

列表渲染 —— ForEach

ArkTS 的 ForEach 类似 Android RecyclerView + Adapter,但声明式使用更简洁。

📱 ArkTS · ForEach 列表
@Component
struct UserList {
  @State users: Array<string> = ['Alice', 'Bob', 'Carol']

  build() {
    Column() {
      Text('用户列表').fontSize(20)

      ForEach(this.users, (name: string, index: number) => {
        Text(`${index + 1}. ${name}`)
          .fontSize(16)
          .padding(12)
          .onClick(() => {
            Console.info(`点击了 ${name}`)
          })
      }, (name: string) => name)  // keyGenerator(唯一键)
    }
  }
}
✅ ForEach 的 keyGenerator

第三个参数是键生成器,类似 RecyclerView 的 getItemId。提供唯一 key 可以让框架精准地做 diff——只有变化的项才重新渲染,而不是全部重建。务必提供有意义的 key,否则列表性能可能很差。

条件渲染 —— if/else

📱 ArkTS · 条件渲染
build() {
  Column() {
    if (this.isLoading) {
      Text('加载中...')
    } else if (this.data === null) {
      Text('暂无数据')
    } else {
      Text(this.data)
    }
  }
}

🧱11 · 自定义构建(@Builder)

Java 用方法封装逻辑;ArkTS 用 @Builder 封装UI 片段。它是 ArkTS 独有的概念——把一段 UI 声明提取为可复用的构建函数。

☕ Java · 方法复用 View
private TextView createLabel(String text) {
    TextView tv = new TextView(this);
    tv.setText(text);
    tv.setTextSize(16);
    tv.setPadding(16, 8, 16, 8);
    return tv;
}

// 使用
layout.addView(createLabel("A"));
layout.addView(createLabel("B"));
📱 ArkTS · @Builder 复用 UI
@Builder
createLabel(text: string) {
  Text(text)
    .fontSize(16)
    .padding({ left: 16, right: 16,
              top: 8, bottom: 8 })
}

// 使用
build() {
  Column() {
    this.createLabel('A')
    this.createLabel('B')
  }
}

@BuilderParam —— 占位插槽

类似 Vue 的 slot 或 React 的 children——让父组件向子组件传入自定义 UI 内容。

📱 ArkTS · @BuilderParam 插槽
@Component
struct Card {
  @BuilderParam content: () => void

  build() {
    Column() {
      Text('--- Card Header ---')
      this.content()  // 父组件传入的内容在这里渲染
      Text('--- Card Footer ---')
    }
    .border({ width: 1 })
  }
}

// 使用
build() {
  Card() {
    Text('自定义内容')
    Image('logo.png')
  }
}

💄12 · 样式与扩展(@Styles / @Extend)

ArkTS 用装饰器复用样式,替代 Java 的 XML styles/themes。

☕ Java · XML 样式
<!-- res/values/styles.xml -->
<style name="TitleText">
    <item name="android:textSize">24sp</item>
    <item name="android:textColor">#333</item>
    <item name="android:padding">16dp</item>
</style>

<TextView style="@style/TitleText" />
📱 ArkTS · @Styles
@Styles
function titleText() {
  .fontSize(24)
  .fontColor('#333333')
  .padding(16)
}

// 使用
build() {
  Text('Title').apply(titleText)
}

@Extend —— 扩展原生组件

📱 ArkTS · @Extend 扩展 Text
@Extend(Text)
function highlight(color: string, size: number) {
  .fontColor(color)
  .fontSize(size)
  .fontWeight(FontWeight.Bold)
}

// 使用:Text 专属扩展方法
build() {
  Text('重要').highlight('#ff0000', 18)
}

🧭13 · 页面路由与生命周期

路由配置

📱 ArkTS · 路由配置
// entry/src/main/resources/base/profile/main_pages.json
{
  "src": ["pages/Index", "pages/Detail", "pages/Settings"]
}

页面跳转

☕ Java · Android Intent
Intent intent = new Intent(this, DetailActivity.class);
intent.putExtra("id", 42);
startActivity(intent);

// 返回结果
startActivityForResult(intent, 1001);
📱 ArkTS · Router
import { router } from '@kit.ArkUI'

// 跳转
router.pushUrl({
  url: 'pages/Detail',
  params: { id: 42 }
})

// 获取参数
const params = router.getParams() as Record<string, Object>
const id = params['id'] as number

// 返回
router.back()

组件生命周期

ArkTSAndroid 对应说明
aboutToAppearonCreate组件创建后、build() 前调用(初始化数据)
aboutToDisappearonDestroy组件销毁前调用(清理资源)
onPageShowonResume页面显示(仅 @Entry 有)
onPageHideonPause页面隐藏(仅 @Entry 有)
onBackPressonBackPressed返回键拦截
📱 ArkTS · 生命周期示例
@Entry
@Component
struct DetailPage {
  @State data: string = ''

  // 组件创建后、build 前调用
  aboutToAppear() {
    this.loadData()
  }

  // 组件销毁前
  aboutToDisappear() {
    Console.info('DetailPage destroyed')
  }

  // 页面重新显示(从其他页面返回)
  onPageShow() {
    Console.info('Page shown')
  }

  // 返回键拦截
  onBackPress(): boolean {
    return true  // true = 拦截,不执行默认返回
  }

  build() { ... }
}

14 · 异步编程

Java 用 CompletableFuture / RxJava / 回调地狱;ArkTS 用 Promise + async/await——语言级支持,更简洁。

☕ Java · CompletableFuture
CompletableFuture.supplyAsync(() -> {
    return fetchData();
})
.thenApply(data -> {
    return parse(data);
})
.thenAccept(result -> {
    System.out.println(result);
})
.exceptionally(e -> {
    e.printStackTrace();
    return null;
});
📱 ArkTS · async/await
async function loadData(): Promise<void> {
  try {
    const data = await fetchData()
    const result = parse(data)
    Console.info(result)
  } catch (e) {
    Console.error(`Error: ${e}`)
  }
}

Promise 基础

📱 ArkTS · Promise 创建与使用
// 创建 Promise(类似 CompletableFuture.supplyAsync)
function fetchUser(id: number): Promise<User> {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (id > 0) {
        resolve({ name: 'Alice', age: 18 })
      } else {
        reject(new Error('Invalid id'))
      }
    }, 1000)
  })
}

// 方式1:then/catch(类似 CompletableFuture 链)
fetchUser(1)
  .then(user => Console.info(user.name))
  .catch(err => Console.error(err))

// 方式2:async/await(推荐,更可读)
async function main() {
  try {
    const user = await fetchUser(1)
    Console.info(user.name)
  } catch (e) {
    Console.error(`Failed: ${e}`)
  }
}

并发 Promise(类似 CompletableFuture.allOf)

📱 ArkTS · Promise 并发
async function loadAll() {
  // 并发发起 3 个请求,全部完成后继续
  const [user, posts, friends] = await Promise.all([
    fetchUser(1),
    fetchPosts(1),
    fetchFriends(1)
  ])
  // 三个结果同时可用
}

// 任一完成即返回
const fastest = await Promise.race([
  fetchFromCache(),
  fetchFromNetwork()
])
✅ async/await 是最佳实践

优先用 async/await 而非 .then().catch() 链——代码读起来像同步代码,异常处理用 try/catch,比 CompletableFuture 的链式调用和异常处理更直观。

🚀15 · 并发模型

ArkTS 不支持多线程共享内存。与 Java 的线程+锁不同,ArkTS 用 TaskPool 和 Worker 实现 Actor 模型——不共享内存,靠消息传递通信。

维度JavaArkTS
并发单元Thread / ExecutorService / Virtual Thread(21+)TaskPool / Worker
内存模型共享内存 + 锁不共享内存(隔离)
通信方式共享变量 + synchronized / Lock消息传递(序列化拷贝)
数据竞争有风险(需同步)不可能(隔离的)
轻量并发Virtual Thread(21+)TaskPool(Actor 模型)
类似概念Erlang/Akka Actor
💡 Java 21 Virtual Thread vs ArkTS TaskPool

Java 21 的 Virtual Thread(虚拟线程)让"成千上万个线程"变得轻量,但仍走共享内存 + 锁的模型,线程间可访问同一对象;ArkTS 的 TaskPool/Worker 是隔离的内存模型——数据靠序列化拷贝传递,从根本上杜绝数据竞争。前者是"更省资源的线程",后者是"不同范式的并发"。

TaskPool —— 轻量任务池

📱 ArkTS · TaskPool
import { taskpool } from '@kit.ArkTS'

// 在 TaskPool 中执行的函数(不能访问主线程的变量)
@Concurrent
function heavyCompute(n: number): number {
  let sum = 0
  for (let i = 0; i < n; i++) {
    sum += i
  }
  return sum
}

// 在主线程调用
async function main() {
  const result = await taskpool.execute(heavyCompute, 100000000)
  Console.info(`Result: ${result}`)
}

Worker —— 长期后台任务

📱 ArkTS · Worker
// 主线程
import { worker } from '@kit.ArkTS'

const w = new worker.ThreadWorker('workers/CalcWorker.ets')

// 发送消息给 Worker
w.postMessage({ data: 42 })

// 接收 Worker 的消息
w.onmessage = (e) => {
  Console.info(`Worker result: ${e.data}`)
}

// workers/CalcWorker.ets(Worker 线程)
const w: worker.ThreadWorkerGlobalScope = worker.workerInstance
w.onmessage = (e) => {
  const result = e.data * 2
  w.postMessage(result)
}
⚠️ 不共享内存

Java 线程间可以共享对象引用(sharedState.count++),需要 synchronized 防竞争;ArkTS 的 TaskPool/Worker 之间不能共享对象——所有传递的数据会被序列化拷贝。所以不存在数据竞争,但也不能直接操作同一份数据。

💡 为什么不用线程

移动端 UI 是单线程的(类似 Android 主线程),ArkTS 直接从语言层面禁止共享内存并发——消除了一整类并发 bug(死锁、竞态、可见性)。代价是:不能像 Java 那样用 synchronized 做细粒度共享控制。但这在 UI 开发中是合理取舍。

📚16 · 模块化

☕ Java · import
import java.util.List;
import com.example.User;
import static java.lang.Math.PI;
📱 ArkTS · import/export
// utils/math.ets —— 导出
export function add(a: number, b: number): number {
  return a + b
}
export const PI = 3.14

// pages/Index.ets —— 导入
import { add, PI } from '../utils/math'

// 默认导出(每个文件最多一个)
export default class User { ... }
import User from '../model/User'

// 导入 OHPM 第三方库
import { axios } from '@ohos/axios'
概念JavaArkTS
导入语法import pkg.Class;import { name } from 'path'
导出public 关键字export / export default
包管理Maven CentralOHPM
依赖文件pom.xml / build.gradleoh-package.json5
通配符导入import pkg.*import * as ns from 'path'

🧬17 · 泛型

Java 泛型是类型擦除(运行时 List<String>List<Integer> 是同一个类);ArkTS 泛型在编译期保留类型信息。

☕ Java · 类型擦除泛型
public class Box<T> {
    private T value;
    public Box(T value) { this.value = value; }
    public T get() { return value; }
}

Box<String> box = new Box<>("hi");
String s = box.get();

// 泛型方法
public <T> T first(List<T> list) {
    return list.get(0);
}
📱 ArkTS · 编译期泛型
class Box<T> {
  value: T
  constructor(value: T) {
    this.value = value
  }
  get(): T { return this.value }
}

const box = new Box<string>('hi')
const s = box.get()

// 泛型函数
function first<T>(arr: T[]): T {
  return arr[0]
}

// 泛型约束(extends)
function getLength<T extends Array<any>>(arr: T): number {
  return arr.length
}
⚠️ ArkTS 泛型限制

ArkTS 对泛型的支持比 Java 弱:① 不支持通配符泛型(? extends T / ? super T);② 不支持泛型擦除检查(instanceof T 在运行时不可用);③ 某些高级类型操作(映射类型 Partial<T>、条件类型)在 ArkTS 中受限或禁止

🏷️18 · 装饰器总览

ArkTS 的装饰器系统是它最独特的特性。Java 用注解(@Override@Autowired)标记元数据,由框架在运行时通过反射处理;ArkTS 装饰器在编译期被编译器处理,生成高效代码——无反射开销。

装饰器Java 类比用途
@Entry@MainActivity(概念)标记页面入口组件
@Component标记 struct 为可复用组件
@State@Bindable / LiveData组件内可变状态
@Prop函数参数父→子单向传值
@Link双向绑定父↔子双向同步
@Provide@Provides(Dagger)祖先提供数据
@Consume@Inject(Dagger)后代消费数据
@Observed@Entity + Observable标记 class 可观察
@ObjectLink接收 @Observed 对象
@Builder封装 UI 片段
@BuilderParamUI 插槽占位
@StylesXML style复用样式
@Extend扩展原生组件方法
@Concurrent标记函数可在 TaskPool 执行
@StorageLinkSharedPreferences绑定 AppStorage
@LocalStorageLink绑定 LocalStorage
@Watch监听状态变化回调
@Reusable标记可复用组件(性能优化)
@Animatable标记可动画属性
✅ 装饰器 vs 注解的本质区别

Java 注解是运行时元数据,通过反射读取——有性能开销;ArkTS 装饰器是编译期指令,编译器直接生成对应代码——零反射、零运行时开销。例如 @State 在编译期被替换为"响应式状态管理"的底层实现代码,用户写的只是声明,编译器做了全部重活。

💣19 · Java 开发者常见陷阱

1. this 绑定丢失

Java Lambda 自动捕获 this;ArkTS 普通函数 this 动态绑定。回调用箭头函数

2. === vs ==

始终用 === 严格相等。'1' == 1true(隐式转换),'1' === 1false

3. null 和 undefined 不同

Java 只有 null;ArkTS 有 null(显式空)和 undefined(未初始化)。null == undefined 为 true,但 null === undefined 为 false。

4. 禁止 any

TS 允许 any,ArkTS 禁止。需要多类型用联合类型 string | number

5. 禁止运行时修改对象布局

obj.newProp = x 在 TS/JS 中合法,ArkTS 编译报错。所有属性必须预先声明。

6. number 是浮点

ArkTS 没有独立的整数类型,number 底层是 64 位浮点。0.1 + 0.2 !== 0.3——浮点精度问题始终存在。

7. 数组不是连续内存

Java 数组是连续内存块,ArkTS 数组是哈希表实现(JS 引擎优化),性能特征不同。大量数值计算考虑用 TypedArray

8. 不共享内存并发

不能用 synchronized / volatile。跨线程数据靠序列化拷贝传递。

9. @State 数组变异

this.arr.push(x) 可能不触发刷新——最可靠方式:this.arr = [...this.arr, x]

10. 不支持方法重载

ArkTS 函数不能像 Java 那样同名不同参。用可选参数 title?: string 或默认值 level = 'INFO' 替代。

11. struct 不是 class

ArkUI 组件用 struct,不能继承、不能 new。它有 build() 方法但没有传统构造器。

12. 异步不是多线程

async/await 是单线程异步(事件循环),不创建新线程。真正的并行需要 TaskPool/Worker。

🎓20 · 迁移建议与速查

思维转变清单

  1. 放下命令式 UI:不要找 findViewById / setText。UI 是状态的函数,改状态 → UI 自动更新。
  2. 放下共享内存并发:不要找 synchronized / volatile。用 TaskPool/Worker + 消息传递。
  3. 放下类继承体系:不要建深层继承树。用 interface + 组合 + @Builder 复用 UI。
  4. 放下方法重载:用可选参数 + 默认值替代。
  5. 放下注解处理器:ArkTS 装饰器在编译期处理,无反射开销,也不能自定义装饰器处理逻辑。
  6. 拥抱结构化类型:不需要 implements,结构匹配即可赋值。
  7. 拥抱 async/await:比 CompletableFuture 链更直观,比回调地狱更可读。

概念映射速查表

Java / AndroidArkTS
Activity / Fragment@Entry + @Component struct
TextView / Button / ImageViewText / Button / Image
LinearLayoutColumn / Row
RecyclerView + AdapterList + ForEach
setContentView()build() 方法
findViewById()不需要(声明式直接引用)
setText()修改 @State 变量
setOnClickListener().onClick(() => {})
XML styles@Styles / @Extend
Intent + startActivityrouter.pushUrl()
onCreate / onResume / onPause / onDestroyaboutToAppear / onPageShow / onPageHide / aboutToDisappear
ViewModel + LiveData@State + @Link + @Provide
CompletableFuturePromise + async/await
ExecutorService / Thread / Virtual Thread(21+)TaskPool / Worker
synchronized / Lock不需要(不共享内存)
record(16+)interface / class(数据对象)
sealed(17+)可辨识联合 + 字面量类型
switch expression + pattern matching(21+)switch + if/else 收窄
text block(15+)模板字符串 `...`(可插值)
@Override 注解override 关键字
instanceof + pattern(21+)instanceof / typeof
nullnull + undefined
String(引用类型)string(值类型)
int / long / doublenumber(统一)
方法重载可选参数 + 默认值
finalconst / readonly
Optional<T>T | null + ?? + ?.
Stream APIArray.filter/map/reduce
Maven / Gradlehvigor + OHPM
JVM 字节码Ark Byte Code(方舟 AOT)

推荐学习路径

  1. DevEco Studio 官方教程 —— 跑通第一个 Hello World
  2. ArkTS 基础语法 —— 类型系统、函数、class/interface
  3. ArkUI 声明式 UI —— build()、内置组件、布局
  4. 状态管理 —— @State/@Prop/@Link/@Provide/@Consume
  5. 异步与并发 —— Promise/async-await、TaskPool/Worker
  6. 页面路由与生命周期 —— 多页面应用开发
  7. 实战项目 —— 完成一个列表+详情+网络请求的完整应用
✅ 最终忠告

ArkTS 最大的门槛不是语法——而是声明式 UI + 状态驱动的思维转变。一旦理解了"UI = f(state)",你会发现 ArkTS 比 Android 命令式 UI 简洁得多。不要试图在 ArkTS 里复刻 Android 的 View 操作方式——拥抱声明式,让框架替你管理 UI。