此次所說的是Kotlin的變量和常量,主要會對如下內容作介紹:java
public String name = "Mikyou";//定義變量
public final int age = 18;//final定義常量
複製代碼
var name: String = "Mikyou"
val age: Int = 18
複製代碼
或者編程
var name = "Mikyou"
val age = 18
複製代碼
總結: 由以上的對比可得出:bash
var name: String = "Mikyou"
var address: String?//若是這個變量沒有初始化,那麼須要顯示聲明類型而且指明類型是否可null
address = "NanJing"
val age: Int = 18
複製代碼
或者app
var name = "Mikyou"
val age = 18
複製代碼
在Kotlin中屬性是頭等特性,它習慣於用一個屬性去替代Java中的字段和setter,getter方法。而Kotlin中的set、get訪問器至關於Java中的setter,getter方法。Kotlin有個新的特性就是能夠去定義一個類中屬性的訪問器包括setter,getter訪問器。該特性十分適用於須要通過多個屬性邏輯計算得出的一個新的屬性。那麼邏輯計算的過程操做不須要像Java同樣開一個方法來實現。能夠直接在屬性訪問器中進行邏輯運算。dom
在Java中實現:ide
public class Rectangle {
private float width;
private float height;
public Rectangle(float width, float height) {
this.width = width;
this.height = height;
}
public boolean isSquare() {//在java中實現一個方法進行相關的邏輯計算
return width == height;
}
}
複製代碼
在Kotlin中實現:函數式編程
class Rectangle(width: Float, height: Float) {
val isSquare: Boolean//在Kotlin中只須要一個屬性就能解決,從新定義了isSquare的getter屬性訪問器,訪問器中能夠寫入具體邏輯代碼。
get() {
return width == height
}
}
複製代碼
在Java中實現Android中的一個自定義View中的setter方法。函數
public class RoundImageView extends ImageView {
...
public void setBorderColor(int color) {
mColor = color;
invalidate();
}
...
}
複製代碼
在Kotlin中實現Android中的一個自定義View中的set屬性訪問器。學習
class RoundImageView @JvmOverloads constructor(context: Context, attributeSet: AttributeSet? = null, defAttrStyle: Int = 0)
: ImageView(context, attributeSet, defAttrStyle) {
var mBorderColor: Int
set(value) {//自定義set屬性訪問器
field = value
invalidate()
}
}
複製代碼
因爲Kotlin是一門新的語言,咱們在學習的過程當中常常習慣性的去記住一些所謂定理,而沒有去真正深究爲何是這樣。好比拿今天的議題來講,相信不少的人都這樣認爲(剛開始包括我本身)var修飾的變量是可變的,而val修飾的變量是不可變的。而後學完Kotlin的自定義屬性訪問器就會以爲是有問題的。而後去看一些國外的博客,雖然有講述可是看完後更讓我懵逼的是val修飾的變量的值是能夠變化的可讀的,而且底層的引用也是變化的。前面那句確實能夠理解,後面一句仍是保留意見。因而乎就開始寫demo認證。 引用國外博客的一句原話"But can we say that val guarantees that underlying reference to the object is immutable? No…" 國外博客源地址測試
假設一: 在Kotlin中的val修飾的變量不能說不可變的,只能說val修飾變量的權限是可讀的。
假設二: 在Koltin中的val修飾的變量的引用是不可變的,可是指向的對象是可變的。
論證假設一: 咱們在Kotlin的開發過程當中,通常是使用了val修飾的變量就不能再次被賦值了,不然就會拋出編譯時的異常。可是不能再次被賦值不表明它是不可變的。由於Kotlin與Java不同的是多了個自定義屬性訪問器的特性。這個特性貌似就和val修飾的變量是不可變的矛盾了。而Java中不存在這個問題,若是使用了final修飾的變量,沒有所謂自定義訪問器概念。
fun main(args: Array<String>) {
val name = "Hello Kotlin"
name = "Hello Java"
}
複製代碼
print error:
Error:(8, 5) Kotlin: Val cannot be reassigned
複製代碼
定義get屬性訪問器例子
class RandomNum {
val num: Int
get() = Random().nextInt()
}
fun main(args: Array<String>) {
println("the num is ${RandomNum().num}")
}
複製代碼
print result:
the num is -1411951962
the num is -1719429461
複製代碼
總結: 由以上的例子能夠說明假設一是成立的,在Kotlin中的val修飾的變量不能說是不可變的,而只能說僅僅具備可讀權限。
論證假設二: 由論證一,咱們知道Kotlin的val修飾的變量是可變的,那它的底層引用是不是可變的呢?國外一篇博客說引用是可變的,真是這樣嗎?經過一個例子來講明。
User類:
package com.mikyou.kotlin.valtest
open class User() {
var name: String? = "test"
var age: Int = 18
var career: String? = "Student"
}
複製代碼
Student類:
class Student() : User()
複製代碼
Teacher類:
class Teacher() : User()
複製代碼
Customer接口:
interface Customer {
val user: User//注意: 這裏是個val修飾的User實例引用
}
複製代碼
VipCustomer實現類:
class VipCustomer : Customer {
override val user: User
get() {
// return Student().apply {
// name = "mikyou"
// age = 18
// career = "HighStudent"
// }
return Teacher().apply {
//看到這裏不少人確定認爲,底層引用也會發生改變,畢竟Student, Teacher是不一樣的對象了。可是事實是這樣的嗎?
name = "youkmi"
age = 28
career = "HighTeacher"
}
}
}
複製代碼
測試:
fun main(args: Array<String>) = VipCustomer().user.run {
println("my name is $name, I'm $age years old, my career is $career, my unique hash code is ${hashCode()} ")
}
複製代碼
print result:
my name is mikyou, I'm 18 years old, my career is HighStudent, my unique hash code is 666988784 //切換到Teacher my name is youkmi, I'm 28 years old, my career is HighTeacher, my unique hash code is 666988784
複製代碼
總結: 由以上的例子能夠說明假設二是成立的,兩個不一樣的對象hashCode同樣說明,user的引用地址不變的,而變化的是引用指向的對象是能夠變化的。
到這裏Kotlin入門基礎語法就結束了,下一篇將會繼續深刻Kotlin相關內容
歡迎關注Kotlin開發者聯盟,這裏有最新Kotlin技術文章,每週會不按期翻譯一篇Kotlin國外技術文章。若是你也喜歡Kotlin,歡迎加入咱們~~~