一起从零学Kotlin-20170730

学习本文章的同学,你一定得熟悉Java方面的知识,否则本文章不是太适合你哦!

一起从零学Kotlin-20170730

0.官方API

链接:http://pan.baidu.com/s/1geVxlJ1 密码:4nht
官方API才是学习的王道……

Intellij IDEA(kotlin开发学习IDEA,并且还支持Java)下载
https://www.jetbrains.com/idea/

官网下载慢的可以从我云盘里面下载:
链接:http://pan.baidu.com/s/1i4Au2nb 密码:qato

1.val和var声明可变和不可变变量

val:用于声明不可变的变量,不可变指的是引用不可变,相当于Java当中的final

var:用于声明可变的变量

fun main(args: Array) {

    val a = "a是不可变的变量" //不可变

    var another = 3 //可变

    println(a)
    println(another)

}

2.fun函数

Kotlin中的函数可以这样声明:

fun 函数名 (参数列表):返回值类型{函数体}

fun 函数名 (参数列表) = 表达式

 //fun 函数名 参数列表:返回值类型{函数体} 
fun add1(a1:Int,a2:Int):Int{

    return a1+a2

}

//fun 函数名 参数列表 = 表达式
fun add2(a1:Int,a2:Int) = a1+a2

还有一种比较奇怪的方式:

fun main(args: Array) {

      println(sum1(1,2))

      println(sum2(3,4))

}


var sum1 = fun (a1:Int,a2:Int):Int{

      return a1+a2
}

var sum2 = fun(a1:Int,a2:Int) = a1+a2

输出:
3
7

这种方式叫做匿名函数,有啥用途?目前笔者也不是很清楚,学过的大神说它相当的厉害,所以继续往后学,应该会揭晓。

3.聪明的类型推断

Kotlin能够很聪明的判断一些位置所应有的类型,这让程序员省心了不少。
比如:
以下代码:

var a = 3 //自动推断a的类型为Int

var str:String = "string"
var str2 = str //自动推断str2的类型为String

fun add(a1:Int,a2:Int) = a1 + a2 //自动推断add()方法的返回类型为a1+a2所对应的类型,也就是Int类型         

4.Lambda表达式

其实就和匿名函数一样,写法如下:
{(参数列表) -> [函数体,最后一行是返回值]}

fun main(args: Array) {

     println(sum(1,2))

     println(sum2(3,4))


}

var sum = {a1:Int,a2:Int-> a1+a2 }


var sum2 = {a1:Int,a2:Int->
                        println("$a1 + $a2 = ${a1 + a2}")
                        a1+a2
}

Lambda的类型是什么,这跟传入的类型和返回的类型相关,比如下面的代码中Lambda对应的类型如下代码所示:

 var sum = {a1:Int,a2:Int-> a1+a2 } //(Int,Int)->Int
 var str = {a1:Int,str:String->
                             a1.toString() + str +"".toString()
                             println(str)
           }//(Int,String)->unit

Kotlinl里面的unit就相当于Java当中的void
Lambda表达式可以嵌套使用吗?当然可以啊,比如Lambda的类型是(Int,(Int,String)->Int)->Int这不是就是Lambda表达式的嵌套吗?只不过作为初学者的我们是有点复杂哦。

那么Lambda表达式如何调用呢?
比如,下面Lambda表达式如何调用:
var sum = {(a1:Int,a2:Int) -> a1+a2}

你可以这么调用:sum(2,3)
你也可以这么调用sum.invoke(2,3)

5.类及类的声明

Java当中的类的声明有以下几个方面:
1.构造器
2.成员变量
3.成员方法
4.访问权限的设置
5.静态和非静态的设置
6.为某些成员变量设置get和set方法
对于那些对Java非常熟悉的同学,这些也就不需要特殊说明了把!不熟悉?那现在还不太适合学习Kotlin,理由很简单,因为面向对象思想都没有理解,那之后学习起来相当吃力的,所以,请务必先接触一下Java,再来学习Kotlin就轻松容易的多了。

那么Kotlin如何取声明一个类呢?
关键字还是很Java一样使用”class”关键字声明类

5.1 构造器

Kotlin当中的构造器的名字可不是跟Java一样,和类名相同,其构造器的名字必须是:constructor,代码如下所示:

class Person{

    var name:String = "" //成员变量
    var age:Int = 0

    constructor(name:String,age:Int){

        this.age = age
        this.name =name

    }//Person类的构造器

}

此外Kotlin对于构造器还有一个特殊的写法,代码如下:

class Student(var name:String,var age:Int)//构造器的特殊写法

对应的代码应该是下面的样子:

class Student{

    var name:String = "" 
    var age:Int = 0

    constructor(name:String,age:Int){

        this.age = age
        this.name =name

    }

}

此外,类的构造器分为主构造器和次构造器:

在 Kotlin中的一个类可以有一个主构造函数和一个或多个次构造函数。主构造函数是类头的 一部分:它跟在类名(和可选的类型参数)后,如果主构造函数没有任何注解或者可见性修饰符,可以省略这个constructor 关键字。

主构造函数不能包含任何的代码。初始化的代码可以放到以 init 关键字作为前缀的初始化 块(initializer blocks)中。

主构造函数的参数可以在初始化块中使用。它们也可以在类体内声明的属性初始化器中使用。

如果一个非抽象类没有声明任何(主或次)构造函数,它会有一个生成的不带参数的主构造 函数。构造函数的可见性是public。如果你不希望你的类有一个公有构造函数,你需要声明 一个带有非默认可见性的空的主构造函数。

说了这么多,还不如上上代码来的直接:

class Student(var name:String,var age:Int){//主构造函数

    init {
       name = "sda"
        age = 28
    }

    var ID:String = "20171314"

    constructor(name:String,age:Int,ID:String) : this(name,age) {

        this.ID = ID

    }//次级构造函数


}

5.2 成员变量

这基本和Java当中是一样的,看上述代码就知道了

5.3 成员方法

Kotlin当中如果从属于类的函数叫做”成员方法”或者”方法”,不从属于类的叫做”函数”,什么是不从属于类呢?比如下列代码中的A()函数:

fun main(args: Array) {

    A()

}


fun A(){

    println("函数A()")

}//不从属于类,是函数

Kotlin中的成员方法没什么特别要说明的,基本上和Java的声明类似,代码如下:

class Person{

    var name:String = ""
    var age:Int = 0

    constructor(name:String,age:Int){

       this.age = age
       this.name =name

    }

    fun  自我介绍(){

        println("我是$name,今年${age}岁")

    }//Person的成员方法"自我介绍()"


}

5.4 权限修饰符的设置

Java当中的默认访问权限是default,作用于当前的包内,Kotlin的默认访问权限是public,你没看错,的确是public,kotlin的访问权限特性如下:

类的权限修饰符:
open:如果你确定你自定义的类是会被继承的,那么你需要给这个类添加 open 修饰符。

final:这是kotlin默认的,也就是没有添加任何修饰符,和上面Student类一样,此修饰符代表着你的类不能被继承。

sealed:sealed 修饰的类称为密封类,用来表示受限的类层次结构。例如当一个值为有限集中的 类型、而不能有任何其他类型时。在某种意义上,他们是枚举类的扩展:枚举类型的值集合也是受限的,但每个枚举常量只存在一个实例,而密封类的一个子类可以有可包含状态的多个实例。

data:data 修饰的类称之为数据类。它通常用在我们写的一些 POJO 类上。
当 data 修饰后,会自动将所有成员用operator声明,即为这些成员生成类似 Java 的 getter/setter 方法。

成员变量修饰符:
public:
private:
protected:
上面三种我就不罗嗦了,因为和Java中的是一样的

internal:它是模块级别的访问权限。

何为模块(module),我们称被一起编译的一系列 Kotlin 文件为一个模块。在 IEDA 中可以很明确的看到一个 module 就是一个模块,当跨 module 的时候就无法访问另一个module 的 internal 变量或方法。这会在后面说明。

5.5 静态和非静态的设置

貌似Kotlin中不存在静态修饰符static,那么肯定有个替代的东西,但是存在一个伴生类的写法,它就是用来替代Java当中的静态变量和静态方法的,示例代码如下:

fun main(args: Array) {


    println(Student.a)

    println(Student.get())

}

class Student(var name: String,var  age: Int) {


    companion object {//静态方法和变量都应该写在这里面

        var  a:Int =  3;//静态变量

        fun get():Int{

            return a
        }

    }



}

5.6 为某些成员变量设置get和set方法

在类前面加”data”修饰符即可达到效果,而且注意的一点就是,无论你有没有在声明类的时候加”data”关键字。

Getters和 Setters
声明一个属性的完整语法是

其初始器(initializer)、getter 和 setter 都是可选的。属性类型如果可以从初始器 (或者从 其 getter 返回值,如下文所示)中推断出来,也可以省略。

6.Kotlin对基本运算符进行重写以及创造自己的运算符

Java当中是不能对基本的运算符进行重写的,但是Kotlin就不一样了,可以对基本运算符进行重写,怎么样,是不是感觉很牛啊!我们就拿一个数学当中的复数相加操作为例字,我们知道基本运算符中没有复数相加的操作,没关系,我们可以进行在复数类FuShu中把“+”运算符进行重写,代码如下,注意为了让童鞋们更好的理解,我使用了中文命名,实际开发中尽量少用中文:

class 复数(var 实部:Int,var 虚部:Int){

    operator  fun plus(fuShu: 复数):复数{
        return 复数(实部 + fuShu.实部,虚部+ fuShu.虚部)
    }

    override fun toString(): String {
        return "$实部 + ${虚部}i"
    }

}


fun main(args: Array) {

    var fuShu1 = 复数(3,4)

    var fuShu2 = 复数(4,5)

    println(fuShu1 + fuShu2)

}

输出:
7 + 9i

除此之外我们还可以添加我们自己的运算符,比如以下神奇的代码:

class 人(var name:String,var age:Int){

    infix  fun 吃(str:String){

        println("我叫$name,今年${age}岁,现在正在吃$str")
    }//使用中缀表达式对自定义运算符,其实就是可以让方法可以像运算符一样被调用


}

fun main(args: Array) {

   var 某个人 = 人("张三",23)

   某个人 吃 "螃蟹"

}

输出:
我叫张三,今年23岁,现在正在吃螃蟹

注意的是要想把方法自定义自己的运算符,此方法一定含有参数,并且只能是一个参数,要问原因,其实很简单,因为运算符只涉及两个参数,一个就是运算的,一个就是被运算的,so 明白了吧!

7.分支表达式,when表达式…

分支表达式?啥玩意儿?Java当中的分支语句?的确,分支表达式这很难理解,其实我把代码一贴出来,你就恍然大悟了:

var string = readLine() //readLine()方法是接收键盘输入的字符串

 val str = if(readLine()!!.contains("1")){"11111"}else{"aaaaa"}
 //当输入的字符串当中含有子字符串"1",那么这个分支表达式就会返回字符串"11111",否则返回"aaaaa"

没错,分支表达式可以具有返回值的,分支语句是不会返回值的,so 明白了吧!上述是”if表达式”是分支表达式的一种,那么肯定存在其他的分支表达式,在提到其他的分支表达式之前,必须说明一点,Java当中有个分支语句叫switch,Kotlin没有switch啦,那么咋办呢?删除switch肯定会有替代switch的啦,kotlin中的when语句就可以替代switch语句,代码如下:

var string = readLine()


val str = when(string){

          "1"->"11111" //当string的值为"1",注意是等于,那么就返回值"11111"
          "a"->"aaaaa"

    else->{

        "啥都不是" //当string的值不是"1"或者"a"的时候,就返回"啥都不是"
    }

}

看懂笔者写的代码,一方面你已经掌握了Kotlin分支表达式,一方面掌握了分支语句。
区分起来很简单,一个有返回值,一个没有返回值

8.循环语句以及关键字continue和break

Java当中的循环语句有:for语句,while语句,那么Kotlin中的循环语句会跟Java一样 吗?

首先,我们来看看for语句,Java当中for语句用法有:(1)集合或者数组的迭代,(2)次数循环,比如从1加到100,那么Kotlin中的for语句会是什么样子呢?

Kotlin中的for语句:
Kotlin中的for语句迭代很强大,比Java的还要强大,比如,有一个String[]数组,它的迭代是这样的:

var strs:Array = arrayOf("a","b","c","d","e")

for(str in strs){
    println(str)
}

这似乎跟java的基本一样,为什么是似乎?因为Kotlin支持自动类型推断,所以在用于遍历的变量不需要指定类型,不得不再说一句自动类型推断简直太人性话了,但是有些时候,我们必须要带数组下标的方式去遍历,Java当中的for语句可就变得麻烦多了,因为必须要以下类似的写法:

 //Java当中带下标的方式去遍历String数组
 String[] strs  = {"a","b","c","d","e"}

 for(int i=0;i

这简直太麻烦了,还要声明一个变量i,Kotlin可不需要,它是这样的

var strs:Array = arrayOf("a","b","c","d","e")


//不带下标遍历数组
for(str in strs){
    println(str)
}

//带下标遍历数组
for((Index,Value) in strs.withIndex()){

    println("下标:$Index,值:$Value")

} //withIndex()方法返回Iterable>

这么一比较,又觉得kotlin那叫一个爽。那么如何使用Kotlin中的for语句求的1到100之和呢?代码如下:

var intRange:IntRange = 1..100 // 这是[1,100]区间

var sum = 0;

for(i in intRange){

    sum = sum + i

}

println("1到100的累和结果是:$sum")

接下来看看while循环,kotlin的while跟Java是一样一样的,都有
while(条件体){循环体}

do{循环体}while(条件体)两种方式,由于是一样的,这里我就不在啰嗦了。

接下来,来看看kotlin中的continue和break关键字,这俩关键字也是跟Java当中是一样一样的,所以我也就再次不想啰嗦了,实例代码如下:

fun main(args: Array) {


     var students:Array = arrayOf(Student("a",1)
                                     ,Student("b",2),Studen("c",3)
                                     ,Student("d",4),Studet("e",5))

     for((Index,Value) in students.withIndex()){

           if(Value.name == "a")continue

           if(Value.name == "c")break

           println("下标:$Index,值:${Value.name}->${Value.age}")
     }

}


class Student(var name:String,var age:Int)

9.Kotlin中的异常

Java的异常体系是这样的:

其中非运行时异常必须捕获和处理,通过try{}catch(){}finally{}语句来处理,除此之外,Java中可以自定义异常类,继承自基础体系中的异常,即可让自己的类加入到异常体系的大家族,具体细节,我就不罗嗦了,这都是Java的基础。

那么Kotlin中的异常体系又是如何呢?
Kotlin中所有异常类都是Throwable类的子孙类。每个异常都有消息、堆栈回溯信息和可选 的原因。跟Java一样代码块使用throw来抛出异常,方法使用throws来抛出异常,使用tru{}catch(){}finally{}语句来捕获和处理异常,可以有零到多个catch块。finally 块可以省略。但是catch和finally 块至少应该存在一个。这基本上和Java保持一致的,除此之外,try{}catch(){}finally{}是一个表达式,也就是说它可以具有返回值,示例代码如下:

var str = try {

    var file = File("D:\\aa")
    var fis  = FileInputStream(file)

}catch (e:FileNotFoundException){

    "文件木有找到"

}finally {

    "文件找到啦"

}


println(str)

注意的是Kotlin中并不会去取检查异常,什么意思?在Java中非运行时异常一定要捕获和处理,但是Kotlin并不存在运行时异常和非运行时异常的概念,也就是说,捕获和处理不是强制性的,这要靠程序员自己去捕获和处理,比如上面代码中的FileNotFoundException在Java当中一定是要被捕捉处理的,但是Kotlin不强制要求你捕捉和处理,为什么Kotlin要这样呢?因为强制捕捉异常会让代码变得复杂,Kotlin有其精简的特性,当然不会强制要求你捕捉异常的啦,不过,有些必须进行捕捉处理的,尽管Kotlin强制要求,我们都要去捕捉和处理。

其实理解表达式很简单,就是表达式一定是有返回值的,这一点一定要记住,一旦理解了这一点,那么Kotlin的所有表达式,就了如指掌了。

10.具名参数,变长参数,默认参数

具名参数,就是通过具体的参数名来传入参数,示例代码如下:

fun main(args: Array) {

    println(add(a1 = 1,a2 = 2))//使用函数add(a1,a2)具体的参数名字"a1"(a1 = 1)和"a2"(a2 = 2)来对函数add(a1,a2)进行调用

}

fun add(a1:Int,a2:Int) = a1+a2

变长参数,什么是变长参数呢?当你的方法不确定要传入几个参数,并且这几个参数的类型相同,那么你就可以使用变长参数的方式来满足你的要求,使用vararg关键字进行声明,示例代码如下:

fun main(args: Array) {


    println(add(1,2,3,4))

    println(add(1,3,4,0,8,2,3,5,6,7,8))



}

fun add(vararg ints:Int):Int{//变长的参数

    var sum = 0
    for(i in ints){

       sum = sum + i

    }

    return sum
}

我们都知道,Java中也存在这种变长参数,但是Java的变长参数只能在方法参数列表的最后面,但是Kotlin就不一样了,kotlin的变长参数可以出现在参数列表的任意位置。示例代码如下:

fun main(args: Array) {


     println(add(true,1,2,3,4,str = "哈哈哈"))

     println(add(false,3,4,0,8,2,3,5,6,7,8,str = "hello"))

     var intArray:IntArray = intArrayOf(1,2,3,4,5)

     println(add(false,*intArray,str = "sasda"))//直接把数组作为变长参数ints的值



}

fun add(falg:Boolean,vararg ints:Int,str:String):Int{

    var sum = 0
    for(i in ints){

        sum = sum + i
    }

    return sum
}

默认参数,在你声明自己的方法或者函数的时候,可以使用默认参数来为你的参数来个初始化,这样做的结果就是,你在调用这个方法的时候,可以不用再次传递参数给它,当然也可以传递参数给他,示例代码如下:

fun main(args: Array) {


    var r = 5.0
    println("半径为${r}cm的圆的面积为:${getYuanMianJi(r = r)}(cm*cm)")

    var r1 = 6.22
    println("半径为${r}cm的圆的面积为:${getYuanMianJi(3.1415,r1)}(cm*cm)")


}


fun getYuanMianJi(pi: Double = 3.14,r:Double) = r*r*pi

输出结果:
半径为5.0cm的圆的面积为:78.5(cm*cm)
半径为6.22cm的圆的面积为:121.5396086(cm*cm)

你可能感兴趣的:(Kotlin)