链接: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
val:用于声明不可变的变量,不可变指的是引用不可变,相当于Java当中的final
var:用于声明可变的变量
fun main(args: Array) {
val a = "a是不可变的变量" //不可变
var another = 3 //可变
println(a)
println(another)
}
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
这种方式叫做匿名函数,有啥用途?目前笔者也不是很清楚,学过的大神说它相当的厉害,所以继续往后学,应该会揭晓。
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类型
其实就和匿名函数一样,写法如下:
{(参数列表) -> [函数体,最后一行是返回值]}
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)
Java当中的类的声明有以下几个方面:
1.构造器
2.成员变量
3.成员方法
4.访问权限的设置
5.静态和非静态的设置
6.为某些成员变量设置get和set方法
对于那些对Java非常熟悉的同学,这些也就不需要特殊说明了把!不熟悉?那现在还不太适合学习Kotlin,理由很简单,因为面向对象思想都没有理解,那之后学习起来相当吃力的,所以,请务必先接触一下Java,再来学习Kotlin就轻松容易的多了。
那么Kotlin如何取声明一个类呢?
关键字还是很Java一样使用”class”关键字声明类
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
}//次级构造函数
}
这基本和Java当中是一样的,看上述代码就知道了
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的成员方法"自我介绍()"
}
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 变量或方法。这会在后面说明。
貌似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
}
}
}
在类前面加”data”修饰符即可达到效果,而且注意的一点就是,无论你有没有在声明类的时候加”data”关键字。
Getters和 Setters
声明一个属性的完整语法是
其初始器(initializer)、getter 和 setter 都是可选的。属性类型如果可以从初始器 (或者从 其 getter 返回值,如下文所示)中推断出来,也可以省略。
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 明白了吧!
分支表达式?啥玩意儿?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分支表达式,一方面掌握了分支语句。
区分起来很简单,一个有返回值,一个没有返回值
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)
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的所有表达式,就了如指掌了。
具名参数,就是通过具体的参数名来传入参数,示例代码如下:
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)