当前位置:网站首页>【 Kotlin 中的类和对象实例】
【 Kotlin 中的类和对象实例】
2022-07-26 03:13:00 【冷醉泉】
一、准备工作
在此衔接课程的文章中,您将构建一个 Dice Roller Android 应用。当用户“掷骰子”时,系统会生成一个随机结果。生成结果时会考虑骰子的面数。例如,6 面的骰子,只能生成 1 到 6 的值。
下面是最终应用呈现的样子。

为帮助您专注于了解此应用的全新编程概念,您将使用基于浏览器的 Kotlin 编程工具来创建核心应用功能。该程序会将您的结果输出到控制台。之后您将在 Android Studio 中实现界面。
在此第一个章节中,您将创建一个 Kotlin 程序,以模拟掷骰子并输出一个随机数字,就像实际掷骰子的情形一样。
前提条件
- 已了解如何在https://developer.android.com/training/kotlinplayground
中打开、修改和运行代码 - 能够创建并运行使用变量和函数的 Kotlin 程序,并将结果输出到控制台。
- 能够使用采用
${variable}表示法的字符串模板设置文本中数字的格式。
学习内容
- 如何编写程序来生成随机数字以模拟掷骰子。
- 如何使用变量和方法创建
Dice类,以构建代码。 - 如何创建类的对象实例、修改其变量以及调用其方法。
您将构建的内容
- 使用基于浏览器的 Kotlin 编程工具构建可执行随机掷骰子操作的 Kotlin 程序。
所需工具
- 一台已连接到互联网的计算机
二、掷出随机数字
游戏通常具有随机性。您可以赢得随机奖励,或在棋盘游戏中移动随机步数。在日常生活中,您可以使用随机数字和字母来生成更安全的密码!
您可以编写一个程序来模拟掷骰子,而无需真的掷骰子。每次掷骰子时,结果可以是可能值范围内的任何数字。幸运的是,您无需为此类程序自行构建随机数字生成器。大多数编程语言(包括 Kotlin)都内置有用于生成随机数字的方法。在此任务中,您将使用 Kotlin 代码来生成随机数字。
设置起始代码
- 在浏览器中,打开网站 https://developer.android.com/training/kotlinplayground。
- 删除代码编辑器中的所有现有代码,并将其替换为以下代码。这是您在之前的章节中使用的
main()函数。
fun main() {
}
使用随机函数
如要掷骰子,您需要一种方法来表示所有有效的掷骰结果值。对于常规的 6 面骰子,可接受的掷骰结果值包括:1、2、3、4、5 和 6。
在前面的课程中,您学习了数据类型,比如 Int 表示整数,String 表示文字。IntRange 是另一种数据类型,表示从起始值到结束值的整数范围。IntRange 是适合用于表示掷骰可能产生的值的数据类型。
- 在
main()函数中,将一个变量定义为名为diceRange的val。将其分配给 1 到 6 的IntRange,用于表示 6 面骰子可以掷出的整数值范围。
val diceRange = 1..6
可以看出,1..6 是一个 Kotlin 范围,因为它包含起始数字、两个点以及一个结束数字(中间没有空格)。下面再列举两个整数范围的其他例子,2..5 表示数字 2 到 5,100..200 表示数字 100 到 200。
提示: 请注意,在此定义中并未指定 IntRange,就像您在为整数或字符串创建变量时无需指定 Int 或 String 一样。大多数情况下,系统能够判断出预期的数据类型。
例如,系统会将以下内容:
val diceRange = 1…6
解释为以下内容:
val diceRange: IntRange = 1…6
与调用 println() 可指示系统输出给定文本类似,您可以使用 random() 函数生成并返回给定范围内的随机数字。同之前一样,您可以将结果存储在变量中。
- 在
main()中,将一个变量定义为名为randomNumber的val。 - 为
randomNumber设置对diceRange范围调用random()的结果值,如下所示。
val randomNumber = diceRange.random()
请注意,在变量和函数调用之间使用一个句点(即点),即可对 diceRange 调用 random()。您可以将其解读为“从 diceRange 中生成随机数字”。然后结果会存储在 randomNumber 变量中。
- 为了显示随机生成的数字,请使用字符串格式表示法(也称为“字符串模板”)
${randomNumber}进行输出,如下所示。
println("Random number: ${
randomNumber}")
完成后的代码应如下所示。
fun main() {
val diceRange = 1..6
val randomNumber = diceRange.random()
println("Random number: ${
randomNumber}")
}
- 运行几次代码。每次,您都应看到如下输出内容,其中会显示不同的随机数字。
Random number: 6
关于范围的提示:
- 范围可以是任何整数。以下范围是有效范围:3…46、0…270、-6…+6、-10…-4。
- 您可以直接对范围调用函数,例如:(1…6).random()。
三、创建 Dice 类
当您掷骰子时,它们是您手中的真实物体。而您刚刚编写的代码尽管可以正常运行,但是很难将其与真实的骰子关联起来。编写程序时,如果能让程序更贴合其表示的事物,就会更容易让人理解。所以,如果能用程序创建一个可以投掷的骰子,那就太棒了!
所有骰子的工作原理基本都相同。它们具有相同的属性(如骰面)、相同的行为(例如可以滚动)。在 Kotlin 中,您可以创建骰子的程序蓝图,说明骰子有骰面,并可以掷出一个随机数字。此蓝图称为“类”。
然后,您可以在该类中创建称为“对象实例”的真实骰子对象。例如,您可以创建 12 面的骰子或 4 面的骰子。
提示: “类”就好比建筑设计师的蓝图规划,它不是真正的房子,而是关于如何建造房子的说明。房子是根据蓝图建造的实际事物或对象实例。
注意: 将有关骰子的一切属性组合到类中称为封装。封装是一个华丽的词语,但实际上它的意思就是您可以将逻辑上相关的功能整合到一个地方。
定义 Dice 类
在以下步骤中,您将定义一个名为 Dice 的新类来表示可滚动的骰子。
- 为了重新开始,请清除
main()函数中的代码,确保最终代码如下所示。
fun main() {
}
- 在此
main()函数下,添加一个空行,然后添加代码以创建Dice类。如下所示,先输入关键字class,后跟类名称,再跟左大括号和右大括号。在大括号内留出空间,以便放入类的代码。
class Dice {
}
注意:
- 与使用 Kotlin 中的 fun 关键字创建新函数类似,请使用 class 关键字创建新类。
- 您可以为 class选择任何名称,但如果名称能指示类所表示的对象,将会很有帮助。按照惯例,类名称采用大驼峰式命名法(也称为驼峰式大小写)编写。例如:Car、ParkingMeter和
CustomerRecord 都是有效的类名称,您可以猜出它们所表示的对象。
在类定义中,可以使用变量为类指定一个或多个属性。真实的骰子可以具有多个面、一种颜色或重量。在此任务中,您将着重处理骰子的面数属性。
- 在
Dice类中,添加一个名为sides的var,用于表示骰子将具有的面数。将sides设置为 6。
class Dice {
var sides = 6
}
大功告成。现在,您有了一个表示骰子的非常简单的类。
创建 Dice 类的实例
有了这个 Dice 类,您就有了表示骰子的蓝图。为了在程序中呈现出一个真实的骰子,您需要创建一个 Dice 对象实例。(如果您需要有三个骰子,就要创建三个对象实例。)

- 为了创建
Dice的对象实例,请在main()函数中创建一个名为myFirstDice的val,并将其初始化为Dice类的实例。请注意类名称后面的括号,其表示您在通过该类创建一个新的对象实例。
fun main() {
val myFirstDice = Dice()
}
现在,您已经有了依据蓝图构建的 myFirstDice 对象,接下来可以访问其属性了。Dice 的唯一属性是其 sides。您使用“点分表示法”访问属性。因此,如需访问 myFirstDice 的 sides 属性,请调用 myFirstDice.sides,这读作“myFirstDice 点 sides”。
- 在
myFirstDice声明的下方,添加println()语句以输出myFirstDice.的sides数量。
注意: 您之前在调用 diceRange.random() 时已使用过点分表示法。概括地说,您可以将点分表示法理解为,“对点前面的对象执行点后面的操作”。例如此处,myFirstDice.sides 表示“获取该实例的 sides 属性”。
您的代码应如下所示。
fun main() {
val myFirstDice = Dice()
println(myFirstDice.sides)
}
class Dice {
var sides = 6
}
- 运行程序,它应输出在
Dice类中定义的sides的数量。
6
现在,您有了一个 Dice 类和一个具有 6 个 sides 的真实骰子 myFirstDice。
我们来掷骰子吧!
掷骰子
您之前曾使用函数执行过输出蛋糕层的操作。掷骰子操作也可以用函数实现。由于所有骰子都可以滚动,因此您可以在 Dice 类中为其添加一个函数。在类中定义的函数也称为方法。
- 在
Dice类的sides变量下方,插入一个空行,然后创建一个用于掷骰子的新函数。首先输入 Kotlin 关键字fun,再输入方法的名称,然后是括号(),然后再是左大括号和右大括号{}。可以在大括号内留一个空行,以便输入更多代码,如下所示。您的类应如下所示。
class Dice {
var sides = 6
fun roll() {
}
}
注意: 您可以为该方法指定任意名称,但如果名称能指示要执行的操作,将会很有帮助。函数和方法的命名惯例是以小写字母开头,采用驼峰式大小写形式,尽可能以操作动词开头。
当您掷一个六面骰子时,它会产生一个从 1 到 6 的随机数字。
- 在
roll()方法中,创建一个val randomNumber。在1..6范围内为其分配一个随机数字。使用点分表示法对该范围调用random()。
val randomNumber = (1..6).random()
- 生成随机数字后,将其输出到控制台。完成后的
roll()方法应如以下代码所示。
fun roll() {
val randomNumber = (1..6).random()
println(randomNumber)
}
- 为了真实地滚动
myFirstDice,请在main()中对myFirstDice调用roll()方法。您使用“点分表示法”调用方法。因此,为了对myFirstDice调用roll()方法,请输入myFirstDice.roll(),这读作“myFirstDice点roll()”。
myFirstDice.roll()
完成后的代码应如下所示。
fun main() {
val myFirstDice = Dice()
println(myFirstDice.sides)
myFirstDice.roll()
}
class Dice {
var sides = 6
fun roll() {
val randomNumber = (1..6).random()
println(randomNumber)
}
}
- 运行代码!您应会看到随机掷骰子的结果小于骰子面数。多运行几次代码,会发现面数保持不变,掷骰子的结果值发生变化。
祝贺您!您已使用 sides 变量和 roll() 函数定义了 Dice 类。在 main() 函数中,您创建了一个新的 Dice 对象实例,然后对该实例调用了 roll() 方法,以生成随机数字。
6
4
祝贺您!您已使用 sides 变量和 roll() 函数定义了 Dice 类。在 main() 函数中,您创建了一个新的 Dice 对象实例,然后对该实例调用了 roll() 方法,以生成随机数字。
四、返回您掷骰子的结果值
您目前是在 roll() 函数中输出 randomNumber 的值,运行一切正常!但有时,将函数的结果返回给调用该函数的对象会更有用。例如,您可以将 roll() 方法的结果分配给某个变量,然后将玩家移动相应的步数!我们来看看具体操作方法。
- 在
main()中,修改显示myFirstDice.roll()的代码行。创建名为diceRoll的val。将其设置为与roll()方法返回的值相等。
val diceRoll = myFirstDice.roll()
目前还没有任何效果,因为 roll() 尚未返回任何内容。为了使上述代码按预期运行,roll() 必须返回一些内容。
在之前的章节中,您了解到需要为函数的输入参数指定数据类型。同样,您也必须为函数返回的数据指定数据类型。
- 更改
roll()函数以指定将返回的数据类型。在本例中,随机数字为Int,因此返回类型为Int。指定返回类型的语法如下:在函数名称后面,在括号后添加冒号、空格,然后为函数返回类型添加Int关键字。函数定义应如下代码所示。
fun roll(): Int {
- 运行该代码。您将在问题视图中看到一个错误。错误内容是:
A ‘return' expression required in a function with a block body (‘{
...}')
您将函数定义改为了返回 Int,但系统提示说您的代码实际上并未返回 Int。“块主体”或“函数主体”是指函数大括号内的代码。您可以修复此错误,方法是在函数主体末尾使用 return 语句从函数返回值。
- 在
roll()中,移除println()语句,并将其替换为randomNumber的return语句。您的roll()函数应如以下代码所示。
fun roll(): Int {
val randomNumber = (1..6).random()
return randomNumber
}
- 在
main()中,移除有关骰子面数的输出语句。 - 添加一个语句,用信息性句子输出
sides和diceRoll的值。您完成的main()函数应类似于以下代码。
fun main() {
val myFirstDice = Dice()
val diceRoll = myFirstDice.roll()
println("Your ${
myFirstDice.sides} sided dice rolled ${
diceRoll}!")
}
- 运行代码,输出应如下所示。
Your 6 sided dice rolled 4!
以下是到目前为止所编写的所有代码。
fun main() {
val myFirstDice = Dice()
val diceRoll = myFirstDice.roll()
println("Your ${
myFirstDice.sides} sided dice rolled ${
diceRoll}!")
}
class Dice {
var sides = 6
fun roll(): Int {
val randomNumber = (1..6).random()
return randomNumber
}
}
五、更改骰子的面数
并非所有骰子都有 6 个面!骰子形状各异,大小不一:有 4 面的、8 面的,还有 120 面的!
- 在
Dice类的roll()方法中,将硬编码的1..6更改为使用sides,这样,范围和掷出的随机数字将始终适用于面数。
val randomNumber = (1..sides).random()
- 在
main()函数中,在输出掷骰结果的后面,将myFirstDice的sides设置为 20。
myFirstDice.sides = 20
- 复制下面的现有输出语句并将其粘贴在更改面数的位置下方。
- 将
diceRoll的输出结果替换为对myFirstDice调用roll()方法的输出结果。
println("Your ${
myFirstDice.sides} sided dice rolled ${
myFirstDice.roll()}!")
您的程序应如下所示。
fun main() {
val myFirstDice = Dice()
val diceRoll = myFirstDice.roll()
println("Your ${
myFirstDice.sides} sided dice rolled ${
diceRoll}!")
myFirstDice.sides = 20
println("Your ${
myFirstDice.sides} sided dice rolled ${
myFirstDice.roll()}!")
}
class Dice {
var sides = 6
fun roll(): Int {
val randomNumber = (1..sides).random()
return randomNumber
}
}
- 运行程序,您应该会看到一条有关 6 面骰子的消息,以及另一条有关 20 面骰子的消息。
Your 6 sided dice rolled 5!
Your 20 sided dice rolled 2!
六、自定义骰子
类的概念是代表一个事物,通常是现实世界中的事物。在本例中,Dice 类代表实际的骰子。在现实世界中,骰子的面数是不会变的。如果您需要不同的面数,就需要使用不同的骰子。在编程上,这意味着您应该创建一个具有所需面数的新骰子对象实例,而不是更改现有 Dice 对象实例的面数属性。
在此任务中,您将修改 Dice 类,以便在创建新实例时指定面数。您将更改 Dice 类定义,以便可以提供面数。这类似于函数接受输入参数的方式。
- 修改
Dice类定义,以接受名为numSides的整数。类中的代码不变。
class Dice(val numSides: Int) {
// Code inside does not change.
}
- 在
Dice类中,删除sides变量,因为您现在可以使用numSides。 - 此外,修改范围以使用
numSides。
您的 Dice 类应如下所示。
class Dice (val numSides: Int) {
fun roll(): Int {
val randomNumber = (1..numSides).random()
return randomNumber
}
}
如果运行这段代码,您将看到大量错误,因为需要更新 main() 才能使用对 Dice 类的更改。
- 在
main()中,为了创建具有 6 个面的myFirstDice,您现在必须提供面数作为Dice类的参数,如下所示。
val myFirstDice = Dice(6)
- 在输出语句中,将
sides更改为numSides。 - 然后在下方,删除将
sides更改为 20 的代码, 因为该变量已不存在。 - 同时删除其下方的
println语句。
fun main() {
val myFirstDice = Dice(6)
val diceRoll = myFirstDice.roll()
println("Your ${
myFirstDice.numSides} sided dice rolled ${
diceRoll}!")
}
- 输出第一个掷骰结果后,添加代码以创建并输出第二个名为
mySecondDice的Dice对象,其具有 20 个面。
val mySecondDice = Dice(20)
- 添加用于掷骰并输出返回值的输出语句。
println("Your ${
mySecondDice.numSides} sided dice rolled ${
mySecondDice.roll()}!")
- 完成后的 main() 函数应如下所示。
fun main() {
val myFirstDice = Dice(6)
val diceRoll = myFirstDice.roll()
println("Your ${
myFirstDice.numSides} sided dice rolled ${
diceRoll}!")
val mySecondDice = Dice(20)
println("Your ${
mySecondDice.numSides} sided dice rolled ${
mySecondDice.roll()}!")
}
class Dice (val numSides: Int) {
fun roll(): Int {
val randomNumber = (1..numSides).random()
return randomNumber
}
}
- 运行已完成的程序,输出内容应如下所示。
Your 6 sided dice rolled 3!
Your 20 sided dice rolled 7!
七、采用规范的编码做法
编写代码时,应尽量简洁。您可以去掉 randomNumber 变量并直接返回随机数字。
- 更改
return语句以直接返回随机数字。
fun roll(): Int {
return (1..numSides).random()
}
在第二个输出语句中,您将用于获取随机数的调用放入字符串模板。您可以按照在第一个输出语句中采用的相同方法来去掉 diceRoll 变量。
- 在字符串模板中调用
myFirstDice.roll()并删除diceRoll变量。您的main()代码的前两行现在如下所示。
val myFirstDice = Dice(6)
println("Your ${
myFirstDice.numSides} sided dice rolled ${
myFirstDice.roll()}!")
- 运行代码,输出内容应该没有变化。
注意: 更改代码使其更简洁、高效或易于阅读和理解称为“重构”。这就像写一篇文章,先写一份包含所有信息的初稿,然后再对文字进行修改和提炼。
以下是您重构后的最终代码。
fun main() {
val myFirstDice = Dice(6)
println("Your ${
myFirstDice.numSides} sided dice rolled ${
myFirstDice.roll()}!")
val mySecondDice = Dice(20)
println("Your ${
mySecondDice.numSides} sided dice rolled ${
mySecondDice.roll()}!")
}
class Dice (val numSides: Int) {
fun roll(): Int {
return (1..numSides).random()
}
}
八、解决方案代码
fun main() {
val myFirstDice = Dice(6)
println("Your ${
myFirstDice.numSides} sided dice rolled ${
myFirstDice.roll()}!")
val mySecondDice = Dice(20)
println("Your ${
mySecondDice.numSides} sided dice rolled ${
mySecondDice.roll()}!")
}
class Dice (val numSides: Int) {
fun roll(): Int {
return (1..numSides).random()
}
}
九、总结
- 对
IntRange调用random()函数以生成随机数字:(1..6).random() - 类就像是对象的蓝图。它们可以具有作为变量和函数实现的属性和行为。
- 类的实例代表对象,通常是实物,如骰子。可以调用针对对象的操作并更改其属性。
- 创建实例时,可以向类提供值。例如:创建
class Dice(val numSides: Int),然后通过Dice(6)创建实例。 - 函数可以返回一些内容。可以在函数定义中指定要返回的数据类型,并在函数正文中使用 return 语句来返回内容。例如:
fun example(): Int { return 5 }
十、了解详情
十一、自行练习
注意: 可视需要进行练习。您可以借此机会练习您在此 Codelab 中学到的知识。
进行以下练习:
- 为
Dice类指定另一种颜色属
性,并创建多个具有不同面数和颜色的实例! - 创建
Coin类,使其能够翻转,创建该类的实例,并抛掷多个硬币!您将如何将random()
函数与范围结合使用来实现硬币的抛掷?
边栏推荐
- There are a group of students in the class who have got the test results in Chinese and mathematics. Please select the students whose total score is the first
- Opencv报错:(parameter or structure field))Unrecognized or unsupported array type in functon ‘cvGetMat‘
- 复制列表时踩过的坑:浅拷贝与深拷贝
- LeetCode·每日一题·919.完全二叉树插入器·层次遍历·BFS
- Managing databases in a hybrid cloud: eight key considerations
- Hcip day 8 notes sorting (OSPF routing control, Appendix E, anti ring, shortest path calculation, republication))
- 【尤里复裂人】带你轻松理解——深拷贝和浅拷贝
- LoRa和NB-IOT可用用在哪些地方
- Use Anaconda to configure the tensorflow of GPU Version (less than 30 series graphics cards)
- Continuous delivery and Devops are good friends
猜你喜欢

Installation and operation of orb-slam2 under ROS

Istio三之VirtualService、Gateway、DestinationRule配置使用

QT notes - temporary floating window
![[untitled]](/img/6f/a2cd98af7a8de469e5311422b48afe.png)
[untitled]

STM - exti external interrupt learning notes

Swin Transformer【Backbone】

Cloud native guide what is cloud native infrastructure

URDF 语法详解

称霸薪酬榜!什么行业大有“钱”途?

Win11大小写提示图标怎么关闭?Win11大小写提示图标的关闭方法
随机推荐
Continuous delivery and Devops are good friends
Jsd-2204-cool shark Mall (Management Commodity module) -day02
snownlp库各功能及用法
Summary of Huawei virtualization fusioncompute knowledge points
STM32 - DMA notes
LeetCode·
STM32——PWM学习笔记
Opencv 以指定格式保存图片
万维网、因特网和互联网的区别
78. 子集
[sql] usage of self connection
ES6 set and map
Istio三之VirtualService、Gateway、DestinationRule配置使用
Opencv saves pictures in the specified format
[STL]优先级队列priority_queue
tensorflow中tf.Variable()函数的用法
QT signal transmission between multi-level objects signal transmission between multi-level nested class objects
Chen Yili, China Academy of communications technology: cost reduction and efficiency increase are the greatest value of Enterprise Cloud native applications
LeetCode·
Dataframe sorting: datetime format splitting; Delete a specific line; Group integration.