美文网首页
Kotlin-基础笔记整理一

Kotlin-基础笔记整理一

作者: roczheng | 来源:发表于2018-12-19 15:21 被阅读0次
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
}

相关文章

网友评论

      本文标题:Kotlin-基础笔记整理一

      本文链接:https://www.haomeiwen.com/subject/kwigqqtx.html