Kotlin 的变量、函数和类型

变量

变量声明:var 、val 、lateinit 、const val

  • 类型和变量名位置互换了
  • 中间是用冒号分隔的
  • 结尾没有分号(对,Kotlin 里面不需要分号)
var name: String? =null
这种类型之后加 ? 的写法,在 Kotlin 里叫可空类型
  • val 只读变量
    • 只能赋值一次,不能修改 类似java中的final
  • lateinit 延迟初始化
    • 意思是:告诉编译器我没法第一时间就初始化,但我肯定会在使用它之前完成初始化的。
      lateinit修饰的对象在赋值前调用会抛出异常
    lateinit var textView: TextView
    var name:String =null
类似java中的final
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_first)
        textView = findViewById(R.id.tv_textView)
    }
  • const val
    • const 必须修饰val
    • const 只允许在top-level级别和object中声明
  • const val和val区别
    const和val 修饰的两个String类型,如下:
object myObject {
    const val constObject: String = "constObject"
 
    val normalObject: String = "normalObject"
}

打开Android studio 点击 Tools->Kotlin->Show Kotlin ByteCode,如下:

public final class com/example/kotlin/myObject {
  public final static Ljava/lang/String; constObject = "constObject"
 
  private final static Ljava/lang/String; normalObject = "normalObject"
 
  public final getNormalObject()Ljava/lang/String;
}

主要区别:
const val 可见性为public final static,可以直接访问。
val 可见性为private final static,并且val 会生成方法getNormalObject(),通过方法调用访问

类型推断

Kotlin 有个很方便的地方是,如果你在声明的时候就赋值,那不写变量类型也行:

🏝️
var name: String = "Mike"
👇
var name = "Mike"

函数

Kotlin 除了变量声明外,函数的声明方式也和 Java 的方法不一样。Java 的方法(method)在 Kotlin 里叫函数(function),其实没啥区别,或者说其中的区别我们可以忽略掉。对任何编程语言来讲,变量就是用来存储数据,而函数就是用来处理数据。

函数的声明

java
Food cook(String name) {
    ...
}
🏝️kotlin
👇                      👇
fun cook(name: String): Food {
    ...
}
  • 以 fun 关键字开头
  • 返回值写在了函数和参数后面

基本类型

  • 在 Kotlin 中,所有东西都是对象,Kotlin 中使用的基本类型有:数字、字符、布尔值、数组与字符串。
🏝️
var number: Int = 1 // 👈还有 Double Float Long Short Byte 都类似
var c: Char = 'c'
var b: Boolean = true
var array: IntArray = intArrayOf(1, 2) // 👈类似的还有 FloatArray DoubleArray CharArray 等,intArrayOf 是 Kotlin 的 built-in 函数
var str: String = "string"

类和对象

  • 首先是类的可见性,Java 中的 public 在 Kotlin 中可以省略,Kotlin 的类默认是 public 的。
  • 类的继承的写法,Java 里用的是 extends,而在 Kotlin 里使用 :,但其实 : 不仅可以表示继承,还可以表示 Java 中的 implement。
    • 举个例子,假设我们有一个 interface 叫 Impl:
🏝️
interface Impl {}
☕️java
public class Main2Activity extends AppCompatActivity implements Impl { }
🏝️kotlin
class MainActivity : AppCompatActivity(), Impl {}
  • 构造方法的写法不同。
☕️ java
public class MainActivity extends AppCompatActivity {
    // 👇默认构造函数
    public MainActivity() {
    }
}
🏝️ kotlin              
class MainActivity constructor() : AppCompatActivity() {
                        👆
}
  • override 的不同
    • Java 里面 @Override 是注解的形式。
    • Kotlin 里的 override 变成了关键字。
    • Kotlin 省略了 protected 关键字,也就是说,Kotlin 里的 override 函数的可见性是继承自父类的。
      除了以上这些明显的不同之外,还有一些不同点从上面的代码里看不出来,但当你写一个类去继承 MainActivity 时就会发现:
  • Kotlin 里的 MainActivity 无法继承:
🏝️
// 👇写法会报错,This type is final, so it cannot be inherited from
class NewActivity: MainActivity() {
}
- 原因是 Kotlin 里的类默认是 final 的,而 Java 里只有加了 final 关键字的类才是 final 的。

那么有什么办法解除 final 限制么?我们可以使用 open 来做这件事:

  🏝️
open class MainActivity : AppCompatActivity() {}

这样一来,我们就可以继承了。

🏝️
class NewActivity: MainActivity() {}

类型的判断和强转

  • 刚才讲的实例化的例子中,我们实际上是把子类对象赋值给父类的变量,这个概念在 Java 里叫多态,Kotlin 也有这个特性,但在实际工作中我们很可能会遇到需要使用子类才有的函数。
    比如我们先在子类中定义一个函数:
🏝️
class NewActivity : MainActivity() {
    fun action() {}
}

那么接下来这么写是无法调用该函数的:

🏝️
fun main() {
    var activity: Activity = NewActivity()
    // 👆activity 是无法调用 NewActivity 的 action 方法的
}

在 Java 里,需要先使用 instanceof 关键字判断类型,再通过强转来调用:

void main() {
    Activity activity = new NewActivity();
    if (activity instanceof NewActivity) {
        ((NewActivity) activity).action();
    }
}

Kotlin 里同样有类似解决方案,使用 is 关键字进行「类型判断」,并且因为编译器能够进行类型推断,可以帮助我们省略强转的写法:

🏝️
fun main() {
    var activity: Activity = NewActivity()
    if (activity is NewActivity) {
        // 👇的强转由于类型推断被省略了
        activity.action()
    }
}

那么能不能不进行类型判断,直接进行强转调用呢?可以使用 as 关键字:

🏝️
fun main() {
    var activity: Activity = NewActivity()
    (activity as NewActivity).action()
}

这种写法如果强转类型操作是正确的当然没问题,但如果强转成一个错误的类型,程序就会抛出一个异常。

我们更希望能进行安全的强转,可以更优雅地处理强转出错的情况。

这一点,Kotlin 在设计上自然也考虑到了,我们可以使用 as? 来解决:

🏝️
fun main() {
    var activity: Activity = NewActivity()
    // 👇'(activity as? NewActivity)' 之后是一个可空类型的对象,所以,需要使用 '?.' 来调用
    (activity as? NewActivity)?.action()
}

它的意思就是说如果强转成功就执行之后的调用,如果强转不成功就不执行。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,185评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,652评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,524评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,339评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,387评论 6 391
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,287评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,130评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,985评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,420评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,617评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,779评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,477评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,088评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,716评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,857评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,876评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,700评论 2 354