版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第1章建立鸿蒙程序开发环境工欲善其事必先利其器。为了开发鸿蒙智能终端程序,需要首先建立鸿蒙智能终端程序开发环境。本章对智能终端系统进行简单介绍后,详细介绍如何建立鸿蒙智能终端程序开发环境,并开发和运行测试第一个鸿蒙智能终端成以验证开发环境的完整性。目录1.1鸿蒙智能终端系统及其应用开发环境1.2建立鸿蒙智能终端系统程序开发环境1.3鸿蒙应用程序工程结构1.4开发一个具有交互能力的程序1.5练习:建立鸿蒙智能终端程序开发环境1.1鸿蒙智能终端系统及其应用开发环境智能终端呈现多种不同的形式,常见的智能终端形式包括:智能手机、智能平板、智能电视、智能手环、智慧屏等,这些不同形式的智能终端都是通过智能操作系统驱动的。目前,驱动智能终端工作的智能操作系统主要有三大类,它们是iOS操作系统、Android操作系统、鸿蒙操作系统。通过鸿蒙操作系统驱动的智能终端称为鸿蒙智能终端系统;类似的,通过iOS操作系统驱动的智能终端称为iOS智能终端系统;通过Android操作系统驱动的智能终端称为Android智能终端系统。为了给智能终端系统开发应用程序,智能终端系统为开发者提供了相应的应用开发环境,例如,针对Android智能终端系统,可以使用AndroidStudio开发环境;针对iOS智能终端系统,可以使用Xcode开发环境;针对鸿蒙智能终端系统,则可以使用DevEcoStudio开发环境。本书介绍如何使用DevEcoStudio开发环境为鸿蒙智能终端开发应用程序。1.2建立鸿蒙智能终端系统程序开发环境开发者可以使用DevEcoStudio开发环境为鸿蒙智能终端系统开发应用程序。使用DevEcoStudio工具,可以基于鸿蒙操作系统为鸿蒙智能手机系统、鸿蒙智能电视系统、鸿蒙智能手环系统、鸿蒙智能平板系统等开发应用程序。1.2.1下载及安装DevEcoStudio在浏览器搜索引擎中输入“鸿蒙开发者官网”,点击进入“华为开发者联盟-HarmonyOS开发者官网”。1.2.2开发第一个鸿蒙智能终端程序在桌面上双击“DevEcoStudio”启动DevEcoStudio开发环境,启动后的开发界面。1.2.3运行鸿蒙应用程序新建的名称为Ch0101的鸿蒙程序工程可以直接运行在鸿蒙智能终端上。为了便利和简化鸿蒙应用程序的运行、测试和验证,DevEcoStudio提供了专门用于测试验证鸿蒙应用程序的模拟器。点击DevEcoStudio工具栏上的三角形按钮,即可运行当前的程序工程:1.2.4修改DevEcoStudio的界面风格可以根据自己对界面风格的喜好修改DevEcoStudio的风格。为此,在DevEcoStudio中,选择菜单File->Settings:1.3鸿蒙应用程序工程结构为了便于管理程序开发过程中的文件,企业级集成开发环境(IntegratedDevelopmentEnvironment,简称IDE)都基于工程的方法来管理程序涉及的所有文件。本节在对DevEcoStudio界面进行简单介绍的基础上,对鸿蒙程序工程的结构进行介绍。1.3.1DevEcoStudio界面组成熟悉IntelliJIDEA开发环境的读者能够看出DevEcoStudio开发环境就是基于IntelliJIDEA开发的,因此,从外观和功能上,DevEcoStudio开发环境与IntelliJIDEA非常类似。从界面组成上,DecEcoStudio由五大部分组成:1.3.2应用程序工程结构鸿蒙应用程序工程具有自己独有的工程结构。将新建的Ch0101程序工程关键目录展开,可以观察到鸿蒙程序工程的典型结构:鸿蒙应用程序工程包括两大关键组成部分:其一,工程目录下名称为AppScope的应用程序所属工程子目录;其二,工程目录下名称为entry的模块所属工程子目录。AppScope工程子目录下存放的是在整个应用程序中都可以使用的资源,包括存放在resources/base/element下的字符串资源、颜色资源等,以及存放在resources/base/media下的媒体资源等;AppScope工程子目录下还有一个名称为app.json5的应用程序配置文件,该配置文件用于配置应用程序的名称、图标、包名等信息。特别强调:AppScope工程子目录只用于存放应用程序的资源和配置文件,不用于存放程序源代码。工程模块entry子目录下存放的是所属entry模块的ArkTS源代码、模块所属资源和模块配置文件:src/main/ets工程子目录用于存放所属entry模块的ArkTS源代码;src/main/resources工程子目录用于存放所属entry模块的资源;src/main/module.json5则存放entry模块的配置信息。1.4开发一个具有交互能力的程序之前所创建的Ch0101程序工程只显示了“HelloWorld”文字,该程序不具备与用户的交互功能。现在新建一个名称为Ch0102的程序工程,运行该程序,将在首页面显示一段文字、一张图片和一个按钮,点击按钮,将显示一个对话框。在DevEcoStudio中新建一个名称为Ch0102的程序工程。由于程序中需要显示一张图片,因此,需要将一张图片存放到entry模块的src/main/resources/base/media目录下。修改src/main/ets/pages/index.ets文件为如下内容:@Entry@ComponentstructIndex{@Statemessage:string='Loremipsumdolorsitamet,consectetur'+'adipiscingelit.Naminscelerisquesem.Maurisvolutpat,dolor'+'idinterdumullamcorper,risusdoloregestaslectus,sitamet'+'mattispurusduinecrisus.Maecenasnonsodalesnisi,veldictum.';
build(){Column(){Text(this.message).id('HelloWorld').fontSize(20).fontWeight(FontWeight.Bold).margin(20)Image($r('app.media.scene')).margin(20).height(200).objectFit(ImageFit.Auto)Button("点我").width('93%').onClick(()=>{AlertDialog.show({title:'对话框',message:'这是一个普通对话框,用于显示一些提示信息',autoCancel:true,alignment:DialogAlignment.Bottom,offset:{dx:0,dy:-20},gridCount:3,confirm:{value:'关闭',action:()=>{('Button-clickingcallback')}}})})}.height('100%').width('100%')}}这段代码用于首界面的布局:它是ArkTS代码,也称为方舟TypeScript代码。ArkTS是专为开发鸿蒙应用程序而设计的语言。ArkTS基于TypeScript,并对TypeScript进行扩充和部分限制。关于ArkTS语言,将在第2章进行详细介绍。虽然还没有学习ArkTS语言,可以先对这段代码做一个直观的简单解释:它定义了一个名称为Index的组件,这个组件将作为Ch0102程序的首界面。在这个组件中,包含一个布局组件Column,在Column布局组件中,将按列布局的方式依次显示一个文本组件、一个图像组件和一个按钮组件,并且,当点击按钮组件时,将显示一个AlertDialog对话框。运行这个程序,显示本届开头所显示的界面。1.5练习:建立鸿蒙智能终端程序开发环境从鸿蒙官网下载DevEcoStudio开发环境并在自己的电脑上安装,完成安装后,新建一个鸿蒙应用程序工程,然后新建鸿蒙模拟器,并在模拟器上运行应用程序进而验证开发环境安装的完整性。Q&A第2章ArkTS语言基础ArkTS语言也称为方舟语言,是鸿蒙应用程序开发的官方语言,因此,为了开发鸿蒙应用程序,需要首先学习ArkTS语言。由于ArkTS语言是基于TypeScript语言开发的,而TypeScript语言又是基于JavaScript开发的,因此,对于具有TypeScript语言基础,或者具有JavaScript语言基础的人,学习ArkTS语言是比较容易的。本章对ArkTS语言的核心部分进行介绍。目录2.1从JavaScript到TypeScript再到ArkTS2.2基本知识2.3函数2.4类2.5接口2.6泛型类型及泛型函数2.7空安全及其处理2.8模块及其应用2.9案例:计算一元二次方程的根2.10练习:求解形状的面积和周长2.1从JavaScript到TypeScript再到ArkTSJavaScript语言被广泛地用于浏览器页面的控制。将JavaScript语言与HTML标记语言、CSS样式语言结合起来,可以编写出非常灵活、非常美观、用户体验非常好的Web页面应用程序。JavaScript语言取得巨大成功,重要原因在于JavaScript语言简洁、易学易用、并且不失灵活性。程序设计人员不能将完整的面向对象的程序设计思想用于基于JavaScript程序设计中。TypeScript正式为了克服和解决JavaScript的以上两个缺点而出现的。TypeScript规定在变量声明变量时必须明确定义变量的类型。TypeScript还吸纳了面向对象的思想,提供了完善的面向对象程序设计机制。ArkTS在TypeScript的基础上,对TypeScript做了进一步扩展和规范,包括:其一,ArkTS对TypeScript的动态类型特性施加了更严格的限制;其二,通过取消动态类型特性,ArkTS代码能更有效地被运行前编译和优化;其三,增加了面向对象编程技术。ArkTS保持了TypeScript的大部分语法,为现有的TypeScript开发者实现无缝过渡,让移动开发者快速上手ArkTS,同时,ArkTS提供了与JavaScript的无缝互通,开发者可以很容易地将JavaScript代码集成到他们的应用中。2.2基本知识本节对ArkTS的基本内容进行介绍,包括:基本数据类型、引用型数据类型、变量定义和使用、运算符、基本程序流程控制语句等。ArkTS的这些基本知识大部分与JavaScript相同或者类似。2.2.1基本数据类型和引用型数据类型ArkTS常用基本数据类型及其含义:序号数据类型含义1number数值类型,包括浮点数和整数。表示由数字序列组成的十进制数,对于数值类型的字面常量,0b开头的数值表示二进制数值;0o开头表示那禁止数值;0x靠头表示十六进制数值。2string字符串类型,任何以双引号或者单引号包围的数据都是字符串数据。3boolean布尔类型。布尔值类型的变量的值只能是true或者false。4nullnull类型,也就是空类型。该类型只有一个值,也就是null。5undefinedundefined类型,也就是无定义类型。该类型只有一个值,也就是undefined。6symbolsymbol类型。symbol类型的变量用来表示独一无二的值,可以通过Symbol构造函数生成。ArkTS常用引用类型及其含义:序号数据类型含义1objectobject类型,也就是对象类型。ArkTS中除基本数据类型以外的都是对象类型。object是引用类型,它存储的是值的引用。2arrayarray类型,也就是数组类型。用于存储多个同类型数据的引用类型。例如,number[]定义了一个元素为number的数组类型;string[]定义了一个元素类型为string的数组类型。3voidvoid类型,用于指定函数没有返回值。void类型只有一个值,就是void。注意,void类型一般不作为变量的类型定义,只作为函数的返回值类型使用。4enumenum类型,也就是枚举类型。枚举类型是预先定义的一组命名值的值类型,其中命名值又称为枚举常量。5[数据类型,数据类型,…]元组可以看做是数组的扩展,它表示已知元素数量和类型的数组,它特别适合用来实现多值返回。确切的说,就是已知数组中每一个位置上的元素的类型,可以通过元组的索引为元素赋值。6数据类型|数据类型|…union类型,即联合类型,是由多个类型组合成的引用类型。2.2.2变量的声明和使用不同于JavaScript对变量的声明和使用,在ArkTS中可以使用变量之前,需要首先声明变量,并且在声明变量时需要指明变量的数据类型,表示所声明的变量只能存储指定类型的值。在ArkTS中,以关键字let关键字开头声明变量。例如:let关键字结合const关键字使用,可以定义只读常量。例如:lethi:string='hello';hi='hello,world';letcount:number=1000;letbirth:object=newDate();letconstPI:number=3.14;letconstcenter:string=‘Here’;为了简化变量声明,ArtTS提供了类型自动推导机制:ArkTS可以根据赋予变量值的类型,自动推导出变量的类型。例如:这里定义了变量age并赋予其值为20,此时,ArkTS会自动推导出变量age的数据类型为number;同理,根据赋予scores变量的值,ArkTS可以推导出scores的数据类型为数值类型的数组。因此,以上定义age和scores变量的语句等价于如下语句:为了代码的可读性和便于维护,在声明变量时,建议不要省略变量的类型。letage=20;letscores=[92.5,100,89,93.5];letage:number=20;letscores:number[]=[92.5,100,89,93.5];2.2.3运算符ArkTS的运算符与JavaScript的运算符完全相同,包括赋值运算符:=;复合赋值运算符:+=、-=、*=、/=、%=、<<=、>>=、>>>=、&=、|=、^=;关系运算符:===、!==、==、!=、>、>=、<、<=;算术运算符:+、-、*、/、++、--;位运算符:&、|、!;逻辑运算符:&&、||、!,等等,不再赘述。2.2.4流程控制语句ArkTS的流程控制语句与JavaScript完全相同,包括if…else语句、switch…case…default语句、条件表达式语句condition?expression1:expression2、for循环语句、for…each语句、while循环语句、break语句、continue语句、try…catch…finally语句、throw语句等。不再赘述。2.3函数函数是ArkTS的一种特殊对象,ArkTS函数与JavaScript函数基本类似,只是在ArkTS中需要为函数指明返回值类型。本节对ArkTS函数进行介绍。2.3.1函数声明和调用函数声明引入(定义)一个函数,一个函数声明包含函数名称、参数列表、返回类型和函数体。例如,以下示例是一个简单的函数,这个函数的名称为add,包含两个string类型的参数,返回类型为string:functionadd(x:string,y:string):string{letz:string=`${x}${y}`;returnz;}如果ArkTS能够从返回值推导出返回值类型,则在声明函数时可以省略函数返回值类型。例如:不需要返回值的函数的返回类型可以显式指定为void类型或省略掉类型,并且在这类函数的函数体中不需要使用返回语句。为了代码的可读性和便于维护,建议在声明函数时不要省略函数的返回值类型。在ArkTS中调用函数的方式与JavaScript完全一致,不再赘述。//显式指定返回类型functionfoo():string{return'foo';}
//推断返回类型为stringfunctiongoo(){return'goo';}2.3.2函数的可选参数在定义函数时,可以根据需要指定可选参数。所谓可选参数,是指在调用函数时可有可无的实参参数。可选参数的格式可为name?:type,也就是,在函数参数的名字后面跟一个问号。例如:由于参数name后面有一个问号,因此,name参数是可选的:程序代码根据调用时是否传递了实参而显示不同的信息。在指定可选参数时,还可以为可选参数指定默认值,也就是,当调用时未给定参数值,则为可选参数使用默认参数值。例如:functionhello(name?:string){if(name==undefined){console.log('Hello!');}else{console.log(`Hello,${name}!`);}}其中的coeff为具有默认值的可选参数,当调用者未给出这个参数时,则这个参数的具有默认值2。函数的最后一个参数可以是rest参数,rest参数的格式为...rest。rest参数允许函数接收一个由剩余实参组成的数组,用于处理不定数量的参数输入。例如:这个函数具有一个类型为string的参数和一个rest参数,计算rest参数的和并返回。functionmultiply(n:number,coeff:number=2):number{returnn*coeff;}functionsum(prompt:string,...numbers:number[]):number{console.log(prompt);letres=0;for(letnofnumbers)res+=n;returnres;}2.3.3函数作为数据类型在ArkTS中,可以使用type关键字定义一个函数类型,然后,在后续可以江定义的函数类型作为数据类型使用。例如:这段代码使用type关键字定义了一个名称为Trig的函数类型。本质上,一个函数类型规定了函数的原型:函数参数列表以及返回值类型。一旦定义了函数类型,就可以像使用其他数据类型一样将函数类型作为类型使用。例如,在上例的action函数中,其参数就是一个Trig类型的参数。最后,在调用action函数时,传递了Math.sin函数最为实参,因此,对action函数的调用将返回sin(3.14)的值。//使用type关键字定义了一个函数类型typeTrig=(x:number)=>number//将函数类型作为普通数据类型使用functionaction(f:Trig){f(3.14);//调用函数}action(Math.sin);//将函数作为参数传入2.3.4lambda函数lambda函数有时也称为箭头函数,可以在不用指定函数类型的情况下快速而简洁地定义一个函数变量。例如:这段代码定义了一个函数类型变量sum,这个函数有两个参数:名称为x的number参数和名称为y的number类型参数,并且这个函数返回一个number类型的值。可以使用以下方式调用这个lambda函数:letsum=(x:number,y:number):number=>{returnx+y;}letrt=sum(100,200);console.log(rt);//显示3002.4类“类”是面向堆成程序设计中非常重要的概念和技术,本节对在ArkTS中定义和使用类进行介绍。2.4.1定义类和使用类入门在ArkTS中,可以使用class关键字定义类。定义类的本质就是引入了一个新类型,并定义其字段、方法和构造函数。例如,以下示例定义了Person类,该类具有字段name和surname、构造函数和方法fullName:classPerson{name:string='';surname:string='';
constructor(n:string,sn:string){=n;this.surname=sn;}
fullName():string{return+''+this.surname;}}一旦定义了一个类,就可以使用关键字new创建实例。例如,可以使用如下代码创建Person类的实例:letp=newPerson('John','Smith');console.log(p.fullName());2.4.2字段在定义类时,在其中声明的某种类型的变量称为字段或者属性。类可以具有实例字段或者静态字段。实例字段存在于类的每个实例上,也就是每个实例都有自己的实例字段集合。例如,在定义Person类时,其中的name和surname就是实例字段。要访问实例字段,需要使用类的实例。例如:以上代码首先定义Person类,其中包含两个实例字段name和age。之后,使用new关键字创建Person类的两个实例,并使用变量p1和p2引用它们,进而可以使用变量p1或p2访问各自实例的实例字段name和age。classPerson{name:string='';age:number=0;constructor(n:string,a:number){=n;this.age=a;}
getName():string{return;}}
letp1=newPerson('Alice',25);;letp2=newPerson('Bob',28);p2.getName();使用关键字static声明静态字段。静态字段属于类本身,类的所有实例共享一个静态字段。要访问静态字段,需要使用类名。例如:ArkTS要求所有字段在声明时或者构造函数中显式初始化,这是为了减少运行时的错误和获得更好的执行性能。classPerson{staticnumberOfPersons=0;constructor(){//...Person.numberOfPersons++;//...}}console.log(Person.numberOfPersons);2.4.3方法可以在ArkTS的类中定义方法。ArkTS类的方法包括构造方法和普通方法。类的构造方法也称为构造函数,使用constructor名称表示,构造函数没有返回值类型声明;类的普通方法包括实例方法和静态方法。静态方法属于类本身,使用static关键字修饰,静态方法只能访问静态字段;而实例方法既可以访问静态字段,也可以访问实例字段,包括类的私有字段。例如,下面的示例定义了一个名称为Circle的类:一旦定义了Circle类,可以使用new关键字创建Circle类的对象,进而访问对象的方法或者字段:classCircle{radius:number=0;staticPI:number=3.14;
constructor(radius:number){this.radius=height;}
area():number{returnPI*radius*radius;}
staticgetPI:number{returnPI;}}letc:Circle=newCircle(10);console.log(c.area());console.log(Circle.getPI());2.4.4可见性修饰符类的方法和属性都可以使用可见性修饰符进行修饰。可见性修饰符包括:private、protected和public。默认可见性为public。public修饰的类成员(字段、方法、构造函数)在程序的任何可访问该类的地方都是可见的。private修饰的成员不能在声明该成员的类之外访问。protected修饰符的作用与private修饰符非常相似,不同点是protected修饰的成员允许在派生类中访问。例如:classC{publicx:string='';privatey:string='';set_y(new_y:string){this.y=new_y;//OK,因为y在类本身中可以访问}}letc=newC();c.x='a';//OK,该字段是公有的c.y='b';//编译时错误:'y'不可见2.4.5对象字面量对象字面量是一个表达式,可用于创建类实例并提供一些初始值。它在某些情况下更方便,可以用来代替new表达式。对象字面量的表示方式是:封闭在花括号对({})中的'属性名:值'的列表。例如:此处,使用对象字面量创建了类C的一个实例,并显示实例的实例字段的值。classC{n:number=0;s:string='';}
letc:C={n:42,s:'foo'};console.log(c.n);//显示42console.log(c.s);//显示foo2.4.6类的继承一个类(称为子类,或者继承类,或者派生类)可以继承另一个类(称为基类,或者父类,或者超类)。继承类继承基类的字段和方法,但不继承构造函数。继承类可以新增定义字段和方法,也可以覆盖其基类定义的方法。例如,下面的例子中Person类是父类,Teacher类是继承Person类的子类:classPerson{name:string='';privateage=0;
constructor(name:string,age:number){=name;this.age=age;}getAge():number{returnthis.age;}setAge(age:number):void{this.age=age;}display():void{console.log();console.log(this.age);}}classTeacherextendsPerson{income:number=0;constructor(name:string,age:number,income:number){super(name,age);this.income=income;}taxes():number{returnthis.income*0.42;}display():void{super.display();console.log(this.income);}}这段代码首先定义了Person类,然后定义了Person类的子类Teacher类。Teacher类继承了Person类的name属性、getAge()方法、setAge()方法,但是不能继承Person类的构造函数和private修饰的属性age。在Teacher类的构造函数中,使用super(name,age)访问了父类的构造函数。在Teacher类中,还重写了父类的display()方法,并且使用super.display()访问了父类的display()方法用于显示name字段和age字段的值。现在可以创建Person类以及Teacher类的对象,如下代码所示:letp:Person=newPerson(‘张三’,20);p.setAge(21);p.display();lett:Teacher=newTeacher(‘王老师’,38,5324);t.setAge(40);console.log(t.getAge);t.diaplay();张三2140王老师4053242.4.7抽象类带有修饰符abstract的类称为抽象类。抽象类可用于表示一组更具体的概念所共有的概念。不允许创建抽象类的实例。抽象类一般作为父类使用。例如,下面的例子:abstractclassBase{field:number;constructor(p:number){this.field=p;}}
classDerivedextendsBase{count:number;constructor(p:number,count:number){super(p);this.count=count;}do:number{//dosomething}}抽象类中可以包含抽象方法。所谓抽象方法,就是使用abstract关键字修饰的方法,并且,抽线方法不能有函数体。抽象方法只能出现在抽线类中。例如,下面的例子:abstractclassShape{name:string;constructor(name:string){=name;}abstractperimeter():number;}
classTriangleextendsShape{a:number;b:number;c:number;constructor(a:number,b:number,c:number){super(‘三角形’);this.a=a;this.b=b;this.c=c;}perimeter():number{returnthis.a+this.b+this.c;}}这段代码定义了父类Shape,它是一个抽象类,其中还包含了一个名称为perimeter()的抽象方法。在子类Triangle中,实现了抽象方法perimeter()。因此,可以创建Triangle剋的实例并调用其中的方法完成州长的计算。2.5接口与ArkTS的类类似,ArkTS接口声明也引入新类型。接口是定义代码协定框架的常见方式,任何一个类的实例只要实现了某个接口,就可以通过该接口实现多态。2.5.1接口定义和使用在ArkTS中,使用interface关键字定义一个新的接口。一般来说,接口通常包含属性和方法的声明。例如,下面的代码定义了一个名称为Compute的接口:在接口的定义中,对于接口中的方法,只需要给出方法的原型即可。例如,上例中的Compute接口,包括一个属性name和两个方法:add()方法和sub()方法。接口规定了程序的框架,一旦定义了接口,可以通过类实现指定的接口。例如,下面的名称为MyMath的累实现了Compute接口:interfaceCompute{name:string;add(a:number,b:number):number;sub(a:number,b:number):number;}classMyMathimplementsCompute{name:string=‘’;inventor:string=‘’;
add(a:number,b:number):number{returna+b;}sub(a:number,b:number):number{returna-b;}display(){console.log(‘MyownMathclass’);}}2.5.2接口的继承与类的继承类似,接口也是可以被继承的。使用extends关键字实现接口的继承。例如,下面的例子中,Compute2接口继承了上例中的Compute接口。一个实现了某个子接口的类,必须实现接口的所有方法,包括父接口和子接口的所有方法。例如,下面的例子中,YourMath实现了子接口Compute2:interfaceCompute2extendsCompute{mult(a:number,b:number):number;divide(a:number,b:number):number;}classYourMathimplementsCompute2{name:string=‘’;count:number=0;
add(a:number,b:number):number{returna+b;}sub(a:number,b:number):number{returna-b;}mult(a:number,b:number):number{returna*b;}divide(a:number,b:number):number{returna/b;}print(){console.log(‘YourMathclass’);}}2.5.3抽象类和接口抽象类与接口都无法实例化。抽象类是类的抽象,抽象类用来捕捉子类的通用特性;接口是行为的抽象。在ArkTS中,抽象类与接口有如下区别:(1)一个类只能继承一个抽象类,而一个类可以实现一个或多个接口;(2)接口中不能含有静态代码块以及静态方法,而抽象类可以有静态代码块和静态方法;(3)抽象类里面可以有方法的实现,但是接口完全都是抽象的,不存在方法的实现;(4)抽象类可以有构造函数,而接口不能有构造函数。2.6泛型类型及泛型函数泛型类型和泛型函数允许创建的代码在多种类型上运行,而不仅支持单一类型。本届对泛型相关内容进行介绍。2.6.1泛型类型考虑如下一种编程场景:现在需要编写一个类,完成类似堆栈的功能,也就是,可以将任何同类型的元素放入堆栈,或者从堆栈中弹出一个元素。根据程序要求,可以采用数组存储元素,但是,由于要在堆栈中放置任何元素,因此,实现无法知道要放置的元素的类型。这时,可以使用泛型技术解决这个问题。代码如下:classStack<T>{privateitems:T[];
constructor(){this.items=[];}
push(element:T):void{this.items.push(element);}
pop():T|undefined{returnthis.items.pop();}
isEmpty():boolean{returnthis.items.length===0;}
size():number{returnthis.items.length;}
toString():string{returnthis.items.toString();}}
//使用示例constnumberStack=newStack<number>();numberStack.push(10);numberStack.push(20);numberStack.push(30);console.log(numberStack.size());//3
//字符串堆栈示例conststringStack=newStack<string>();stringStack.push('TypeScript');stringStack.push('is');stringStack.push('awesome!');console.log(stringStack.pop());//"awesome!"console.log(stringStack.toString());//"TypeScript,is"
//对象堆栈示例classPerson{name:string=‘’;age:number=0;constructor(name:string,age:number){=name;this.age=age;}display():void{console.log(name);console.log(age);}}constpersonStack=newStack<Person>();personStack.push({name:'Alice',age:25});personStack.push({name:'Bob',age:30});由于所定义的Stack类中,将属性items定义为泛型T的类型,因此,Statck实例的items数组中可以存储任何类型的元素。从这个例子可以看出,使用泛型技术可以极大的提高代码的灵活性。包含了泛型类型的类称为泛型类,例如,这个例子中定义的Stack类就是一个泛型类。与定义泛型类类似的方式,也可以定义泛型接口,不再赘述。2.6.2泛型函数与泛型类类似,也可以使用泛型函数提升函数的灵活性。包含有泛型参数的函数称为泛型函数。下面的例子定义了一个泛型参数,该泛型函数将泛型参数的值显示在屏幕上:functionprintall<T>(data:T[]):void{for(iindata){console.log(data[i]);}}printall<string>([‘How’,‘do’,‘you’,‘do?’]);2.7空安全及其处理在程序设计实践中,null,也就是空,是导致程序异常的重要来源。这一节对null及其处理进行介绍。2.7.1声明可为null值的变量默认情况下,ArkTS中的所有类型都是不可为空的,因此变量的值默认情况下不能为空。例如,在下面的示例中,所有行的代码都会导致编译时错误:如果在程序设计中,某个变量的值确实可能为null,则需要使用联合类型明确表述这种可能性,如下代码所示:letx:number=null;//编译时错误lety:string=null;//编译时错误letz:number[]=null;//编译时错误letx:number|null=null;x=1;//okx=null;//okif(x!=null){/*dosomething*/}2.7.2非空断言运算符“!”后缀运算符“!”可用于断言操作数为非空,也就是,用于断言操作变量或者对象是非null和非undefined类型,提示编译器后续对变量或者对象的操作是安全的。例如,下面的代码在编译时会报错:究其原因就是参数arg可能为null或者undefined,但是,变量str只能为string类型。为了解决这个问题,可以使用非空断言运算符“!”。修改后的代码如下:functionhandler(arg:string|null|undefined){letstr:string=arg;//编译错误//...}functionhandler(arg:string|null|undefined){letstr:string=arg!;//通过非空断言运算符告知编译器arg不会为null或者undefinedstr.split('');//...}2.7.3空值合并运算符“??”空值合并二元运算符“??”用于检查左侧表达式的求值是否等于null或者undefined,如果是,则表达式的结果为右侧表达式;否则,结果为左侧表达式。换句话说,语句:a??b等价于三元运算符(a!=null&&a!=undefined)?a:b。例如,下面的例子中,getNick方法如果设置了昵称,则返回昵称;否则,返回空字符串:classPerson{//...nick:string|null=null;getNick():string{returnthis.nick??'';//运算符“??”后面是两个单引号,表示空串}}2.7.4可选属性运算符“?:”和可选链运算符“?.”运算符“?:”表示类或者接口的某个属性是可选的。可选链运算符“?.”则允许在访问对象的某个属性时,如果属性的值为null或者undefined,表达式会短路并返回undefined,而不会抛出错误。看下面这个例子:classPerson{nick:string|null=null;spouse?:Person;//表示spouse是可选属性
setSpouse(spouse:Person):void{this.spouse=spouse;}
getSpouseNick():string|null|undefined{returnthis.spouse?.nick;//当spouse为undefined时返回undefined;}
constructor(nick:string){this.nick=nick;this.spouse=undefined;}}这段代码定义了Person类,其中包含两个属性:nick和spouse,其中nick可谓null,而spouse属性则是可选属性,也就是,spouse的值可为undefined。注意getSpouseNick()方法中的语句:returnthis.spouse?.nick;因为spouse的值可为undefined或者其他非空对象。当spouse为undfined时,该语句会直接返回undefined;当spouse不为undefined时,则返回spouse对象的nick属性的值。2.8模块及其应用程序可划分为多组编译单元或模块。每个模块都有其自己的作用域,即,在模块中创建的任何声明,包括变量、函数、类等,在该模块之外都不可见:如果需要在其他模块中使用,则需要将这些声明导出。与此相对,如果一个模块需要使用另一个模块中导出的声明,包括变量、函数、类、接口等,必须首先将这些声明导入到模块中。2.8.1使用export导出模块的声明可以使用关键字export导出模块顶层的声明。未导出的声明名称被视为私有名称,只能在声明该名称的模块中使用。例如,下面的例子导出了模块的部分声明:在这例子中,从模块中导出了Point类和distance()函数。其他的模块可以将这个模块导出的声明导入,进而可以在其模块的代码中使用这两个声明。exportclassPoint{x:number=0;y:number=0;constructor(x:number,y:number){this.x=x;this.y=y;}}letOrigin=newPoint(0,0);exportfunctiondistance(p1:Point,p2:Point):number{returnMath.sqrt((p2.x-p1.x)*(p2.x-p1.x)+(p2.y-p1.y)*(p2.y-p1.y));}2.8.2使用import导入其他模块的声明导入声明用于导入从其他模块导出的实体,并在当前模块中提供其绑定。导入声明由两部分组成:其一,导入路径:用于指定导入的模块;其二,导入绑定:用于定义导入的模块中的可用实体集和使用形式。使用上一节的模块为例子。为了便于描述,假设上一节编写的模块代码保存在当前工作目录文件名为am.ts的文件中,现在需要导入这个模块的声明在模块bm.ts中使用。可采用多种方式导入。方式一:整体命名方式。也就是采用导入绑定“*asa”表示绑定名称“a”,通过可访问从导入路径指定的模块导出的声明。例如:方式二:独立命名方式。也就是采用导入绑定{ident1,...,identN}表示将导出的实体与指定名称绑定,该名称可以用作简单名称。例如:import*asabfrom'./am.ts';letp1:ab.Point=newab.Point(10,20);letp2:ab.Point=newab.Point(40,60);letdd=ab.distance(p1,p2);console.log(dd);import{Point,distance}from'./am.ts';letp1:Point=newPoint(10,20);letp2:Point=newPoint(40,60);letdd=distance(p1,p2);console.log(dd);方式三:独立重命名方式。也就是采用标识符列表定义了identasalias,则实体ident将绑定在名称alias下。例如:letp1:P=newP(10,20);letp2:P=newP(40,60);letdd=distance(p1,p2);console.log(dd);鸿蒙系统预先定义了很多功能模块,这些模块可以应用到鸿蒙应用程序的开发实践中。在可以使用鸿蒙系统的模块之前,也需要将要使用的模块导入到程序代码中。例如,如下的代码语句将导入鸿蒙的“@ohos.app.ability.UIAbility”模块中的UIAbility声明:importUIAbilityfrom'@ohos.app.ability.UIAbility';从HarmonyOSNEXTDeveloperPreview1版本开始引入Kit概念。SDK对同一个Kit下的接口模块进行了封装,开发者在示例代码中可通过导入Kit的方式来使用Kit所包含的接口能力。其中,Kit封装的接口模块可查看SDK目录下Kit子目录中各Kit的定义。导入鸿蒙Kit也有三种方式:方式一:导入Kit下单个模块的接口能力。例如:import{UIAbility}from'@kit.AbilityKit';方式二:导入Kit下多个模块的接口能力。例如:import{UIAbility,Ability,Context}from'@kit.AbilityKit';方式三:导入Kit包含的所有模块的接口能力。例如:import*asmodulefrom'@kit.AbilityKit';其中,“module”为别名,可自定义,然后通过该名称调用模块的接口。2.9案例:计算一元二次方程的根本章介绍了ArkTS的核心内容。作为开发鸿蒙应用程序的官方语言,使用ArkTS可以开发优秀的鸿蒙应用程序。本节通过一个简单的案例对ArkTS语言的主要内容进行总结和综合应用。2.9.1案例目标使用“类”可以对一类对象的共有性质进行抽象和封装,例如,可以使用类封装“书籍”的性质,也可以使用类封装“学生”的性质等等。本节案例使用“类”封装在中学数学学习的一元二次方程,也就是,编写一个类,对一元二次方程的进行封装,然后,编写测试程序验证其正确性。2.9.2案例分析一元二次方程的一般形式是“ax2+bx+c=0”,其中,a≠0,因此,所定义的一元二次方程的类至少有三个number类型的属性用于保存一元二次方程的三个系数。再者,考虑到求一元二次方程的根是最为常用的方法,因此,在所定义的一元二次方程的类中编写求根方法和显示一元二次方程基本信息的方法。2.9.3案例实施在DevEco中新建一个名称为Ch0201的工程,并在“entry/src/main/ets”子目录下新建functions子目录,然后,在functions子目录下新建名称为quadratic.ets的文件,新建完成的程序工程:在quadratic.ets文件中录入如下代码:exportclassQuadratic{privatea:number=0;privateb:number=0;privatec:number=0;
constructor(a:number,b:number,c:number){this.a=a;this.b=b;this.c=c;}
root():void{if(this.a==0){console.log('非法一元二次方程!');return;}
letdelta:number=this.b*this.b-4*this.a*this.c;if(delta>0){console.log('有两个实根:%d,%d',(-this.b+Math.sqrt(delta))/(2*this.a),(-this.b-Math.sqrt(delta))/(2*this.a));}elseif(delta==0){console.log('有两个相同的实根:%d',(-this.b)/(2*this.a));}else{console.log('该方程没有实根!');}}
toString():string{returnthis.a+'x^2'+'+'+this.b+'x'+'+'+this.c+'=0';}}修改与functions在同一层的pages子目录下的index.ets文件为如下内容:import{Quadratic}from'../functions/quadratic'
@Entry@ComponentstructIndex{@Statemessage:string='HelloWorld';
build(){RelativeContainer(){Text(this.message).id('HelloWorld').fontSize($r('app.float.page_text_font_size')).fontWeight(FontWeight.Bold).alignRules({center:{anchor:'__container__',align:VerticalAlign.Center},middle:{anchor:'__container__',align:HorizontalAlign.Center}}).onClick(()=>{this.message='Welcome';letqq:Quadratic=newQuadratic(2,4,1);console.log(qq.toString());qq.root();})}.height('100%').width('100%')}}2.10练习:求解形状的面积和周长分别定义一个描述三角形和描述圆的类。由于可以计算三角形和圆的周长和面积,因此,所定义的类中需要定义用于计算周长和面积的方法,当然,还可以根据需要定义其他方法。考虑到三角形和圆都是“形状”,因此,建议将三角形和圆的共性抽象成一个称为Shape的父类中,然后使用类的继承机制再定义用于描述三角形和用于描述圆的类。完成三角形和圆的类定义后,再编写测试代码,验证它们的正确性。Q&A第3章构建应用程序UI—基础UI,也就是UserInterface,或者称为用户界面,是用户与系统进行交互的桥梁。鸿蒙提供了完整的用于开发用户UI的技术架构,这个架构称为ArkUI框架,也称为方舟UI。本章ArkUI的基本使用进行介绍。目录3.1UI组件入门3.2系统内置UI组件介绍3.3资源分类与访问3.4细说UI3.5UI组件装饰器及其使用3.6渲染控制3.7案例:图来图往3.8练习:呼来唤去3.1UI组件入门在鸿蒙应用程序中,所有的用户UI都是一个自定义的UI组件。通过ArkUI提供的自定义组件机制,同时在自定义组件中使用ArkUI提供的组件,可以构建非常美观和灵活的用户界面。下面通过例子介绍如何构建用户界面。这个例子进行简单的算术运算:用户在两个输入框中分别输入两个数,然后点击代表不同运算方式的按钮,程序会按指定的运算方式对输入的数进行运算,然后将结果显示在第三个输入框中。完成后的程序的运行效果如图。下面介绍实现例子程序功能的代码。在DevEco中新建名称为Ch0301的程序工程。修改Index.ets代码为如下内容:@Entry@ComponentstructIndex{@Staten1:string='';@Staten2:string='';@Staten3:string='';
build(){Column(){TextInput({text:$$this.n1}).type(InputType.Number).id('n1').fontSize(30).fontWeight(FontWeight.Bold).margin({top:100,right:10,bottom:10,left:10}).borderWidth(2)
TextInput({text:$$this.n2}).type(InputType.Number).id('n2').fontSize(30).fontWeight(FontWeight.Bold).margin(10).borderWidth(2)
Row(){Button('+',{type:ButtonType.Capsule,stateEffect:true}).borderRadius(8).backgroundColor(0x317aff).fontSize(40).width(70).height(50).margin(10).onClick(()=>{letnum1:number=parseInt(this.n1);letnum2:number=parseInt(this.n2);letnum3:number=num1+num2;this.n3=String(num3);})Button('-',{type:ButtonType.Capsule,stateEffect:true}).borderRadius(8).backgroundColor(0x317aff).fontSize(40).width(70).height(50).margin(10).onClick(()=>{letnum1:number=parseInt(this.n1);letnum2:number=parseInt(this.n2);letnum3:number=num1-num2;this.n3=String(num3);})Button('*',{type:ButtonType.Capsule,stateEffect:true}).borderRadius(8).backgroundColor(0x317aff).fontSize(40).width(70).height(50).margin(10).onClick(()=>{letnum1:number=parseInt(this.n1);letnum2:number=parseInt(this.n2);letnum3:number=num1*num2;this.n3=String(num3);})Button('/',{type:ButtonType.Capsule,stateEffect:true}).borderRadius(8).backgroundColor(0x317aff).fontSize(40).width(70).height(50).margin(10).onClick(()=>{letnum1:number=parseInt(this.n1);letnum2:number=parseInt(this.n2);letnum3:number=num1/num2;this.n3=String(num3);})}
TextInput({text:$$this.n3}).id('n3').fontSize(30).fontWeight(FontWeight.Bold).margin(10).borderWidth(2).enabled(false)}.height('100%').width('100%')}}3.2系统内置UI组件介绍在深入介绍如何自定义用户UI界面之前,先对ArkUI中内置的常用基础
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 办公楼建设施工方案
- 艺术节:展现才华与魅力小学主题班会课件
- 人工智能辅助企业目标规划与执行方案
- (2026版)青年教师培养计划
- 化学品泄漏紧急响应紧急处理社区居民预案
- 教育培训机构课程开发系统化流程实施手册
- 气体灭火的施工方案
- 钢结构大棚新建工程施工方案范文
- 施工现场应急滑坡方案
- 2026年八大员继续教育职业技能资格考试练习题库(附答案)
- 2026四川广安爱众股份限公司招聘5人(第四批次)易考易错模拟试题(共500题)试卷后附参考答案
- 2026广东肇庆市端州区教育局招聘中小学教师75人笔试备考题库及答案详解
- GB/T 45355-2025无压埋地排污、排水用聚乙烯(PE)管道系统
- 中国广电笔试试题及答案
- 周围血管与淋巴管疾病第九版课件
- 机器人操作系统(ROS)课件 1.ROS简介
- 试剂性能验证报告范文
- 子宫内节育器嵌顿查房
- 部门年度工作目标分解与工作计划模板
- 个体餐饮员工的规章制度
- GB/T 7704-2017无损检测X射线应力测定方法
评论
0/150
提交评论