Lớp học lập trình này nằm trong khóa học về Kotlin dành cho lập trình viên. Bạn sẽ nhận được nhiều giá trị nhất từ khóa học này nếu bạn làm việc qua các lớp học lập trình theo trình tự. Tùy thuộc vào kiến thức của mình, bạn có thể đọc lướt một số phần. Khóa học này dành cho những lập trình viên biết ngôn ngữ hướng đối tượng và muốn học Kotlin.
Giới thiệu
Trong lớp học lập trình này, bạn tạo một chương trình trong Kotlin và tìm hiểu về các lớp và đối tượng trong Kotlin. Phần lớn nội dung này sẽ quen thuộc với bạn nếu bạn biết một ngôn ngữ khác hướng đối tượng, nhưng Kotlin có một số điểm khác biệt quan trọng để giảm lượng mã bạn cần viết. Bạn cũng sẽ tìm hiểu về lớp trừu tượng và hoạt động ủy quyền giao diện.
Thay vì xây dựng một ứng dụng mẫu duy nhất, các bài học trong khóa học này được thiết kế để trang bị cho bạn kiến thức nhưng hãy độc lập với nhau để có thể đọc lướt các phần mà bạn quen thuộc. Nhiều ví dụ sử dụng chủ đề thủy cung để liên kết chúng với nhau. Và nếu bạn muốn xem toàn bộ câu chuyện về thủy cung, hãy xem khóa học Kotlin Bootcamp dành cho lập trình viên Udacity.
Kiến thức bạn cần có
- Khái niệm cơ bản về Kotlin, bao gồm cả các loại, toán tử và vòng lặp
- Cú pháp hàm của Kotlin\39;s
- Kiến thức cơ bản về lập trình hướng đối tượng
- Các khái niệm cơ bản về IDE như IntelliJ IDEA hoặc Android Studio
Kiến thức bạn sẽ học được
- Cách tạo lớp và truy cập vào các thuộc tính trong Kotlin
- Cách tạo và sử dụng các hàm dựng lớp trong Kotlin
- Cách tạo lớp con và cách tính năng kế thừa hoạt động
- Giới thiệu về lớp trừu tượng, giao diện và ủy quyền giao diện
- Cách tạo và sử dụng lớp dữ liệu
- Cách sử dụng singleton, enum và các lớp được đóng kín
Bạn sẽ thực hiện
- Tạo một lớp có thuộc tính
- Tạo một hàm dựng cho một lớp
- Tạo lớp con
- Xem ví dụ về các lớp và giao diện trừu tượng
- Tạo một lớp dữ liệu đơn giản
- Tìm hiểu về singleton, enum và các lớp được đóng dấu
Những thuật ngữ lập trình sau đây chắc hẳn đã quen thuộc với bạn:
- Lớp là sơ đồ thiết kế của các đối tượng. Ví dụ: lớp
Aquarium
là sơ đồ thiết kế để tạo một đối tượng bể cá. - Đối tượng là các thực thể của lớp; đối tượng trong bể cá là một thực tế trong
Aquarium
. - Tài sản là các đặc điểm của lớp, chẳng hạn như độ dài, chiều rộng và chiều cao của
Aquarium
. - Phương thức, còn được gọi là hàm thành viên, là chức năng của lớp. Phương pháp là việc bạn có thể "do" với đối tượng. Ví dụ: bạn có thể
fillWithWater()
một đối tượngAquarium
. - Giao diện là thông số kỹ thuật mà một lớp có thể triển khai. Ví dụ: việc vệ sinh thường là đối với các đồ vật khác ngoài thủy cung và việc vệ sinh thường diễn ra tương tự như đối với những đồ vật khác. Vì vậy, bạn có thể có một giao diện có tên là
Clean
để xác định phương thứcclean()
. LớpAquarium
có thể triển khai giao diệnClean
để làm sạch bể cá bằng một miếng bọt biển mềm. - Gói là một cách để nhóm các mã có liên quan nhằm sắp xếp mã hoặc tạo một thư viện mã. Sau khi tạo gói, bạn có thể nhập nội dung của gói vào một tệp khác và sử dụng lại mã cũng như lớp học trong gói.
Trong nhiệm vụ này, bạn tạo một gói mới và một lớp có một số thuộc tính và phương thức.
Bước 1: Tạo gói
Các gói có thể giúp bạn sắp xếp mã gọn gàng.
- Trong ngăn Dự án, bên dưới dự án Hello Kotlin, hãy nhấp chuột phải vào thư mục src.
- Chọn New > Package và gọi gói này là
example.myapp
.
Bước 2: Tạo một lớp có thuộc tính
Lớp được xác định bằng từ khóa class
và tên lớp theo quy ước bắt đầu bằng chữ hoa.
- Nhấp chuột phải vào gói example.myapp.
- Chọn New > Kotlin File / class.
- Trong phần Loại, hãy chọn Lớp học rồi đặt tên cho lớp đó
Aquarium
. IntelliJ IDEA đưa tên gói vào tệp và tạo một lớpAquarium
trống cho bạn. - Bên trong lớp
Aquarium
, hãy xác định và khởi chạy các thuộc tínhvar
cho chiều rộng, chiều cao và chiều dài (tính bằng cm). Khởi chạy các thuộc tính có giá trị mặc định.
package example.myapp
class Aquarium {
var width: Int = 20
var height: Int = 40
var length: Int = 100
}
Về cơ bản, Kotlin sẽ tự động tạo các phương thức getter và setter cho các thuộc tính mà bạn đã xác định trong lớp Aquarium
, nhờ đó, bạn có thể truy cập trực tiếp vào các thuộc tính, ví dụ: myAquarium.length
.
Bước 3: Tạo một hàm main()
Tạo một tệp mới có tên là main.kt
để giữ hàm main()
.
- Trong ngăn Dự án ở bên trái, hãy nhấp chuột phải vào gói example.myapp.
- Chọn New > Kotlin File / class.
- Trong trình đơn thả xuống Loại, hãy giữ lựa chọn là Tệp và đặt tên tệp là
main.kt
. IntelliJ IDEA có tên gói nhưng không bao gồm định nghĩa lớp cho một tệp. - Xác định hàm
buildAquarium()
và bên trong tạo một thực thể củaAquarium
. Để tạo một thực thể, hãy tham chiếu đến lớp như thể đó là một hàm,Aquarium()
. Thao tác này sẽ gọi hàm dựng của lớp và tạo một thực thể của lớpAquarium
, tương tự như việc sử dụngnew
trong các ngôn ngữ khác. - Xác định hàm
main()
và gọibuildAquarium()
.
package example.myapp
fun buildAquarium() {
val myAquarium = Aquarium()
}
fun main() {
buildAquarium()
}
Bước 4: Thêm phương thức
- Trong lớp
Aquarium
, hãy thêm một phương thức để in thuộc tính kích thước của thủy cung.
fun printSize() {
println("Width: $width cm " +
"Length: $length cm " +
"Height: $height cm ")
}
- Trong
main.kt
, trongbuildAquarium()
, hãy gọi phương thứcprintSize()
trênmyAquarium
.
fun buildAquarium() {
val myAquarium = Aquarium()
myAquarium.printSize()
}
- Chạy chương trình bằng cách nhấp vào hình tam giác màu xanh lục bên cạnh hàm
main()
. Quan sát kết quả.
⇒ Width: 20 cm Length: 100 cm Height: 40 cm
- Trong
buildAquarium()
, hãy thêm mã để đặt chiều cao thành 60 và in các thuộc tính kích thước đã thay đổi.
fun buildAquarium() {
val myAquarium = Aquarium()
myAquarium.printSize()
myAquarium.height = 60
myAquarium.printSize()
}
- Chạy chương trình và quan sát kết quả.
⇒ Width: 20 cm Length: 100 cm Height: 40 cm Width: 20 cm Length: 100 cm Height: 60 cm
Trong nhiệm vụ này, bạn tạo một hàm dựng cho lớp và tiếp tục làm việc với các thuộc tính.
Bước 1: Tạo hàm dựng
Trong bước này, bạn thêm một hàm dựng vào lớp Aquarium
mà bạn đã tạo trong việc cần làm đầu tiên. Trong ví dụ trước đó, mọi bản sao của Aquarium
đều được tạo với cùng phương diện. Bạn có thể thay đổi thứ nguyên sau khi tạo nó bằng cách đặt các thuộc tính, nhưng sẽ dễ dàng hơn để tạo kích thước chính xác để bắt đầu.
Trong một số ngôn ngữ lập trình, hàm dựng được xác định bằng cách tạo một phương thức trong lớp có cùng tên với lớp. Trong Kotlin, bạn xác định hàm dựng ngay trong phần khai báo lớp, chỉ định các tham số bên trong dấu ngoặc đơn như thể lớp đó là một phương thức. Giống như các hàm trong Kotlin, các thông số đó có thể bao gồm giá trị mặc định.
- Trong lớp
Aquarium
mà bạn đã tạo trước đó, hãy thay đổi định nghĩa lớp để thêm 3 thông số hàm dựng có giá trị mặc định cholength
,width
vàheight
, rồi gán cho các thuộc tính đó tương ứng.
class Aquarium(length: Int = 100, width: Int = 20, height: Int = 40) {
// Dimensions in cm
var length: Int = length
var width: Int = width
var height: Int = height
...
}
- Cách viết gọn hơn của Kotlin là xác định các thuộc tính trực tiếp với hàm dựng, sử dụng
var
hoặcval
, còn Kotlin cũng tự động tạo các phương thức getter và setter. Sau đó, bạn có thể xóa các định nghĩa thuộc tính trong phần nội dung của lớp.
class Aquarium(var length: Int = 100, var width: Int = 20, var height: Int = 40) {
...
}
- Khi tạo một đối tượng
Aquarium
bằng hàm dựng đó, bạn có thể chỉ định không có đối số nào và nhận giá trị mặc định, hoặc chỉ chỉ định một số đối số trong số đó hoặc chỉ định tất cả đối số và tạo mộtAquarium
có kích thước hoàn toàn tùy chỉnh. Trong hàmbuildAquarium()
, hãy thử các cách tạo đối tượngAquarium
bằng cách sử dụng các tham số có tên.
fun buildAquarium() {
val aquarium1 = Aquarium()
aquarium1.printSize()
// default height and length
val aquarium2 = Aquarium(width = 25)
aquarium2.printSize()
// default width
val aquarium3 = Aquarium(height = 35, length = 110)
aquarium3.printSize()
// everything custom
val aquarium4 = Aquarium(width = 25, height = 35, length = 110)
aquarium4.printSize()
}
- Chạy chương trình và quan sát kết quả.
⇒ Width: 20 cm Length: 100 cm Height: 40 cm Width: 25 cm Length: 100 cm Height: 40 cm Width: 20 cm Length: 110 cm Height: 35 cm Width: 25 cm Length: 110 cm Height: 35 cm
Xin lưu ý rằng bạn không phải làm quá tải hàm dựng và viết một phiên bản khác cho mỗi trường hợp này (cộng thêm một vài hàm cho các tổ hợp khác). Kotlin tạo những gì cần thiết từ các giá trị mặc định và các thông số đã đặt tên.
Bước 2: Thêm khối init
Các hàm dựng mẫu ở trên chỉ khai báo thuộc tính và chỉ định giá trị của một biểu thức cho chúng. Nếu hàm dựng của bạn cần thêm mã khởi tạo, thì bạn có thể đặt hàm dựng đó trong một hoặc nhiều khối init
. Trong bước này, bạn thêm một số khối init
vào lớp Aquarium
.
- Trong lớp
Aquarium
, hãy thêm một khốiinit
để in rằng đối tượng đang khởi tạo và khối thứ hai để in thể tích theo lít.
class Aquarium (var length: Int = 100, var width: Int = 20, var height: Int = 40) {
init {
println("aquarium initializing")
}
init {
// 1 liter = 1000 cm^3
println("Volume: ${width * length * height / 1000} l")
}
}
- Chạy chương trình và quan sát kết quả.
aquarium initializing
Volume: 80 l
Width: 20 cm Length: 100 cm Height: 40 cm
aquarium initializing
Volume: 100 l
Width: 25 cm Length: 100 cm Height: 40 cm
aquarium initializing
Volume: 77 l
Width: 20 cm Length: 110 cm Height: 35 cm
aquarium initializing
Volume: 96 l
Width: 25 cm Length: 110 cm Height: 35 cm
Xin lưu ý rằng các khối init
được thực thi theo thứ tự xuất hiện trong định nghĩa lớp, và tất cả các khối này được thực thi khi hàm dựng được gọi.
Bước 3: Tìm hiểu về hàm dựng phụ
Ở bước này, bạn sẽ tìm hiểu về các hàm dựng phụ và thêm một hàm dựng vào lớp của mình. Ngoài một hàm dựng chính, có thể có một hoặc nhiều khối init
, một lớp Kotlin cũng có thể có một hoặc nhiều hàm dựng phụ để cho phép hàm dựng quá tải, tức là các hàm dựng có đối số khác nhau.
- Trong lớp
Aquarium
, hãy thêm một hàm dựng phụ lấy một số loại cá làm đối số, sử dụng từ khóaconstructor
. Tạo một thuộc tính bểval
cho thể tích bể cá tính theo lít dựa trên số lượng cá. Giả định 2 lít nước (2.000 cm^3) nước trên mỗi con cá, cộng thêm một khoảng trống nhỏ để nước không bị tràn.
constructor(numberOfFish: Int) : this() {
// 2,000 cm^3 per fish + extra room so water doesn't spill
val tank = numberOfFish * 2000 * 1.1
}
- Bên trong hàm dựng phụ, hãy giữ nguyên chiều dài và chiều rộng (đã đặt trong hàm dựng chính) và tính toán chiều cao cần thiết để đặt thùng chứa thể tích đã cho.
// calculate the height needed
height = (tank / (length * width)).toInt()
- Trong hàm
buildAquarium()
, hãy thêm lệnh gọi để tạoAquarium
bằng cách sử dụng hàm dựng phụ mới. In kích thước và thể tích.
fun buildAquarium() {
val aquarium6 = Aquarium(numberOfFish = 29)
aquarium6.printSize()
println("Volume: ${aquarium6.width * aquarium6.length * aquarium6.height / 1000} l")
}
- Chạy chương trình và quan sát kết quả.
⇒ aquarium initializing Volume: 80 l Width: 20 cm Length: 100 cm Height: 31 cm Volume: 62 l
Xin lưu ý rằng khối lượng này sẽ được in hai lần, một lần bằng khối init
trong hàm dựng chính trước khi hàm dựng phụ được thực thi và một lần bằng mã trong buildAquarium()
.
Bạn cũng có thể đưa từ khóa constructor
vào hàm dựng chính, nhưng bạn không cần dùng từ khóa này trong hầu hết các trường hợp.
Bước 4: Thêm phương thức getter cho thuộc tính mới
Trong bước này, bạn sẽ thêm một phương thức getter của thuộc tính rõ ràng. Kotlin tự động xác định phương thức getter và setter khi bạn xác định các thuộc tính, nhưng đôi khi cần điều chỉnh hoặc tính toán giá trị của một thuộc tính. Ví dụ: bạn đã in tập của Aquarium
. Bạn có thể cung cấp khối lượng dưới dạng tài sản bằng cách xác định một biến và phương thức getter cho biến đó. Vì volume
cần được tính toán, phương thức getter cần trả về giá trị đã tính, mà bạn có thể thực hiện bằng hàm một dòng.
- Trong lớp
Aquarium
, hãy xác định một thuộc tínhInt
có tên làvolume
và xác định phương thứcget()
để tính khối lượng trong dòng tiếp theo.
val volume: Int
get() = width * height * length / 1000 // 1000 cm^3 = 1 l
- Xóa khối
init
in ra âm lượng. - Xóa mã trong
buildAquarium()
sẽ in âm lượng. - Trong phương thức
printSize()
, hãy thêm một dòng để in âm lượng.
fun printSize() {
println("Width: $width cm " +
"Length: $length cm " +
"Height: $height cm "
)
// 1 l = 1000 cm^3
println("Volume: $volume l")
}
- Chạy chương trình và quan sát kết quả.
⇒ aquarium initializing Width: 20 cm Length: 100 cm Height: 31 cm Volume: 62 l
Kích thước và thể tích giống như trước, nhưng thể tích chỉ được in một lần sau khi đối tượng được khởi tạo hoàn toàn bằng cả hàm dựng chính và hàm dựng phụ.
Bước 5: Thêm phương thức setter thuộc tính
Trong bước này, bạn sẽ tạo một phương thức setter mới cho khối lượng.
- Trong lớp
Aquarium
, hãy thay đổi giá trị củavolume
thànhvar
để có thể đặt giá trị này nhiều lần. - Thêm một phương thức setter cho thuộc tính
volume
bằng cách thêm phương thứcset()
bên dưới phương thức getter. Phương thức này sẽ tính toán lại chiều cao dựa trên lượng nước đã cung cấp. Theo quy ước, tên của thông số setter làvalue
, nhưng bạn có thể thay đổi thông số này nếu muốn.
var volume: Int
get() = width * height * length / 1000
set(value) {
height = (value * 1000) / (width * length)
}
- Trong
buildAquarium()
, hãy thêm mã để đặt thể tích của Thủy cung là 70 lít. In kích thước mới.
fun buildAquarium() {
val aquarium6 = Aquarium(numberOfFish = 29)
aquarium6.printSize()
aquarium6.volume = 70
aquarium6.printSize()
}
- Chạy lại chương trình của bạn và quan sát chiều cao và âm lượng đã thay đổi.
⇒ aquarium initialized
Width: 20 cm Length: 100 cm Height: 31 cm
Volume: 62 l
Width: 20 cm Length: 100 cm Height: 35 cm
Volume: 70 l
Không có công cụ sửa đổi hiển thị nào, chẳng hạn như public
hoặc private
, trong mã cho đến nay. Lý do là: theo mặc định, mọi thứ trong Kotlin đều ở chế độ công khai, nghĩa là mọi thứ đều có thể truy cập được ở mọi nơi, bao gồm cả lớp, phương thức, thuộc tính và biến thành viên.
Trong Kotlin, các lớp, đối tượng, giao diện, hàm dựng, hàm, thuộc tính và phương thức setter có thể có những từ khóa công cụ sửa đổi chế độ hiển thị:
public
có nghĩa là có thể nhìn thấy bên ngoài lớp. Mọi thứ đều ở chế độ công khai theo mặc định, bao gồm cả các biến và phương thức của lớp.internal
có nghĩa là bộ lọc sẽ chỉ hiển thị trong học phần đó. Mô-đun là một tập hợp các tệp Kotlin được biên dịch cùng nhau, ví dụ: một thư viện hoặc ứng dụng.private
có nghĩa là tệp sẽ chỉ hiển thị trong lớp đó (hoặc tệp nguồn nếu bạn đang làm việc với các hàm).protected
giống vớiprivate
, nhưng cũng sẽ hiển thị với mọi lớp con.
Xem Công cụ sửa đổi chế độ hiển thị trong tài liệu về Kotlin để biết thêm thông tin.
Biến thành viên
Các thuộc tính trong một lớp hoặc biến thành phần là public
theo mặc định. Nếu bạn xác định các thuộc tính này bằng var
, thì chúng có thể thay đổi, tức là dễ đọc và có thể ghi. Nếu bạn xác định các thuộc tính này bằng val
, chúng sẽ chỉ đọc sau khi khởi tạo.
Nếu bạn muốn chỉ định hoặc đọc mã thuộc tính, nhưng mã bên ngoài chỉ có thể đọc, thì bạn có thể để thuộc tính và phương thức getter là công khai và khai báo phương thức setter ở chế độ riêng tư, như được hiển thị bên dưới.
var volume: Int
get() = width * height * length / 1000
private set(value) {
height = (value * 1000) / (width * length)
}
Trong nhiệm vụ này, bạn sẽ tìm hiểu cách hoạt động của lớp con và tính kế thừa trong Kotlin. Những ngôn ngữ này tương tự như những gì bạn đã thấy trong các ngôn ngữ khác, nhưng có một số điểm khác biệt.
Trong Kotlin, theo mặc định, các lớp không thể phân lớp con. Tương tự, bạn không thể ghi đè các biến thuộc tính và thành phần bằng các lớp con (mặc dù chúng có thể được truy cập).
Bạn phải đánh dấu một lớp là open
để cho phép phân lớp con đó. Tương tự, bạn phải đánh dấu các thuộc tính và biến thành phần là open
để ghi đè các biến đó trong lớp con. Cần có từ khóa open
để ngăn việc vô tình làm rò rỉ thông tin triển khai trong giao diện của lớp học.
Bước 1: Đặt lớp học cho Thủy cung mở
Trong bước này, bạn tạo Aquarium
lớp open
để có thể ghi đè lớp này ở bước tiếp theo.
- Đánh dấu lớp
Aquarium
và tất cả thuộc tính của lớp đó bằng từ khóaopen
.
open class Aquarium (open var length: Int = 100, open var width: Int = 20, open var height: Int = 40) {
open var volume: Int
get() = width * height * length / 1000
set(value) {
height = (value * 1000) / (width * length)
}
- Thêm một thuộc tính
shape
đang mở có giá trị"rectangle"
.
open val shape = "rectangle"
- Thêm một thuộc tính
water
đang mở có phương thức getter trả về 90% âm lượng củaAquarium
.
open var water: Double = 0.0
get() = volume * 0.9
- Thêm mã vào phương thức
printSize()
để in hình dạng và lượng nước dưới dạng phần trăm thể tích.
fun printSize() {
println(shape)
println("Width: $width cm " +
"Length: $length cm " +
"Height: $height cm ")
// 1 l = 1000 cm^3
println("Volume: $volume l Water: $water l (${water/volume*100.0}% full)")
}
- Trong
buildAquarium()
, hãy thay đổi mã để tạoAquarium
bằngwidth = 25
,length = 25
vàheight = 40
.
fun buildAquarium() {
val aquarium6 = Aquarium(length = 25, width = 25, height = 40)
aquarium6.printSize()
}
- Chạy chương trình và quan sát kết quả mới.
⇒ aquarium initializing rectangle Width: 25 cm Length: 25 cm Height: 40 cm Volume: 25 l Water: 22.5 l (90.0% full)
Bước 2: Tạo lớp con
- Tạo một lớp con của
Aquarium
có tên làTowerTank
. Lớp này sẽ triển khai một bể hình trụ tròn thay vì bể chứa hình chữ nhật. Bạn có thể thêmTowerTank
bên dướiAquarium
, vì bạn có thể thêm một lớp khác trong cùng tệp với lớpAquarium
. - Trong
TowerTank
, hãy ghi đè thuộc tínhheight
, đã được xác định trong hàm dựng. Để ghi đè một tài sản, hãy dùng từ khóaoverride
trong lớp con.
- Tạo hàm dựng cho
TowerTank
lấydiameter
. Dùngdiameter
cho cảlength
vàwidth
khi gọi hàm dựng trong lớp cao cấpAquarium
.
class TowerTank (override var height: Int, var diameter: Int): Aquarium(height = height, width = diameter, length = diameter) {
- Ghi đè thuộc tính thể tích để tính một hình trụ. Công thức của một hình trụ bằng pi nhân với bình phương của bán kính nhân với chiều cao. Bạn cần nhập hằng số
PI
từjava.lang.Math
.
override var volume: Int
// ellipse area = π * r1 * r2
get() = (width/2 * length/2 * height / 1000 * PI).toInt()
set(value) {
height = ((value * 1000 / PI) / (width/2 * length/2)).toInt()
}
- Trong
TowerTank
, hãy ghi đè thuộc tínhwater
thành 80% âm lượng.
override var water = volume * 0.8
- Ghi đè
shape
thành"cylinder"
.
override val shape = "cylinder"
- Lớp
TowerTank
cuối cùng của bạn phải có dạng như mã bên dưới.
Aquarium.kt
:
package example.myapp
import java.lang.Math.PI
... // existing Aquarium class
class TowerTank (override var height: Int, var diameter: Int): Aquarium(height = height, width = diameter, length = diameter) {
override var volume: Int
// ellipse area = π * r1 * r2
get() = (width/2 * length/2 * height / 1000 * PI).toInt()
set(value) {
height = ((value * 1000 / PI) / (width/2 * length/2)).toInt()
}
override var water = volume * 0.8
override val shape = "cylinder"
}
- Trong
buildAquarium()
, hãy tạo mộtTowerTank
có đường kính 25 cm và chiều cao là 45 cm. In kích thước.
main.kt:
package example.myapp
fun buildAquarium() {
val myAquarium = Aquarium(width = 25, length = 25, height = 40)
myAquarium.printSize()
val myTower = TowerTank(diameter = 25, height = 40)
myTower.printSize()
}
- Chạy chương trình và quan sát kết quả.
⇒ aquarium initializing rectangle Width: 25 cm Length: 25 cm Height: 40 cm Volume: 25 l Water: 22.5 l (90.0% full) aquarium initializing cylinder Width: 25 cm Length: 25 cm Height: 40 cm Volume: 18 l Water: 14.4 l (80.0% full)
Đôi khi bạn muốn xác định hành vi hoặc thuộc tính phổ biến để chia sẻ giữa một số lớp có liên quan. Kotlin cung cấp 2 cách để thực hiện việc đó, đó là giao diện và lớp trừu tượng. Trong nhiệm vụ này, bạn tạo một lớp AquariumFish
trừu tượng cho những thuộc tính phổ biến đối với tất cả cá. Bạn tạo một giao diện có tên là FishAction
để xác định hành vi chung cho tất cả các loại cá.
- Cả lớp trừu tượng lẫn giao diện đều không thể tạo thực thể của riêng nó, điều đó có nghĩa là bạn không thể tạo trực tiếp đối tượng của những loại đó.
- Lớp trừu tượng có hàm dựng.
- Các giao diện không được có logic logic hoặc lưu bất kỳ trạng thái nào.
Bước 1. Tạo một lớp trừu tượng
- Trong phần example.myapp, hãy tạo một tệp mới,
AquariumFish.kt
. - Tạo một lớp, còn gọi là
AquariumFish
và đánh dấu lớp đó bằngabstract
. - Hãy thêm một thuộc tính
String
,color
và đánh dấu thuộc tính đó bằngabstract
.
package example.myapp
abstract class AquariumFish {
abstract val color: String
}
- Tạo hai lớp con là
AquariumFish
,Shark
vàPlecostomus
. - Vì
color
là trừu tượng, các lớp con phải triển khai hàm này. ĐặtShark
màu xám vàPlecostomus
vàng.
class Shark: AquariumFish() {
override val color = "gray"
}
class Plecostomus: AquariumFish() {
override val color = "gold"
}
- Trong tệp main.kt, hãy tạo một hàm
makeFish()
để kiểm tra các lớp học của bạn. Hãy tạo bản sao choShark
vàPlecostomus
, sau đó in màu của từng bản xem trước. - Xóa mã thử nghiệm trước đó của bạn trong
main()
và thêm cuộc gọi vàomakeFish()
. Mã của bạn phải trông giống như mã bên dưới.
main.kt
:
package example.myapp
fun makeFish() {
val shark = Shark()
val pleco = Plecostomus()
println("Shark: ${shark.color}")
println("Plecostomus: ${pleco.color}")
}
fun main () {
makeFish()
}
- Chạy chương trình và quan sát kết quả.
⇒ Shark: gray Plecostomus: gold
Sơ đồ dưới đây biểu thị lớp Shark
và lớp Plecostomus
, các lớp này phân lớp con cho lớp trừu tượng, AquariumFish
.
Bước 2. Tạo giao diện
- Trong AquariumFish.kt, hãy tạo một giao diện có tên là
FishAction
bằng phương thứceat()
.
interface FishAction {
fun eat()
}
- Thêm
FishAction
vào từng lớp con và triển khaieat()
bằng cách cho phép máy in thực hiện chức năng của cá.
class Shark: AquariumFish(), FishAction {
override val color = "gray"
override fun eat() {
println("hunt and eat fish")
}
}
class Plecostomus: AquariumFish(), FishAction {
override val color = "gold"
override fun eat() {
println("eat algae")
}
}
- Trong hàm
makeFish()
, hãy yêu cầu từng con cá bạn tạo ra ăn thứ gì đó bằng cách gọieat()
.
fun makeFish() {
val shark = Shark()
val pleco = Plecostomus()
println("Shark: ${shark.color}")
shark.eat()
println("Plecostomus: ${pleco.color}")
pleco.eat()
}
- Chạy chương trình và quan sát kết quả.
⇒ Shark: gray hunt and eat fish Plecostomus: gold eat algae
Sơ đồ dưới đây đại diện cho lớp Shark
và lớp Plecostomus
, cả hai đều bao gồm và triển khai giao diện FishAction
.
Trường hợp sử dụng lớp trừu tượng so với giao diện
Các ví dụ ở trên rất đơn giản, nhưng khi bạn có nhiều lớp liên quan, lớp và giao diện trừu tượng có thể giúp bạn thiết kế gọn gàng, ngăn nắp và dễ bảo trì hơn.
Như đã lưu ý ở trên, các lớp trừu tượng có thể có các hàm dựng và giao diện không thể, nhưng nếu không thì các hàm này tương tự nhau. Vì vậy, khi nào bạn nên sử dụng tính năng này?
Khi bạn sử dụng giao diện để soạn lớp, chức năng của lớp được mở rộng thông qua các thực thể lớp có trong đó. Thành phần có xu hướng giúp việc sử dụng lại mã trở nên dễ dàng hơn và cho thấy lý do so với sự kế thừa từ một lớp trừu tượng. Ngoài ra, bạn có thể dùng nhiều giao diện trong một lớp nhưng chỉ có thể phân lớp con từ một lớp trừu tượng.
Thành phần thường dẫn đến khả năng đóng gói tốt hơn, kết nối thấp hơn (phụ thuộc), giao diện sạch hơn và mã dễ sử dụng hơn. Vì những lý do này, nên sử dụng bản sáng tác cùng với giao diện. Mặt khác, việc kế thừa từ một lớp trừu tượng có xu hướng phù hợp tự nhiên với một số vấn đề. Vì vậy, bạn nên ưu tiên bản sáng tác, nhưng khi việc kế thừa có ý nghĩa thì Kotlin cũng cho phép bạn làm điều đó!
- Hãy dùng một giao diện nếu bạn có nhiều phương thức và một hoặc hai cách triển khai mặc định, ví dụ như trong
AquariumAction
dưới đây.
interface AquariumAction {
fun eat()
fun jump()
fun clean()
fun catchFish()
fun swim() {
println("swim")
}
}
- Sử dụng lớp trừu tượng bất cứ khi nào bạn không thể hoàn tất lớp học. Ví dụ: quay trở lại lớp
AquariumFish
, bạn có thể thực hiện tất cảAquariumFish
triển khaiFishAction
và cung cấp cách triển khai mặc định choeat
trong khi vẫn đểcolor
trừu tượng, bởi vì thực sự không phải là màu mặc định cho cá.
interface FishAction {
fun eat()
}
abstract class AquariumFish: FishAction {
abstract val color: String
override fun eat() = println("yum")
}
Nhiệm vụ trước đó là giới thiệu các lớp học, giao diện và ý tưởng sáng tác. Ủy quyền giao diện là một kỹ thuật nâng cao, trong đó, phương thức của một giao diện được triển khai bởi đối tượng trợ giúp (hoặc ủy quyền), mà sau đó một lớp sẽ dùng. Kỹ thuật này có thể hữu ích khi bạn sử dụng giao diện trong một chuỗi các lớp không liên quan: bạn thêm chức năng giao diện cần thiết vào một lớp trình trợ giúp riêng và mỗi lớp sử dụng một bản sao của lớp trình trợ giúp để triển khai chức năng này.
Trong nhiệm vụ này, bạn dùng tính năng ủy quyền giao diện để thêm chức năng vào một lớp.
Bước 1: Tạo giao diện mới
- Trong AquariumFish.kt, hãy xóa lớp
AquariumFish
. Thay vì kế thừa từ lớpAquariumFish
,Plecostomus
vàShark
sẽ triển khai giao diện cho cả hành động cá và màu sắc của chúng. - Tạo giao diện mới,
FishColor
, xác định màu dưới dạng chuỗi.
interface FishColor {
val color: String
}
- Thay đổi
Plecostomus
để triển khai hai giao diện,FishAction
vàFishColor
. Bạn cần ghi đècolor
từFishColor
vàeat()
từFishAction
.
class Plecostomus: FishAction, FishColor {
override val color = "gold"
override fun eat() {
println("eat algae")
}
}
- Hãy thay đổi lớp
Shark
để triển khai cả hai giao diện làFishAction
vàFishColor
thay vì kế thừa từAquariumFish
.
class Shark: FishAction, FishColor {
override val color = "gray"
override fun eat() {
println("hunt and eat fish")
}
}
- Mã hoàn tất của bạn sẽ trông giống như sau:
package example.myapp
interface FishAction {
fun eat()
}
interface FishColor {
val color: String
}
class Plecostomus: FishAction, FishColor {
override val color = "gold"
override fun eat() {
println("eat algae")
}
}
class Shark: FishAction, FishColor {
override val color = "gray"
override fun eat() {
println("hunt and eat fish")
}
}
Bước 2: Tạo lớp singleton
Tiếp theo, bạn sẽ triển khai quá trình thiết lập cho phần ủy quyền bằng cách tạo một lớp trợ giúp sẽ triển khai FishColor
. Bạn tạo một lớp cơ bản có tên là GoldColor
. Lớp này triển khai FishColor
– tức là lớp chỉ có màu vàng.
Việc tạo nhiều phiên bản GoldColor
sẽ không hợp lý, vì tất cả đều hoạt động giống nhau. Vì vậy, Kotlin cho phép bạn khai báo một lớp mà ở đó bạn chỉ có thể tạo một phiên bản của lớp bằng cách sử dụng từ khóa object
thay vì class
. Kotlin sẽ tạo thực thể đó và thực thể đó được tham chiếu theo tên lớp. Sau đó, tất cả các đối tượng khác chỉ có thể sử dụng thực thể này – không có cách nào để tạo các thực thể khác của lớp này. Nếu bạn quen với mẫu singleton, thì đây là cách bạn triển khai singleton trong Kotlin.
- Trong AquariumFish.kt, hãy tạo một đối tượng cho
GoldColor
. Ghi đè màu.
object GoldColor : FishColor {
override val color = "gold"
}
Bước 3: Thêm ủy quyền giao diện cho FishColor
Bây giờ bạn đã sẵn sàng sử dụng ủy quyền giao diện.
- Trong tệp AquariumFish.kt, hãy xóa tùy chọn ghi đè
color
khỏiPlecostomus
. - Thay đổi lớp
Plecostomus
để nhận màu từGoldColor
. Bạn thực hiện việc này bằng cách thêmby GoldColor
vào phần khai báo lớp, tạo ủy quyền. Điều này có nghĩa là thay vì triển khaiFishColor
, hãy sử dụng phương thức triển khai doGoldColor
cung cấp. Vì vậy, mỗi lần truy cập vàocolor
, hệ thống sẽ ủy quyền choGoldColor
.
class Plecostomus: FishAction, FishColor by GoldColor {
override fun eat() {
println("eat algae")
}
}
Với lớp học như vậy, tất cả loài Plecos sẽ có màu vàng, nhưng những loài cá này thực sự có nhiều màu sắc. Bạn có thể giải quyết vấn đề này bằng cách thêm tham số hàm dựng cho màu, trong đó GoldColor
làm màu mặc định cho Plecostomus
.
- Thay đổi lớp
Plecostomus
để nhận đường dẫn trongfishColor
bằng hàm dựng, rồi đặt giá trị mặc định làGoldColor
. Thay đổi chế độ ủy quyền từby GoldColor
thànhby fishColor
.
class Plecostomus(fishColor: FishColor = GoldColor): FishAction,
FishColor by fishColor {
override fun eat() {
println("eat algae")
}
}
Bước 4: Thêm ủy quyền giao diện cho FishAction
Tương tự như vậy, bạn có thể dùng tính năng ủy quyền giao diện cho FishAction
.
- Trong AquariumFish.kt, hãy tạo một lớp
PrintingFishAction
triển khaiFishAction
, lớp này sẽ nhậnString
,food
, sau đó in những gì cá ăn.
class PrintingFishAction(val food: String) : FishAction {
override fun eat() {
println(food)
}
}
- Trong lớp
Plecostomus
, hãy xóa hàm ghi đèeat()
vì bạn sẽ thay thế hàm này bằng một thực thể đại diện. - Trong khai báo
Plecostomus
, hãy uỷ quyềnFishAction
choPrintingFishAction
, vượt qua"eat algae"
. - Với tất cả sự ủy quyền đó, sẽ không có mã nào trong phần nội dung của lớp
Plecostomus
, do đó, hãy xóa{}
vì mọi thao tác ghi đè đều được xử lý bằng việc ủy quyền giao diện
class Plecostomus (fishColor: FishColor = GoldColor):
FishAction by PrintingFishAction("eat algae"),
FishColor by fishColor
Sơ đồ dưới đây đại diện cho các lớp Shark
và Plecostomus
, cả hai đều bao gồm giao diện PrintingFishAction
và FishColor
, nhưng ủy quyền triển khai cho các lớp đó.
Việc ủy quyền giao diện rất hữu ích và bạn thường nên xem xét cách sử dụng tính năng này bất cứ khi nào có thể sử dụng lớp trừu tượng bằng một ngôn ngữ khác. Tính năng này cho phép bạn dùng bố cục để thêm các hành vi, thay vì yêu cầu nhiều lớp con, mỗi lớp con chuyên dùng theo một cách khác nhau.
Lớp dữ liệu tương tự như struct
trong một số ngôn ngữ khác – lớp này chủ yếu tồn tại để lưu một số dữ liệu, nhưng đối tượng lớp dữ liệu vẫn là một đối tượng. Các đối tượng lớp dữ liệu Kotlin có thêm một số lợi ích, chẳng hạn như tiện ích in và sao chép. Trong nhiệm vụ này, bạn tạo một lớp dữ liệu đơn giản và tìm hiểu về sự hỗ trợ mà Kotlin cung cấp cho các lớp dữ liệu.
Bước 1: Tạo một lớp dữ liệu
- Thêm một gói
decor
mới trong gói example.myapp để giữ mã mới. Nhấp chuột phải vào example.myapp trong ngăn Project rồi chọn File > New > Package. - Trong gói này, hãy tạo một lớp mới có tên là
Decoration
.
package example.myapp.decor
class Decoration {
}
- Để đặt
Decoration
làm lớp dữ liệu, hãy thêm từ khóadata
vào phần khai báo lớp. - Thêm một thuộc tính
String
có tên làrocks
để cung cấp cho lớp một số dữ liệu.
data class Decoration(val rocks: String) {
}
- Trong tệp, bên ngoài lớp, hãy thêm một hàm
makeDecorations()
để tạo và in một thực thể củaDecoration
bằng"granite"
.
fun makeDecorations() {
val decoration1 = Decoration("granite")
println(decoration1)
}
- Thêm một hàm
main()
để gọimakeDecorations()
và chạy chương trình của bạn. Lưu ý rằng kết quả hợp lệ được tạo vì đây là lớp dữ liệu.
⇒ Decoration(rocks=granite)
- Trong
makeDecorations()
, hãy tạo thêm 2 đối tượngDecoration
vừa là "slate" vừa in.
fun makeDecorations() {
val decoration1 = Decoration("granite")
println(decoration1)
val decoration2 = Decoration("slate")
println(decoration2)
val decoration3 = Decoration("slate")
println(decoration3)
}
- Trong
makeDecorations()
, hãy thêm một câu lệnh in để in kết quả so sánhdecoration1
vớidecoration2
và câu lệnh thứ hai so sánhdecoration3
vớidecoration2
. Dùng phương thức equals() do các lớp dữ liệu cung cấp.
println (decoration1.equals(decoration2))
println (decoration3.equals(decoration2))
- Chạy mã.
⇒ Decoration(rocks=granite) Decoration(rocks=slate) Decoration(rocks=slate) false true
Bước 2. Sử dụng cấu trúc phá hủy
Để nhận thuộc tính của một đối tượng dữ liệu và chỉ định các biến đó cho các biến, bạn có thể chỉ định từng biến thể như thế này.
val rock = decoration.rock
val wood = decoration.wood
val diver = decoration.diver
Thay vào đó, bạn có thể tạo các biến, mỗi biến cho một thuộc tính và chỉ định đối tượng dữ liệu cho nhóm biến. Kotlin đặt giá trị của thuộc tính vào mỗi biến.
val (rock, wood, diver) = decoration
Hành động này được gọi là hủy cấu trúc và là một cách rút gọn hữu ích. Số biến phải khớp với số thuộc tính và các biến được chỉ định theo thứ tự khai báo trong lớp. Dưới đây là một ví dụ hoàn chỉnh mà bạn có thể thử trong tệp Decoration.kt.
// Here is a data class with 3 properties.
data class Decoration2(val rocks: String, val wood: String, val diver: String){
}
fun makeDecorations() {
val d5 = Decoration2("crystal", "wood", "diver")
println(d5)
// Assign all properties to variables.
val (rock, wood, diver) = d5
println(rock)
println(wood)
println(diver)
}
⇒ Decoration2(rocks=crystal, wood=wood, diver=diver) crystal wood diver
Nếu không cần một hoặc nhiều thuộc tính, bạn có thể bỏ qua các thuộc tính đó bằng cách sử dụng _
thay vì tên biến, như hiển thị trong mã bên dưới.
val (rock, _, diver) = d5
Trong nhiệm vụ này, bạn sẽ tìm hiểu về một số lớp chuyên dụng trong Kotlin, bao gồm:
- Lớp học singleton
- Enum
- Lớp học kín
Bước 1: Nhắc lại các lớp singleton
Dùng lại lớp GoldColor
trong ví dụ trước.
object GoldColor : FishColor {
override val color = "gold"
}
Vì mọi thực thể của GoldColor
đều làm điều tương tự, nên thực thể đó được khai báo là object
thay vì class
để biến giá trị đó thành singleton. Chỉ có thể có một trường hợp.
Bước 2: Tạo một danh sách
Kotlin cũng hỗ trợ giá trị enum, cho phép bạn liệt kê thứ gì đó và tham chiếu đến tên đó theo tên, giống như trong các ngôn ngữ khác. Khai báo một giá trị enum bằng cách đặt tiền tố enum
cho từ khai báo. Việc khai báo liệt kê cơ bản chỉ cần một danh sách tên. Tuy nhiên, bạn cũng có thể xác định một hoặc nhiều trường liên kết với mỗi tên.
- Trong Decoration.kt, hãy thử một ví dụ về enum.
enum class Color(val rgb: Int) {
RED(0xFF0000), GREEN(0x00FF00), BLUE(0x0000FF);
}
Bảng liệt kê cũng giống một singleton, chỉ có thể có một và chỉ có một giá trị trong bảng liệt kê. Ví dụ: chỉ có thể có một Color.RED
, một Color.GREEN
và một Color.BLUE
. Trong ví dụ này, các giá trị RGB được gán cho thuộc tính rgb
để đại diện cho các thành phần màu. Bạn cũng có thể nhận giá trị thứ tự của một giá trị enum bằng thuộc tính ordinal
và tên của thuộc tính này bằng cách sử dụng thuộc tính name
.
- Hãy thử một ví dụ khác về enum.
enum class Direction(val degrees: Int) {
NORTH(0), SOUTH(180), EAST(90), WEST(270)
}
fun main() {
println(Direction.EAST.name)
println(Direction.EAST.ordinal)
println(Direction.EAST.degrees)
}
⇒ EAST 2 90
Bước 3: Tạo một lớp kín
Lớp được đóng dấu là một lớp có thể phân lớp con, nhưng chỉ bên trong tệp mà lớp đó được khai báo. Nếu cố gắng phân lớp con cho lớp trong một tệp khác, bạn sẽ gặp lỗi.
Vì các lớp và lớp con thuộc cùng một tệp, nên Kotlin sẽ biết tĩnh tất cả các lớp con. Đó là vào thời gian biên dịch, trình biên dịch xem tất cả các lớp và lớp con và biết rằng đây là tất cả lớp, vì vậy trình biên dịch có thể kiểm tra thêm cho bạn.
- Trong AquariumFish.kt, hãy thử một ví dụ về lớp học được đóng kín, theo chủ đề nước.
sealed class Seal
class SeaLion : Seal()
class Walrus : Seal()
fun matchSeal(seal: Seal): String {
return when(seal) {
is Walrus -> "walrus"
is SeaLion -> "sea lion"
}
}
Lớp Seal
không thể phân lớp con trong một tệp khác. Nếu muốn thêm các loại Seal
khác, bạn phải thêm các loại đó vào cùng một tệp. Điều này giúp các lớp bịt kín trở thành một cách an toàn để đại diện cho số lượng loại cố định. Ví dụ: các lớp kín rất phù hợp để trả về thành công hoặc lỗi từ API mạng.
Bài học này đề cập đến rất nhiều khía cạnh. Mặc dù phần lớn công cụ đó đã quen thuộc với các ngôn ngữ lập trình hướng đối tượng khác, nhưng Kotlin sẽ thêm một số tính năng để mã trở nên ngắn gọn và dễ đọc.
Lớp và hàm dựng
- Xác định một lớp trong Kotlin bằng cách dùng
class
. - Kotlin tự động tạo phương thức setter và getter cho các thuộc tính.
- Xác định hàm dựng chính ngay trong phần xác định lớp. Ví dụ:
class Aquarium(var length: Int = 100, var width: Int = 20, var height: Int = 40)
- Nếu một hàm dựng chính cần thêm mã, hãy viết mã đó trong một hoặc nhiều khối
init
. - Lớp có thể xác định một hoặc nhiều hàm dựng phụ bằng cách sử dụng
constructor
, nhưng kiểu Kotlin là dùng một hàm gốc.
Từ khóa xác định mức độ hiển thị và các lớp con
- Tất cả các lớp và hàm trong Kotlin đều là
public
theo mặc định. Tuy nhiên, bạn có thể dùng từ khóa xác định để thay đổi chế độ hiển thị thànhinternal
,private
hoặcprotected
. - Để tạo lớp con, lớp mẹ phải được đánh dấu là
open
. - Để ghi đè các phương thức và thuộc tính trong lớp con, các phương thức và thuộc tính phải được đánh dấu là
open
trong lớp mẹ. - Một lớp bị kín chỉ có thể được phân lớp con trong cùng một tệp mà lớp đó được xác định. Tạo một lớp kín bằng cách đặt tiền tố khai báo bằng
sealed
.
Lớp dữ liệu, singleton và enum
- Tạo một lớp dữ liệu bằng cách đặt tiền tố khai báo bằng
data
. - Định cấu trúc là cách viết ngắn để chỉ định các thuộc tính của đối tượng
data
cho các biến riêng biệt. - Tạo một lớp singleton bằng cách sử dụng
object
thay vìclass
. - Xác định một giá trị enum bằng
enum class
.
Lớp, giao diện và ủy quyền trừu tượng
- Lớp trừu tượng và giao diện là hai cách để chia sẻ hành vi chung giữa các lớp.
- Lớp trừu tượng xác định các thuộc tính và hành vi, nhưng để triển khai các lớp con.
- Giao diện xác định hành vi và có thể cung cấp phương thức triển khai mặc định cho một số hoặc tất cả hành vi.
- Khi bạn sử dụng giao diện để soạn lớp, chức năng của lớp được mở rộng thông qua các thực thể lớp có trong đó.
- Ủy quyền giao diện sử dụng thành phần, nhưng cũng ủy quyền triển khai cho các lớp giao diện.
- Thành phần là một cách hiệu quả để thêm chức năng vào một lớp bằng cách ủy quyền giao diện. Ưu tiên chung về thành phần là ưu tiên nhưng việc kế thừa từ lớp trừu tượng là phù hợp hơn đối với một số vấn đề.
Tài liệu về Kotlin
Nếu bạn muốn biết thêm thông tin về bất kỳ chủ đề nào trong khóa học này hoặc nếu bạn gặp khó khăn, https://kotlinlang.org là điểm khởi đầu tốt nhất của bạn.
- Lớp và tính kế thừa
- Hàm dựng
- Chức năng ban đầu
- Thuộc tính và trường
- Công cụ sửa đổi chế độ hiển thị
- Lớp trừu tượng
- Giao diện
- Ủy quyền
- Lớp dữ liệu
- Sự bình đẳng
- Hủy cấu trúc
- Khai báo đối tượng
- Lớp enum
- Lớp học kín
- Xử lý các lỗi không bắt buộc bằng cách sử dụng Lớp con dấu Kotlin
Hướng dẫn về Kotlin
Trang web https://try.kotlinlang.org có các hướng dẫn phong phú được gọi là Kotlin Koans, một biên dịch viên dựa trên web và một bộ tài liệu tham khảo đầy đủ có các ví dụ.
Khóa học Udacity
Để xem khóa học Udacity về chủ đề này, hãy xem Kotlin Bootcamp dành cho lập trình viên.
IntelliJ IDEA
Bạn có thể tìm thấy tài liệu về IntelliJ IDEA trên trang web của JetBrains.
Phần này liệt kê các bài tập về nhà có thể được giao cho học viên đang làm việc qua lớp học lập trình này trong khóa học do người hướng dẫn tổ chức. Người hướng dẫn có thể làm những việc sau:
- Giao bài tập về nhà nếu được yêu cầu.
- Trao đổi với học viên cách nộp bài tập về nhà.
- Chấm điểm bài tập về nhà.
Người hướng dẫn có thể sử dụng những đề xuất này ít hay nhiều tùy ý. Do đó, họ có thể thoải mái giao bất kỳ bài tập về nhà nào khác mà họ cảm thấy phù hợp.
Nếu bạn đang tự mình làm việc qua lớp học lập trình này, hãy thoải mái sử dụng các bài tập về nhà này để kiểm tra kiến thức của bạn.
Trả lời những câu hỏi này
Câu hỏi 1
Lớp có một phương thức đặc biệt đóng vai trò là một sơ đồ thiết kế để tạo các đối tượng của lớp đó. Phương pháp gọi là gì?
▢ Trình tạo
▢ Trình tạo trình tạo
▢ Hàm dựng
▢ Sơ đồ thiết kế
Câu hỏi 2
Câu nào sau đây về giao diện và lớp trừu tượng KHÔNG đúng?
▢ Lớp trừu tượng có thể có hàm dựng.
▢Giao diện không thể có hàm dựng.
▢Chúng ta có thể tạo trực tiếp giao diện và lớp trừu tượng.
▢ Các thuộc tính trừu tượng phải được triển khai bằng các lớp con của lớp trừu tượng.
Câu hỏi 3
Câu nào sau đây KHÔNG phải là công cụ sửa đổi chế độ hiển thị Kotlin cho các tài sản, phương thức, v.v.?
▢ internal
▢ nosubclass
▢ protected
▢ private
Câu hỏi 4
Hãy xem xét lớp dữ liệu này:data class Fish(val name: String, val species:String, val colors:String)
Đâu là mã KHÔNG hợp lệ để tạo và định cấu trúc đối tượng Fish
?
▢ val (name1, species1, colors1) = Fish("Pat", "Plecostomus", "gold")
▢ val (name2, _, colors2) = Fish("Bitey", "shark", "gray")
▢ val (name3, species3, _) = Fish("Amy", "angelfish", "blue and black stripes")
▢ val (name4, species4, colors4) = Fish("Harry", "halibut")
Câu hỏi 5
Giả sử bạn sở hữu một vườn thú có nhiều động vật mà tất cả chúng ta cần phải chăm sóc. Câu nào sau đây KHÔNG thuộc quá trình triển khai hoạt động chăm sóc?
▢ interface
để xem nhiều loại thực phẩm mà động vật ăn.
▢ Một lớp abstract Caretaker
mà bạn có thể tạo nhiều loại nhóm nhân viên chăm sóc.
▢ interface
để cung cấp nước sạch cho động vật.
▢ Một lớp data
cho một mục trong lịch biểu cho nguồn cấp dữ liệu.
Chuyển sang bài học tiếp theo:
Để biết thông tin tổng quan về khóa học, bao gồm cả các đường liên kết đến các lớp học lập trình khác, hãy xem "Kotlin Bootcamp dành cho lập trình viên: Chào mừng bạn đến với khóa học này?