kotlin入门潜修之基础篇—基础语法

本文收录于 kotlin入门潜修专题系列,欢迎学习交流。

创作不易,如有转载,还请备注。

基础语法

基本类型

学习一门新的语言首先要学习其基本类型,这是一门语言世界的基石。

在kotlin中,一切都是以对象的类型存在,这点与java不同。但实际上有很多类型在runtime的时候都会被替换为原生类型,只不过对于用户而言都是普通的对象类型而已。kotlin中的基本类型可以分为几个大部分:numbers(数字)、characters(字符)、booleans(布尔值)、arrays(数组)以及strings(字符串)。这些类型由于都是对象类型,对象的共有特性都会支持,比如可以赋值为null等。

数字类型(Numbers)

kotlin中对数字的处理和java很像,但是依然有些许区别,比如kotlin中不再有隐式转换、常量表示有些时候也和java中不同(如支持下划线分割)等等。kotlin内置有6种基本数字类型(注意kotlin中字符不是数字),如下所示:

类型 位数
Double 64
Float 32
Long 64
Int 32
Short 16
Byte 8

数字字面常量

kotlin中的数字字面常量有三种类型:

  1. 十进制:表示方式同java,如100,1000等,当使用特定类型时加上后缀标识符即可,如Long类型 124L,Float类型:123.0F。对于小数如果不加后缀F(或f,大小写都可以)则默认为Double类型。
  2. 十六进制: 如0xFF
  3. 二进制: 如0b00110011

注意,kotlin中不支持八进制数字字面常量。

kotlin为了提高字面常量的可读性,支持对数字进行下划线分割(1.1开始),如下所示:

val intNum = 1_000
val longNum = 1234_5678_9012_3456L
val hexBytes = 0xFF_FF_FF_FF
val bytes = 0b11111111_00000000_10101010_01010101

在java中,数字一般都是以原生类型存在jvm中的,只有少数情况下会使用装箱操作,比如使用泛型的时候。由于kotlin中一切即对象,所以这点与java不同,即所有的数字都要用对象类型来表示。

接着来看下kotlin中的比较操作,java中整型数字的比较示例如下:

Integer i = new Integer(10000);
Integer j = i;
Integer k = i;
Integer h = new Integer(10000);
System.out.println(j == k); //打印 'true'
System.out.println(j == h); //打印 'false'
System.out.println(j.equals(k)); //打印 'true'

上面代码大家应该都很清楚,在java中==表示的是对两个对象的地址进行比较,而equals表示的是对内容进行比较。

再来看下kotlin中的整型数字如何进行比较:

val a: Int = 1000
println(a === a) // 打印 'true'
val boxedA: Int? = a
val anotherBoxedA: Int? = a
println(boxedA == anotherBoxedA) //打印 'true'
println(boxedA === anotherBoxedA) //打印 'true',这里和上一个语句的区别:注意区分“==”和“===”操作符。
println(boxedA?.equals(anotherBoxedA))//打印 'true',

上面代码提到了三个比较方法:==、===和equals,那么三者有什么区别呢?

首先看下最简单的euqals方法,这个和java中的equals方法是一致的,都是用于内容比较,而不是比较地址;

然后再来看下双等号(==)所表达的含义,其实在kotlin中,双等号就是个操作符,其对应的实现就是equals方法,如下所示:

    public open operator fun equals(other: Any?): Boolean

也就是说当比较对象都不为null时,==和equals方法的功能是一模一样的;

最后再来看下三等号(===),这个在kotlin中,实际上比较的是两个对象的地址,其功能和java中的双等号(==)一致。

因此,在进行内容比较的时候建议使用双等号(==)或者equals方法,而在进行地址比较的时候则使用三等号(===)。

数字类型显示转换

kotlin不在像java那样可以进行隐式转换(是指原生数据类型,如int可以隐式赋值为long),在kotlin中必须要进行显示转换:

// 下面的代码在kotlin中是无法变编译的
val a: Int? = 1 // 包裹类型(java.lang.Integer)
val b: Long? = a // 这里即报错,两个类型不一致,一个是Int?,一个是Long?

解决方案及时采用显示转换

 val a: Int? = 1 
 val b: Long? = a?.toLong()

kotlin中,每一个数字类型都对应有这样一个方法,如下所示:
— toByte(): Byte
— toShort(): Short
— toInt(): Int
— toLong(): Long
— toFloat(): Float
— toDouble(): Double
— toChar(): Char

如果不允许隐式转换,那么用户在计算表达式中有两种数字类型怎么解决?如下所示:

val l = 1L + 3 // Long + Int => Long

上面代码是允许出现的,这是因为kotlin会根据上下文环境和操作符(这里是+)的重载自动推断相应类型。

位操作符

java中的位操作符有左移(<<)、右移(>>)等等,kotlin中不在支持这些操作符,转而用方法替代:

val x = (1 shl 2) and 0x01

这点特性确实很赞,毕竟不用再去区分<<到底是左移还是右移了。
kotlin提供了以下位操作相关方法,但支持Int和Long类型。如下所示:
— shl(bits) – 有符号左移
— shr(bits) – 有符号右移
— ushr(bits) – 无符号右移
— and(bits) – 与操作
— or(bits) – 或操作
— xor(bits) – 异或操作
— inv() – 倒置操作

浮点数比较

— 是否相等: a == b and a != b
— 大小比较: a < b, a > b, a <= b, a >= b
— 范围操作符: a..b, x in a..b, x !in a..b
其中是否相等的比较和大小比较和java中一致,但是kotlin新增了范围操作符,用于检测某个数字是否在指定的范围内。这点还是很方便的。

            val i = 1.1
            if (i in 0..2) {
                println(i.toString().plus(" in 0-2"))//打印 '1.1 in 0-2'
            }

以上是对标准浮点数类型的比较,然而对于非标准浮点数怎么进行比较?比如对包含有浮点数的list进行排序,这个时候kotlin和java一样,会调用Float或者Double的equals、compareTo进行比较。

kotlin对浮点数字类型还定义了一个NaN值,这个值表示当前比较对象并不是数字,同时kotlin还对0进行了正负区分,这在调用compareTo的时候会产生和想象中不同的效果,具体事例如下:

       val i :Double = -0.0
       val j :Double = 0.0
       println(i == j)//打印 'true'
       println(i.compareTo(j))//打印 '-1',表示 i < j
       println(Double.NaN == Double.NaN)//打印 'false'
       println(Double.NaN.compareTo(Double.NaN))//打印 '0',表示 NaN = NaN
       println(Double.NaN.compareTo(Double.POSITIVE_INFINITY))//打印 '1',表示 NaN > 无穷大

字符类型(Characters)

字符类型的关键字是Char。

kotlin中的字符类型是Char,与java中区别就是kotlin中的字符无法直接作为数字来表示,示例如下:

java代码示例:

        char c = 'a';
        int i = c;
        System.out.println(i);//打印 '97'

kotlin代码示例:

            val c :Char = 'a'
            val i :Int = c//报错,c是Char类型,Int是整型,无法赋值

但是我们可以显示的对Char进行转换,如下所示:

            val c :Char = 'a'
            val i :Int = c.toInt()
            println(i)//打印 '97'

布尔类型(Booleans)

布尔类型的关键字是:Boolean
同java一样,Boolean类型数据有两种值即true和false,同样,也支持一下操作符:

— || – 或操作,支持截断
— && – 与操作,支持截断
— ! 非操作

上述中的支持截断的意思是在&&或者||操作的时候只要第一个不满足或满足条件就不再执行&&或者||之后的语句,示例如下:

        @JvmStatic fun main(args: Array<String>) {
           if(getFalse() && getTrue()){
           }

            println("&& test end ...")

            if (getTrue() || getFalse()){
            }

            println("|| test end")
        }

        fun getTrue():Boolean {
            System.out.println("getTrue execute...")
            return true
        }

        fun getFalse():Boolean {
            System.out.println("getFalse execute...")
            return false
        }

以上打印为结果为

getFalse execute...
&& test end ...
getTrue execute...
|| test end

即在&&测试中,只要第一个(getFalse)返回了false,就不会执行下一个操作(即getTrue),||也是如此。

数组(Arrays)

数组的关键字为:Array

kotlin以Array为关键字来表示数组,提供诸如get、set等方法以及size属性等等,同时也支持操作符[],示例如下:

            val arr1: Array<Int> = arrayOf(1, 2, 3)
            println(intArr[0])//打印’1‘
            arr1.forEach(::println)//打印'1 2 3'

            val arr2: Array<Int?> = arrayOfNulls(3)
            arr2.forEach(::println)//打印'null null null'

            val arr3: Array<String> = Array(5, { i -> (i + i).toString() })
            arr3.forEach(::println)//打印'0 2 4 6 8'

需要注意的是Array只有一个构造方法,即上面代码中的最后一个构建数组的示例,除此之外没有其他构造方法。该构造方法第一个参数为数组大小,第二个参数接收一个方法,进行数组元素的初始化。

kotlin中的数组是不可变的,无法像java那样进行向上类型的赋值,如下所示:
java代码示例

        Object [] str = new String[]{"1","2"};//java中是可以这样赋值

kotlin代码示例

            val intArr: Array<Int> = arrayOf(1,3)
            val objs:Array<Any> = intArr//编译错误,无法将Array<Int>赋值于Array<Any>
            val objs:Array<out Any> = intArr//编译正确,这里的out关键字表示只要继承于Any的任何类型都可以转。

注意上述代码中,Any是kotlin中所有类的基类,相当于java中的Object。

除此之外,kotlin还提供了特定类型数组,如ByteArray, ShortArray, IntArray等等,用户可以直接使用这些数组类型以满足需求。

字符串类型(Strings)

kotlin中字符串类型关键字为String

在kotlin中String是不可变的,同java一样,kotlin对String提供了很丰富的支持。具体事例如下:

            val str: String = "hello"
            println(str[0])//打印'h',标明支持[]操作符
            for (c in str) {//支持for ... in遍历
                print(c.plus(" "))//打印'h e l l o '
            }
            val str2 =  str + " word"//支持+运算符
            println(str2)//打印’hello word‘

字符串字面常量

kotlin中,字符串字面常量有两种,一种是包含转义字符的字符串,一种是原生字符串(raw string),示例如下:

            val str: String = "hello, world!\n"
            print(str)//打印 'hello,world'

            val text: String = """
    for (c in "text")
        print(c)
"""
            println(text)//打印 原生格式字符串,见下文

            val text2: String = """
 |first line
|second line"""
            
            println(text2)//打印原格式字符串
            println(text2.trimMargin())//打印去掉|之前的所有字符串

上述代码,text会被保持原来格式的打印出来,而text2中有个|字符,这个是kotlin中默认作为margin前缀的字符,当调用trimMargin的时候,会默认清楚|之前的所有空格,并保持对齐,朋友们可自行试验。

字符串模板

kotlin支持字符模板,简单的说就是可以在字符串中解析变量,示例如下:

            val s = "abcd"
            println("$s.length is ${s.length}") //打印 'abcd.length is 4'
            val unit = '$'
            val price = """ ${unit}1.11"""//这里可以看出字符串模板也支持row string
            println(price)//打印 $1.11

至此我们就将kotlin中的基本类型讲完了。

需要说明下,上文中有很多写法可能有朋友暂时还看不明白(比如泛型、运算符重载等等)。不过,没有关系,这些内容都会在后面文章中一一阐述,等看完本系列文章,一切就迎刃而解了。看本篇文章的时候只需关注基础语法即可。

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