Kotlin-基础笔记整理一

1、方法的定义:
fun sum(a: Int, b: Int): Int {   // Int 参数a和b,返回值 Int
    return a + b
}
//表达式作为函数体,返回类型自动推断
fun sum(a: Int, b: Int) = a + b
public fun sum(a: Int, b: Int): Int = a + b   // public 方法则必须明确写出返回类型

fun printSum(a: Int, b: Int): Unit { 
    print(a + b)
}

//Unit相当于java中的void
// 如果是返回 Unit类型,则可以省略(对于public方法也是这样):
public fun printSum(a: Int, b: Int) { 
    print(a + b)
}

可变长参数函数

fun vars(vararg v:Int){
    for(vt in v){
        print(vt)
    }
}

// 测试
fun main(args: Array<String>) {
    vars(1,2,3,4,5)  // 输出12345
}

lambda(匿名函数)

// 测试
fun main(args: Array<String>) {
    val sumLambda: (Int, Int) -> Int = {x,y -> x+y}
    println(sumLambda(1,2))  // 输出 3
}
2、常量与变量:

var和val的区别:
val:定义的变量是不可修改的(类似于java中的final)
var:定义的变量是可以修改的

常量与变量都可以没有初始化值,但是在引用前必须初始化
编译器支持自动类型判断,即声明时可以不指定类型,由编译器判断。

val a: Int = 1
val b = 1       // 系统自动推断变量类型为Int
val c: Int      // 如果不在声明时初始化则必须提供变量类型
c = 1           // 明确赋值
var x = 5        // 系统自动推断变量类型为Int
x += 1           // 变量可修改
3、NULL检查机制:

代码中可为空的参数,使用时需要进行空判断处理,2种处理方式
1、字段后加!!像Java一样抛出空异常
2、字段后加?可不做处理,返回值为 null或配合?:做空判断处理

任何对象都分为可null和不可null,当对象可以为null时,使用的时候必须加判断,或者加上!!

fun main(args: Array<String>) {
//类型后面加?表示可为空
var age: String? = "23" 
//抛出空指针异常
val ages = age!!.toInt()
//不做处理返回 null
val ages1 = age?.toInt()
//age为空返回-1
val ages2 = age?.toInt() ?: -1
//-----------------------------------------------------------
    //使用
    val token = token()
    //第一种方法
    if (token != null) {//不加判断会报错
        println(token.length)
        //token?.length  //如果token为null,则token?.length返回null,不会报错
    }
 //第二种方法,当token为null时,会抛出空异常
 //println(token!!.length) 
}
//声明返回值可以为null
fun token(): String? {
    return null
}
4、类型检测及自动类型转换:

使用 is 运算符检测一个表达式是否某类型的一个实例(类似于Java中的instanceof关键字)

fun getStringLength(obj: Any): Int? {
    if (obj !is String)
        return null
    // 在这个分支中, `obj` 的类型会被自动转换为 `String`
    //---------------------------------------------------
    // 在 `&&` 运算符的右侧, `obj` 的类型会被自动转换为 `String`
    /*  if (obj is String && obj.length > 0)
          return obj.length*/
    //---------------------------------------------------
    return obj.length
}
5、区间:

区间表达式由具有操作符形式 .. 的 rangeTo 函数辅以 in 和 !in 形成

for (i in 1..4) print(i) // 输出“1234”

for (i in 4..1) print(i) // 什么都不输出

if (i in 1..10) { // 等同于 1 <= i && i <= 10
    println(i)
}

// 使用 step 指定步长
for (i in 1..4 step 2) print(i) // 输出“13”

for (i in 4 downTo 1 step 2) print(i) // 输出“42”

// 使用 until 函数排除结束元素
for (i in 1 until 10) {   // i in [1, 10) 排除了 10
     println(i)
}
6、比较数字:

Kotlin 中,三个等号 === 表示比较对象地址,两个 == 表示比较两个值大小

fun main(args: Array<String>) {
    val a: Int = 10000
    println(a === a) // true,值相等,对象地址相等

    //经过了装箱,创建了两个不同的对象
    val boxedA: Int? = a
    val anotherBoxedA: Int? = a

    //虽然经过了装箱,但是值是相等的,都是10000
    println(boxedA === anotherBoxedA) //  false,值相等,对象地址不一样
    println(boxedA == anotherBoxedA) // true,值相等
}
7、类型转换:
  val b: Byte = 1 // OK, 字面值是静态检测的
    //al i: Int = b // 错误
    val i: Int = b.toInt() // OK

toByte(): Byte
toShort(): Short
toInt(): Int
toLong(): Long
toFloat(): Float
toDouble(): Double
toChar(): Char

8、数组:

数组的创建两种方式:
1、一种是使用函数arrayOf()
2、另外一种是使用工厂函数。

fun main(args: Array<String>) {
    //[1,2,3]
    val a = arrayOf(1, 2, 3)
    //[0,2,4]
    val b = Array(3, { i -> (i * 2) })

    //读取数组内容
    println(a[0])    // 输出结果:1
    println(b[1])    // 输出结果:2
}

除了类Array,还有ByteArray, ShortArray, IntArray,用来表示各个类型的数组

9、字符串:

和 Java 一样,String 是不可变的

 var str = "1234";
    for (c in str) {//遍历打印字符串
        println(c)
    }
    //----------------------------
    val text = """
    多行字符串
    多行字符串
    """.trimMargin()//去掉前置空格
10、条件控制:
fun main(args: Array<String>) {
    var x = 0
    if(x>0){
        println("x 大于 0")
    }else if(x==0){
        println("x 等于 0")
    }else{
        println("x 小于 0")
    }

    var a = 1
    var b = 2
    val c = if (a>=b) a else b
    println("c 的值为 $c")
}

使用区间

fun main(args: Array<String>) {
    val x = 5
    val y = 9
    if (x in 1..8) {
        println("x 在区间内")
    }
}
11、When 表达式:

when 将它的参数和所有的分支条件顺序比较,直到某个分支满足条件。

when 既可以被当做表达式使用也可以被当做语句使用。

when (x) {
    1 -> print("x == 1")
    2 -> print("x == 2")
    else -> { // 注意这个块
        print("x 不是 1 ,也不是 2")
    }
}
//----------------------------------------
when (x) {
    0, 1 -> print("x == 0 or x == 1")
    else -> print("otherwise")
}
//-----------------------------------------
when (x) {
    in 1..10 -> print("x is in the range")
    in validNumbers -> print("x is valid")
    !in 10..20 -> print("x is outside the range")
    else -> print("none of the above")
}
//----------------------------------------------
fun hasPrefix(x: Any) = when(x) {
    is String -> x.startsWith("prefix")
    else -> false
}
//----------------------------------------------
//用来取代if-else if
when {
    x.isOdd() -> print("x is odd")
    x.isEven() -> print("x is even")
    else -> print("x is funny")
}

在 when 中,else 等同 switch 的 default

12、循环控制:

For 循环

fun main(args: Array<String>) {
    val items = listOf("apple", "banana", "kiwi")
    for (item in items) {
        println(item)
    }

    for (index in items.indices) {
        println("item at $index is ${items[index]}")
    }
}

while 与 do...while 循环

fun main(args: Array<String>) {
    println("----while 使用-----")
    var x = 5
    while (x > 0) {
        println( x--)
    }
    println("----do...while 使用-----")
    var y = 5
    do {
        println(y--)
    } while(y>0)
}
11、类的定义和类的属性:
//constructor...主构造函数
//如果主构造器没有任何注解,也没有任何可见度修饰符,那么constructor关键字可以省略
class Person constructor(firstName: String) {
    var name: String = "张三"
}

fun main(args: Array<String>) {
    var person = Person("李四")//Kotlin 中没有 new 关键字
    println("姓名:" + person.name)
}
  • getter 和 setter

getter 和 setter 都是可选
如果属性类型可以从初始化语句或者类的成员函数中推断出来,那就可以省去类型,val不允许设置setter函数,因为它是只读的。

var allByDefault: Int? // 错误: 需要一个初始化语句, 默认实现了 getter 和 setter 方法
var initialized = 1    // 类型为 Int, 默认实现了 getter 和 setter
val simple: Int?       // 类型为 Int ,默认实现 getter ,但必须在构造函数中初始化
val inferredType = 1   // 类型为 Int 类型,默认实现 getter

示例:

class Person {
    var lastName: String = "zheng"
    //当调用person.lastName,获取值field.toUpperCase()
    //field(后端变量)   toUpperCase将变量赋值后转换为大写
        get() = field.toUpperCase()
        set//当调用person.lastName = "wang",触发set
    var no: Int = 100
        get() = field
        set(value) {//value当前传递过来的值,在赋值给field(后端变量)之前做一些操作改变值
            if (value < 10) {
                field = value  //传入的值小于10返回改值
            } else {
                field = -1     //如果传入的值大于等于10 返回-1
            }
        }
    var heiht: Float = 145.4f
        private set//set方法为私有是,外部不可调
}

fun main(args: Array<String>) {
    var person = Person()
    person.lastName = "wang"//将wang赋值给lastName
    println("lastName:${person.lastName}")
    person.no = 9
    println("no:${person.no}")
}
  • 输出
    lastName:WANG
    no:9

Kotlin 中类不能有字段。提供了 Backing Fields(后端变量) 机制,备用字段使用field关键字声明,field 关键词只能用于属性的访问器

  • 非空属性必须在定义的时候初始化,kotlin提供了一种可以延迟初始化的方案,使用 lateinit 关键字描述属性
 class MyTest {
    private lateinit var person: Person
    fun setUp() {
        person = Person("哇哈哈")
    }
    fun test() {
        println(person.name)
    }
}
fun main(args: Array<String>) {
    val myTest=MyTest()
    myTest.setUp()
    myTest.test()
}
  • 主构造器

主构造器中不能包含任何代码,初始化代码可以放在初始化代码段中,初始化代码段使用 init 关键字作为前缀

class Person constructor(firstName: String) {
    init {
        println("FirstName is $firstName")
    }
}

构造器有注解,或者有可见度修饰符,这时constructor关键字是必须的,注解和修饰符要放在它之前。

  • 次构造函数
    需要加前缀 constructor
class MyTest(name: String="") {
    var strName: String = ""
    var age: Int = 0
    init {
        strName = name
    }
    //同一个类中代理另一个构造函数使用 this 关键字
    constructor(name: String, age: Int) : this(name) {
        strName = name
        this.age = age
    }
    fun print() {
        println("strName" + strName + "-----age" + age)
    }
}
fun main(args: Array<String>) {
    val myTest1 = MyTest("传递给次构造函数", 20)
    myTest1.print()
    val myTest2 = MyTest("传递给主造函数")
    myTest2.print()
}
  • 输出
    strName传递给次构造函数-----age20
    strName传递给主造函数-----age0

如果一个非抽象类没有声明构造函数(主构造函数或次构造函数),它会产生一个没有参数的构造函数。构造函数是 public 。如果你不想你的类有公共的构造函数,你就得声明一个空的主构造函数:

class DontCreateMe private constructor () {
}
12、抽象类和嵌套类:
  • 抽象类
open class Base {//open 标识此类可以被继承
    open fun f() {}
}

abstract class Derived : Base() {
    override abstract fun f()
}

注意:无需对抽象类或抽象成员标注open注解

  • 嵌套类
class Outer {                  // 外部类
    private val bar: Int = 1
    class Nested {             // 嵌套类
        fun foo() = 2
    }
}

fun main(args: Array<String>) {
    val demo = Outer.Nested().foo() // 调用格式:外部类.嵌套类.嵌套类方法/属性
    println(demo)    // == 2
}
13、内部类和匿名内部类:
  • 内部类
class Outer {
    private val bar: Int = 1
    var v = "成员属性"

    /**嵌套内部类**/
    //类标记为inner,可以访问外部类成员:
    inner class Inner {
        fun foo() = bar  // 访问外部类成员

        fun innerTest() {
            var o = this@Outer //获取外部类的对象
            println("内部类可以引用外部类的成员,例如:" + o.v)
        }
    }
}

fun main(args: Array<String>) {
    val demo = Outer().Inner().foo()
    println(demo) //   1
    val demo2 = Outer().Inner().innerTest()
    println(demo2)   // 内部类可以引用外部类的成员,例如:成员属性
}

要访问来自外部作用域的 this,我们使用this@label,其中 @label 是一个 代指 this 来源的标签

  • 匿名内部类
class Test {
    fun setInterFace(test: TestInterFace) {
        test.test()
    }
}

/**
 * 定义接口
 */
interface TestInterFace {
    fun test()
}

fun main(args: Array<String>) {
    var test = Test()

    /**
     * 采用对象表达式来创建接口对象,即匿名内部类的实例。
     */
    test.setInterFace(object : TestInterFace {
        override fun test() {
            println("对象表达式创建匿名内部类的实例")
        }
    })
}
14、类的修饰符:
  • classModifier: 类属性修饰符,标示类本身特性。
abstract    // 抽象类  
final       // 类不可继承,默认属性
enum        // 枚举类
open        // 类可继承,类默认是final的
annotation  // 注解类
  • accessModifier: 访问权限修饰符
private    // 仅在同一个文件中可见
protected  // 同一个文件中或子类可见
public     // 所有调用的地方都可见
internal   // 同一个模块中可见
15、继承:

Kotlin 中所有类都继承该 Any 类,它是所有类的超类,对于没有超类型声明的类是默认超类

如果一个类要被继承,可以使用 open 关键字进行修饰

open class Base(p: Int)           // 定义基类

class Derived(p: Int) : Base(p)
  • 子类有主构造函数
    则基类必须在主构造函数中立即初始化
open class Person2(var name : String, var age : Int){// 基类
}

class Student(name : String, age : Int, var no : String, var score : Int) : Person2(name, age) {//子类
}
  • 子类没有主构造函数
    则必须在每一个二级构造函数中用 super 关键字初始化基类,或者在代理另一个构造函数。初始化基类时,可以调用基类的不同构造方法。
class Student : Person {
    constructor(ctx: Context) : super(ctx) {
    } 

    constructor(ctx: Context, attrs: AttributeSet) : super(ctx,attrs) {
    }
}
16、重写:

在基类中,使用fun声明函数时,此函数默认为final修饰,不能被子类重写。如果允许子类重写该函数,那么就要手动添加 open 修饰它, 子类重写方法使用 override 关键词:

/**用户基类**/
open class Person{
    open fun study(){       // 允许子类重写
        println("我毕业了")
    }
}
/**子类继承 Person 类**/
class Student : Person() {
    override fun study(){    // 重写方法
        println("我在读大学")
    }
}

多个相同的方法(继承或者实现自其他类,如A、B类),则必须要重写该方法,使用super范型去选择性地调用父类的实现。

  • 示例
open class A {
    open fun f () { print("A") }
    fun a() { print("a") }
}
interface B {
    fun f() { print("B") } //接口的成员变量默认是 open 的
    fun b() { print("b") }
}
class C() : A() , B{
    override fun f() {
        super<A>.f()//调用 A.f()
        super<B>.f()//调用 B.f()
    }
}
fun main(args: Array<String>) {
    val c =  C()
    c.f();

}
  • 输出
    AB
  • 属性重写
    使用 override 关键字,属性必须具有兼容类型,每一个声明的属性都可以通过初始化程序或者getter方法被重写:
interface Foo {
    val count: Int
}

class Bar1(override val count: Int) : Foo

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

推荐阅读更多精彩内容