侧边栏壁纸
博主头像
liuxy博主等级

细水长流,吃穿不愁

  • 累计撰写 37 篇文章
  • 累计创建 30 个标签
  • 累计收到 5 条评论

目 录CONTENT

文章目录

Kotlin初步学习(一)

liuxy
2022-08-22 / 0 评论 / 2 点赞 / 319 阅读 / 4,186 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2022-08-23,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

Kotlin简介

Kotlin是一门基于JVM的编程语言,它正成长为Android开发中用于替代Java语言的继承者。Java是世界上使用最多的编程语言之一,当其他编程语言为更加便于开发者使用而不断进化时,Java并没有像预期那样及时跟进。

Java缺失的很多特性在最新的修订版中逐渐覆盖到了,但Android开发者暂时还没能够使用它们。这就使得类似Kotlin这样的语言有了用武之地了:在旧的开发环境中使用现代语言的特性。

Kotlin是什么?

Kotlin是由JetBrains创建的基于JVM的编程语言,IntelliJ正是JetBrains的杰作,而Android Studio是基于IntelliJ修改而来的。Kotlin是一门包含很多函数式编程思想的面向对象编程语言。
Kotlin生来就是为了弥补Java缺失的现代语言的特性,并极大的简化了代码,使得开发者可以编写尽量少的样板代码。

为什么要使用Kotlin?

首先我必须声明我使用Kotlin的时间并不长,我几乎是边学习边写这一系列博客的。我没有尝试其他替代语言例如Go或者Scala,因此如果你真的想要切换到另一门语言之前,我建议先搜索其他人是如何评价其他语言的。使用Scala开发Android的一个很棒的例子可以在47deg的Github上面找到。

为什么选择Kotlin进行学习的理由:

相对而言更快的学习曲线:例如相比Scala而言,我们将学得更快。Kotlin限制比较多,但如果你之前没有使用过现代编程语言,那么使用Kotlin入门会更容易。

轻量级:相比其他编程语言,Kotlin函数库更小。由于Android存在65K方法数限制,这使得这一点更为重要。虽然使用proguard或者打包成多个dex能够解决这个问题,但是所有这些解决方案都会增加复杂性,并增加调试的时间。Kotlin函数库方法数小于7000个,相当于support-v4的大小。

高度可互操作:Kotlin可以和其他Java类库很好的并且简单的互操作。Kotlin团队在开发这门新语言时正是秉承了这个中心思想。他们希望可以使用Kotlin继续开发现有的使用Java语言编程的工程,而不是重写所有代码。因此Kotlin需要能够极好的和Java互操作。
完美的集成Android Studio以及Gradle:Kotlin有一个专门用于Android Studio的插件,以及另一个专门用于Gradle的插件,因此在Android工程中开始使用Kotlin并不困难(我将在下一篇文章中进行介绍)。

在你作任何决定之前我推荐先阅读一篇由Jake Wharton写的有趣的文章:在Android开发中使用Kotlin。

基本类型

在Kotlin中任何事物都是对象你可以在任何变量上调用相应的方法或属性。Kotlin的一些内置类型如下:

  1. Number: 包含整形与浮点型
  2. Character: 字符(Chat)
  3. Boolean: 布尔值
  4. String: 字符串
  5. Array: 数组

在Kotlin内置的类型个人觉得更加像Java中的一些包装类,如果在学习之前将思维转换成Java包装类的思想我觉得学起来更容易理解一些。当然它们还与Java多少有些不同。

Number类型

Kotlin包含如下number类型:

  1. Double
  2. Float
  3. Long
  4. Int
  5. Short
  6. Byte

怎么样有没有感觉跟Java里面的java.lang.Double、java.lang.Long这些包装类差不多用起来也差不多。还有在Kotlin的数字常量可以用十进制、十六进制、指数形式小数、二进制但是没有八进制。Kotlin中是没有自动向上转型的。

内置数据类型

    var d: Double = 64.0
    var i: Int = 32
    var l: Long = 64
    var f: Float = 32.0F
    var b: Byte = 8
    var s: Short = 16

数字常量

    i = 1  //十进制
    i = 0x1 //十六进制
    i = 01 //八进制不允许
    i = 0b00000 //二进制
    d = 1.2E10 //指数形式
    f = 1.2E10F

    //没有自动向上转换
    l = i   //Int不能自动转换成Long
    d = f  //同样Float也不能自动转换

不过上面说了Kotlin中任何事物都是对象那么我们可以调用相应的方法来显示转换。

    var i: Int = 5;
    var l: Long = i.toLong();

字符类型

字符类型在Kotlin中用Char来表示,它不能直接去应用一个number类型如var ch: Int = 'c’是错误的必需要显示的转换var ch: Int = ‘c’.toInt()同样Char也支持转意字符\n、\b、\r等跟Java中的差不多。

数组

在Kotlin数组分为基本类型的数组和其他类型数据,基本数组类型是指数组中的元素类型都是基本数据类型如: Int、Long、Floa这些类型的数组在Kotlin中分别用IntArray、LongArray、FloatArray来表示可以通过Kotlin内置的方法来创建<>ArrayOf(values)里面的号代表具体的元素类型。

    var intArray: IntArray = intArrayOf(1, 3, 4);
    var longArray: LongArray = longArrayOf(1L, 2L)

其他类型的数组可以使用Array通过传入大小与生成对象的方法来创建数组。

    var str: Array<String> = Array(5, { index -> index.toString })

字符串

字符串用String表示同Java一样是不可变的同样内部也用字符组成,访问内部字符可以通过s[i]和循环来遍历。

    var hello: String = "HelloWorld"

    for(index: Int  in 0..hello.length - 1){
        println(hello[index])
    }

    for(ch in hello){
        println(ch)
    }

字符串可分为能够转意一些特殊字符的字符串和原始的字符串。

    var text1: String = "Hello\tWorld"
    var text2: String = """
        Hello\bWorld
        """
    println(text1)
    println(text2)

在text1中\t会转间成一个制表符但在text2不但\b不会转意且任何内容都会照样输出。原始字符串类似XMl中的CDATA。字符串中可以使用模版,就像Java中的String.format的一样但在Kotlin中使用$号开始后面可以加变量名来替换内容。

    var name: String = "Kotlin";
    var greet: String = "Hi, $name";
    println(greet)

Kotlin语法

函数的使用

定义函数使用fun关键字,如下代码所示:

fun add(a: Int, b: Int): Int{
	return a + b
}

函数add由两个Int类型的参数,冒号后跟的是函数的返回值,一条代码语句末尾不用加分号,当然加上分号也没有问题。

以上的add函数还可以写成如下的方式:

fun add (a: Int, b: Int)  = a + b ;

没有显式指定函数的返回值,会自动推断函数的返回值。
如果一个函数没有返回值,可以写成一下两种方式:

方式一:

//没有返回值的函数,显式指定Unit为返回值
fun showAssResult1(a: Int, b: Int) : Unit{
	println(a + b)
}

方式二:

//没有返回值的函数,省略Unit的写法
fun showAddResult2(a: Int, b: Int){
	println(a + b)
}

常量和变量

使用val关键字声明一个常量(只读,不可修改),使用var关键字声明一个变量,下面是具体用法:

fun test(){
  //使用val关键字声明一个常量(只读),声明常量时必须初始化
  val a: Int = 1 //显式指定常量的类型
  val b = 2 //自动推断类型
  val c: Int // 声明一个不初始化的常量,必须显式指定类型
  //b = 3 //常量值不可修改,这行代码会报错
  //a = 3 //不可以修改常量的值,这行代码会报错

  //使用var关键字声明一个变量,变量的值可以修改
  var year : Int = 2017  //显式指定变量的类型
  var month = 5 //自动推断类型
  var day : Int //声明一个不初始化的变量,必须显式指定类型
  month = 6 //变量值可以被修改
}

注释

Kotlin中的注释和Java中类似,如下所示:

fun connebts(){
  //注释一行代码
  // var s = "hello kotlin"
  /*注释一段代码*/
  /*var a = 0
  a++ 
  a--*/
}

和Java不同的是,Kontlin中的注释可以嵌套。

字符串模板

//字符串模板的用法
fun stringTempl(args: Array<String>){
  if(args.size > 0)
   println("args[0] = ${args[0]}") 
  }
  //main方法是整个程序的入口
  fun main(args: Array<String>){
  var arr = arrayOf("hello", "Kotlin")
  stringTempl(arr)
}

执行结果:

条件表达式

常规的条件表达式可以是这么写的:

//常规写法的条件表达式,这里的函数返回值不能省略
fun max(a: Int, b: Int) : Int{
  if(a > b)
  return a
  else
  return b
}

Kotlin可以简写条件表达式:

//简写的条件表达式
fun max(a: Int, b:Int) = if(a > b) a else b

可空类型

//可空类型
fun nullableTest(){
  //在变量类型后面加上问号,代表该变量是可空变量
  var name: String? = "zhangsan"
  name = null //可以将null赋值给name变量
  var person: String = "tomim"
  //person = null // 这句代码会报错,不可以将null赋值给一个不可空变量 
}

函数返回值为可空的例子如下代码:

/*
函数返回值为Int?,表示返回值可以为空
当参数为空或者为:“”时,则返回null,否则释用Java中的字符串转整型凡人方法
体现了Kotlin代码和Java代码的无缝集成
*/
fun parseInt(s: String): Int? {
  if(s == null  || s == "")
  return null;
  return Integer.parseInt(s);
}

类型检查和自动类型转换

Kotlin中使用is运算符来检查数据类型和做类型转换,如下代码所示:

/*
当函数参数为字符串类型时,就返回字符串的长度,否则返回空
*/
fun getStringLength(n: Any): Int{
  if(n is String)
  return n.length//这里会自动将n转化为字符串类型
  return null
}

上面的代码还可以写成:

/*
当函数参数为字符串类型时,就返回字符串的长度,否则返回空
*/
fun getStringLength(n: Any): Int{
  if(n !is String)
  return null
  return n.length//这里会自动将n转化为字符串类型
}

for循环和while循环

for循环的测试代码

fun testFor(){
  var arr = array(1,2,3,4,5,6)
   //通过索引循环
  for(i in arr.indices){
  println(arr[i])
  }
  //直接使用数组中的对象循环
  for(num in arr){
  println(num)
  }
}

while循环的测试代码

fun testWhile(){
  var i = 0
  while( i < 10){
  println("While循环--->> " + i)
  i ++
  }
}

when表达式

when表达式就类似于Java中的switch表达式,如下代码所示:

fun main(args: Array<String>){
	testCase(" hello Kotlin")
}

fun testCase(obj : Any){
  when(obj){
	is String -> {
        println(" this is string ")
      }
      is Int -> {
      println(" this is integer ")
      }
      else -> {
      println(" unkown value ")
		}
	}
}

ranges的使用

使用in操作符检查一个数是否在某个范围内

/*
判断分数是否大于等于90,小于等于100
*/
fun isGood(score : Int){
  //ranges是闭区间
  if(score in 90..100)
  println(" very good ")
  else
  println(" not so good ")
}

检查索引是否确界

/*
检查index是否在数组arr的索引范围内
*/
fun checkIndex(index : Int , arr: Array<Int>){
  //arr.lastIndex返回的是数组最后一位的下标(索引)
  if(index in 0..arr.lastIndex)
  println(" index in bounds ")
  else
  println(" index out of bounds ")
}

遍历一个范围

for(i in 1..5){
  println(i)
}

也可以通过in运算符遍历一个集合:

//in运算符便利一个字符串数组
fun testStr(arr: Array<String>) {
  for (str in arr){
  println(str)
  }
}

Kotlin有些什么特性呢?

表达式

使用Kotlin可以很容易避免样板代码的编写,因为语言本身已经默认覆盖了大多数典型的情况。
例如,在Java中如果要创建一个典型的数据模型类,我们需要编写(或者至少生成)如下代码:

public class Artist {
    private long id;
    private String name;
    private String url;
    private String mbid;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getMbid() {
        return mbid;
    }

    public void setMbid(String mbid) {
        this.mbid = mbid;
    }

    @Override public String toString() {
        return "Artist{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", url='" + url + '\'' +
                ", mbid='" + mbid + '\'' +
                '}';
    }
}

如果使用Kotlin编写呢?如下所示:

data class Artist(
    var id: Long,
    var name: String,
    var url: String,
    var mbid: String)

空类型安全

当我们使用Java进行开发时,大部分代码都是防守型的。我们需要在使用之前不断的检测对象是否为空,如果我们不想在代码运行时得到非预期的NullPointerException。类似其他很多编程语言,Kotlin是空类型安全的,因此我们需要使用安全调用操作符显式指明对象是否能够为空。
我们可以类似这样声明:

//This won´t compile. Artist can´t be null
var notNullArtist: Artist = null

//Artist can be null
var artist: Artist? = null

// Won´t compile, artist could be null and we need to deal with that
artist.print()

// Will print only if artist != null
artist?.print()

// Smart cast. We don´t need to use safe call operator if we previously checked nullity
if (artist != null) {
    artist.print()
}

// Only use it when we are sure it´s not null. Will throw an exception otherwise.
artist!!.print()

// Use Elvis operator to give an alternative in case the object is null
val name = artist?.name ?: "empty"

扩展函数

我们可以为任何类添加新函数。相比我们工程中普遍存在的传统的工具类,扩展函数更具可读性。例如,我们可以为fragments添加一个新函数,用于显示一个toast:

fun Fragment.toast(message: CharSequence, duration: Int = Toast.LENGTH_SHORT) {
    Toast.makeText(getActivity(), message, duration).show()
}

然后可以这样调用:

fragment.toast("Hello world!")

函数式支持(Lambdas)

每次当我们创建一个新的listener时,都需要声明一个onClick函数用于处理监听回调,我们可以直接编写监听回调的代码而不用声明onClick函数吗?答案是肯定的。这(包括其他很多有趣的功能)得归功与lambda表达式的运用:

view.setOnClickListener({ toast("Hello world!") })

目前的限制

译者注:本小节所列出的限制,在最新版的Kotlin中已经都解决了,仅供读者目睹Kotlin语言的完善和进化过程。

Kotlin目前还处于开发阶段,虽然已经很稳定而且最终release版本即将发布(这个夏天),但在Android开发中存在如下限制:

与自动生成代码的可互操作性:一些知名的依赖于自动生成代码的Android函数库,例如Dagger或者Butterknife,由于某些不兼容的命名,因此不能正常的使用。Kotlin团队正在解决这些问题,将来某一天将会解决(KT-6444)。不管怎么说,就像我将在下一篇文章中说明的,语言的可表达性能够说服我们不再需要这些函数库。

更新:在Kotlin M12已经带来了对注解处理的支持。

没有简单的方式声明自定义views:Kotlin类只能声明一个构造函数,而自定义views一般都有三个重载构造函数。当我们在代码中使用这些自定义views时只有一个构造函数不存在问题,但如果想在xml文件中使用自定义views,只有一个构造函数是不够的。最简单的解决方法是使用Java声明这些自定义views类,并在Kotlin中引用它们。Kotlin团队许诺将在M11发布版中解决这个问题。

更新:Kotlin M11发布了并包含了辅助构造函数。

Android工程中的jUnit测试:Android Studio 1.1引入的这个新特性Kotlin暂时还不支持。但纯粹的Kotlin工程能够完全支持Instrumentation测试和jUnit测试。

2
广告 广告

评论区