當Android遇上Kotlin — Day3

Locus Yu
Locus Yu
Aug 31, 2017 · 8 min read

類別與物件

繼承類別

  • open修飾符是用來表示該類別可以被繼承,原本Java是使用public來做為預設值,但在Kotlin是使用final來做為類別的預設值,所以當該類別需要被其他類別所繼承時,必須先在父類別設定為open才能使用
// 其他類別可以繼承這個類別
open class RichButton : Clickable {
// 這個函數是不可以被修改的(final),不可以在子類別中override它
fun disable() {}
// 這個函數是可以被修改的(open),可以在子類別中override它
open fun animate() {}
// 這函數override了一個已經open的函數,所以他也是可以被override的
override fun click() {}
// 但是如果你不希望子類別去override其父類別所繼承的函數時,可使用final
final override fun click() {}
}

抽象類別

  • 由於抽象類別是不需被初始化,內部也會包含許多需要在子類別去實作抽象的成員函數,因此成員函數預設是open,不需特別定義
// 這是抽象類別
abstract class Animated {

// 這是抽象函數,不需再父類別進行實作,但必須在子類別去override並實作
abstract fun animate()
// 抽象類別中的非抽象函數預設是final,但是可以透過open來打開它
open fun stopAnimating() { ... }

fun animateTwice() { ... }
}

類別的可見性修飾符

  • public(預設值):代表所有地方都能使用這類別
  • internal:代表只有在相同的module內才可以使用這類別
  • protected:代表只有在子類別中能使用
  • private:代表只有該類別內可以使用

內部類別,嵌套類別,密封類別

  • 預設為嵌套類別
  • 透過inner來表示該類別為內部類別
  • 透過sealed來將該類別進行密封,所有子類別都必須嵌套在父類別當中
// 嵌套類別
class Outer {
private val bar: Int = 1
class Nested {
fun foo() = 2
}
}

val demo = Outer.Nested().foo() // == 2
// 內部類別
class Outer {
private val bar: Int = 1
inner class Inner {
fun foo() = bar
}
}

val demo = Outer().Inner().foo() // == 1
// 限定this表達式,用標籤限定符(@)label來表示this的來源
class Outer {
inner class Inner {
fun getOuterReference(): Outer = this@Outer
}
}

類別建構子

class User constructor(_nickname: String) { // 主建構子

val nickname: String

init { // 初始化
nickname = _nickname
}
}
// 其實就跟以下程式是相同的class User(val nickname: String) { ... }

使用data類別修飾符,來建立數據類別

  • 一般在使用Java來建立一個數據Model時,必須去override掉toString(),hashCode(),equals()等function來方便日後的判斷與顯示,現在在Kotlin中,只需要在該類別宣告為data的修飾符,Kotlin會自動幫你生成
data class Client(val name: String, val postalCode: Int)

使用by來進行類別委託

  • 透過by來進行委託,編譯器會自動幫你生成,如此一來你只需要改變你所需要override的方法,而不需要實作所有方法,因為其他方法會透過委託的方式,執行編譯器所生成的實作
// 建立interface
interface Base {
fun print()
}

// 實現此interface的類別
class BaseImpl(val x: Int) : Base {
override fun print() { print(x) }
}

// 透過by來建立類別委託
class Device(b: Base) : Base by b

fun main(args: Array<String>) {
val b = BaseImpl(10)
Device(b).print() // 輸出:10
}

使用object讓Singleton模式更加容易

// Java
private static CaseInsensitiveFileComparator INSTANCE;
public static CaseInsensitiveFileComparator() {
if(INSTANCE == null) {
INSTANCE = new CaseInsensitiveFileComparator();
}
return INSTANCE;
}
@Override
public void compare(File file1, File file2) {
return file1.getPath().compareTo(file2.getPath(), true)
}
CaseInsensitiveFileComparator.INSTANCE.compare(
new File("/User"), File("/user"));
// Kotlin
object CaseInsensitiveFileComparator : Comparator<File> {
override fun compare(file1: File, file2: File): Int {
return file1.getPath().compareTo(file2.getPath(),
ignoreCase = true)
}
}
CaseInsensitiveFileComparator.compare(File("/User"), File("/user"))

另外使用sortedWith()函数,他會透過傳入一個具體的比較物件回傳列表

data class Person(val name: String) {
object NameComparator : Comparator<Person> {
override fun compare(p1: Person, p2: Person): Int =
p1.name.compareTo(p2.name)
}
}
val persons = listOf(Person("Bob"), Person("Alice"))
print(persons.sortedWith(Person.NameComparator))
[Person(name="Alice"), Person(name="Bob")]

使用companion來替代 static 的靜態方法

class A {
companion object {
fun bar() {
println("Companion object called")
}
}
}
A.bar() // 顯示:Companion object calledclass User(val nickname: String) {
companion object { // 宣告companion
fun newSubscribingUser(email: String) =
User(email.substringBefore('@'))
fun newFacebookUser(accountId: Int) =
User(getFacebookName(accountId))
}
}
val subscribingUser = User.newSubscribingUser("bob@gmail.com")
val facebookUser = User.newFacebookUser(545566)

companion的擴展

interface JSONFactory<T> {
fun fromJSON(jsonText: String): T
}
class Person(val firstName: String, val lastName: String) {

companion object { // 宣告一個空的companion
}
}
fun Person.Companion.fromJSON(json: String): Person {
// 宣告一個擴展函數
...
}
val p = Person.fromJSON(json)
Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade