此次所说的是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,欢迎加入咱们~~~