Kotlin我爱编程

kotlin基础知识总结

2018-03-17  本文已影响69人  豆小豆33

目录:
一.环境搭建
二.基础语法
1.函数定义
2.可变参数
3.定义常量与变量
4.NULL检查机制
5.类型转换
三.基本类型
1.数字型,Number(包含整数和浮点等)
2.布尔型(Boolean)
3.数组
4.字符串
5.判断两个对象相等
四.条件语句
1.If
2.When
五.循环语句
1.for
2.While和do while
3.返回和跳转 (continue return break)
4.标签
六.类和对象
1.类声明
2.创建类
3.类构造器
4.抽象类
5.嵌套类
6.内部类
7.类的修饰符
8.类中属性的set,get方法
七.继承
1.kotlin的超类
2.继承的基本实现
3.对构造函数的处理
4.属性重写
八. 接口
九. 泛型
十. 枚举
十一.数据类
十二.密封类

一. 环境搭建(基于android studio 3.0):

buildscript {
    ext.kotlin_version = '1.1.51'
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.0.1'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
    compileSdkVersion 26
    defaultConfig {
        applicationId "kotlin.com.kotlindemo"
        minSdkVersion 19
        targetSdkVersion 26
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:26.1.0'
    implementation 'com.android.support.constraint:constraint-layout:1.0.2'
    compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
}

二. 基础语法

1. 函数定义:

private fun sum(a : Int , b : Int) : Int{
    return a+b
}
public fun sum(a : Int , b : Int) = a + b

2.可变参数:

函数的变长参数可以用 vararg 关键字进行标识:
例子:

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

3. 定义常量与变量:

var <标识符> :<类型> = <初始化值>
val <标识符> :<类型> = <初始化值>
var : 代表当前参数为可变参数
val : 代表当前参数为不可变参数,只可以进行一次赋值。类似于java中的final
例子:

val a : Int = 0
val b = 0
var c : Int = 0
c += 1

4. NULL检查机制:

相比java,kotlin在创建变量和传入变量的时候,就提供了可空相关的标识符

// 可为空 
var age : String? = null
// 可为空,如果age为空,返回null
var age1 = age?.toInt()
// 不能为空
var age2 = age!!.toInt()

5. 类型转换

fun getStringLength(obj : Any): Int? {
    if(obj is String){
        // 进行is判断以后,会自动转化成obj
        return obj.length
    }
    if(obj !is String){
        return null
    }
    return null
}

三. 基本类型

1. 数字型,Number(包含整数和浮点等)

//正确的例子:
val b: Byte = 1 
val i: Int = b.toInt() 
//错误的例子:
val b: Byte = 1 // OK, 字面值是静态检测的
val i: Int = b // 错误

2. 布尔型(Boolean)

和java一致,不做赘述

3. 数组

创建数组的两种方式:
var intArr : IntArray = intArrayof(0,1,2)
var intArr2 : Array<Int> = arrayof(0,1,2)

4. 字符串

Java : var strToInt : Int = Integer.parseInt(str)
Kotlin : var strToInt : Int = str.toInt()
var int : Int = 0
str = int.toString();

5. 判断两个对象相等

四. 条件语句

1. If:

val x = 5
val y = 6
val a = if(x > y) 5 else 6

2. When:

着重强调一下when。在kotlin之中,大家会发现找不到switch了。因为switch被when给替代了。可想而知,when的地位有多高了吧。下面介绍一下when的用法。

五. 循环语句

1. for:

for循环可以便利所有实现迭代器(iterator)的对象,介绍几种实现方式

for(item in collection){
      print(item)
    }
}
for(i in array.indices){
    array[i] // i是索引值
}
for((index,value) in array.withIndex()){
    value = array[index]
}

2. While和do while

实现和java完全一致,不做赘述。
例子:

while( 布尔表达式 ) {
  //循环内容
}
do {
                 //代码语句
}while(布尔表达式);

3. 返回和跳转 (continue return break)

使用方式和java完全一致,简单介绍

4. 标签

好了,本节重头戏来了。标签是一个非常好用的东西。他可以让我们在多循环嵌套的情况下,进行穿插处理。不会像java一样,continue,break只能针对当前循环。那么让我们来体验下标签吧。

fun labelDemo(){
    val intArr = intArrayOf(0,1,2)
    val intArr2 = intArrayOf(0,1,2)
    Log.i(TAG,"start for")
    intArrFor@for (int in intArr){
        Log.i(TAG,"for intArr int : $int")
        intArr2For@for (int2 in intArr2){
        // 每一次退出,回到intArrFor
            if(int2 == 1) break@intArrFor
            Log.i(TAG,"for intArr2 int2 : $int2")
        }
    }
    Log.i(TAG,"end for")
}

备注:暂时缺失对标签在return应用的介绍,讲真,小编自己还没搞明白。搞明白以后再加上来。

六. 类和对象

1. 类声明

class <类名称> {
    // 函数
    fun foo(){}
    }
}

2. 创建类

class Student{
    val name = “小明”
    val age = 5
}
// 创建类
val stu = Student()
stu.name
stu.age

3. 类构造器

kotlin中类分成主构造器和次构造器。一个类可以有主构造器和多个次构造器。

class Preson constructor(name : String , age : Int){

}

如果主构造器没有任何注解,也没有任何可修饰符,那么constructor可以隐藏

class Person(name : String , age : Int){

}
class Person (name : String){
    val personName : String = name
    init{
      personName = name
    }  
}

4. 抽象类

open class Base(){
    open fun baseFun(){}
}
abstract class Child() : Base(){
    abstract fun baseFun(){}
}

5. 嵌套类

嵌套类引用不了外部类的成员,这和Java类似,相当于隐式的外部类。但是在实现上和java略有差异。
java:通过在内部类中加上一个static,说明这是嵌套类。
kotlin:在类的内部再创建一个类的时候,如果加任何修饰符,那么就是嵌套类。
例子

class Outer{
    val a = “”
    // 嵌套类
    class Inner{
        fun foo(){
        }
    }
}

6. 内部类

kotlin内部类需要使用关键字inner来表示。相比嵌套类,内部类可以使用外部类的引用。从而访问外部类的属性和方法等。
例子

class Outer{
  val a = ""
  /**
  * inner标记一个类是内部类
  * 可以引用外部类的成员
  * 采用this@类名方式,获取到外部类的this对象
  */
  inner class inner{
       fun foo(){
          val innerA = this@Outer.a
       }
   }
}

7. 类的修饰符

8.类中属性的set,get方法

set和get在很多教程里都会被放在类的属性里作为一个小点来讲。为什么小编要单独拿出来。我相信很多人如果没有接触过property。都会跟小编有一样一头雾水,所以小编认为有必要再专门说明一下。

class Student{
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
// 所以,一般设置一个参数,都用以下方式实现。
Student stu = new Student();
stu.setName("小明");
class Student{
    val name = ""
}
// 设置参数
val stu = Student()
stu.name = "小明"

看到这里,肯定会有很多小伙伴会有疑问。java如果把参数的权限变成public也可以用和kotlin一样的方式。但是小编在这里告诉你,不要太天真。来让我们看一看,在我们使用kotlin设置参数的时候他,kotlin偷偷背着我们做了什么。

class Student {

    var name : String = "小豆"
    get() = field + "啦啦啦"
    set(value) {
        field = value + "拉拉"
    }
    
    val age = 10
    set(value) {} // 会报错

}

七. 继承

1. kotlin的超类

所有的kotlin都继承Any这个类,算是kotlin中所有类的超类。但他不是object,可以理解成object在java中的地位。

equals()

hashCode()

toString()
toString()

equals()

hashCode()

getClass()

clone()

finalize()

notify()

notifyAll()

wait()

wait(long)

wait(long,int)  

2. 继承的基本实现

类需要加上关键字open,因为类是默认final的。同时抽象类默认加上open
例子:

open class Base(age : Int)

class Child(age : Int) : Base(age){}

3. 对构造函数的处理

// 父类
open class Base(name : String , age : Int){
}
// 子类
class Child(name : String , age : Int, no : Int) : Base(name , age){
}
// 测试
fun main(args: Array<String>) {
    val s =  Child("小豆", 18,10)
    println("学生名: ${s.name}")
    println("年龄: ${s.age}")
    println("学生号: ${s.no}")
}
open class Base(name : String) {

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

    }

}

class Student : Base{

    constructor(name : String) : super(name){
        
    }
    
}

4. 属性重写

属性重写和函数继承一样。需要在属性前加上关键字open。属性重写使用 override 关键字,属性必须具有兼容类型,每一个声明的属性都可以通过初始化程序或者getter方法被重写:
例子

open class Base {

    open val name = ""

    open fun base(){
        print("父类Base")
    }

}

open class Student : Base() {

    override val name: String
        get() = super.name

    override fun base() {
        print("子类base")
    }

}

八. 接口

Kotlin 接口与 Java 8 类似,使用 interface 关键字定义接口,允许方法有默认实现

interface InterDemo {

    fun foo(){ }

}
class Child : InterDemo{
    override  fun foo(){
    }
}
open class Base {
    open fun base(){
        print("父类Base")
    }
}

open class Student : Base() {
    override fun base() {
        print("子类base")
    }
}

fun main(args: Array<String>) {
    val s =  Student()
    s.base();
}
// 输出结果
子类base

由于kolin中接口中的函数是可以有初始化代码的,所以就遇到了继承和实现的接口和类中,包含同一个函数名的情况。我们需要使用super<类名>.<方法名>来选择调用
例子:

open class A {
    open fun base(){ }
}

interface B {
    fun base(){ }
}

class C() : A() , B {
    override fun base() {
        super<A>.base()
        super<B>.base()
    }
}

九. 泛型

泛型,即 "参数化类型",将类型参数化,可以用在类,接口,方法上。与 Java 一样,Kotlin 也提供泛型,为类型安全提供保证,消除类型强转的烦恼。

class Person<T>(t : T) {
    val value = t
}
val person = Person<String>("小豆")
val person = Person("小豆")
 fun <T> box(value : T){
        print(value)
}
//以下全都合法
val box1 = box("小豆1")
val box2 = box<String>("小豆2")

在 Java 泛型里,有通配符这种东西,我们要用 ? extends T 指定类型参数的上限,用 ? super T 指定类型参数的下限。Kotlin 抛弃了这个系统,引用了生产者和消费者的概念。

什么是生产者?生产者是那些只能 读取 数据的对象;
什么是消费者?消费者是那些只能 写入 数据的对象;
要理解这个概念,我们可以看一个例子:

public interface Collection<E> extends Iterable<E> {
  boolean add(E e);
  boolean addAll(Collection<? extends E> c);
}

这是 Collection 接口的add() 和 addAll() 方法,传入它们的类型参数一个是 E ,一个是 ? extends E,为什么呢?这两个方法之间不就是批量操作的区别吗?为什么一个只接受 E 类型的参数,另一个却接受 ? extend E 的类型?

这是因为,Java 泛型是不型变的,也就是说,虽然 String 类型是 Object 类型的子类型,但 Collection<String> 并不是 Collection<Object> 的子类型。

对于一个 Collection<Object> 来说,因为 String 是 Object 的子类型,一个 String 对象就是 Object 类型,所以可以直接把它添加入 Collection<Object> 里,add() 方法的类型参数因为可以设为 E;而想把 Collection<String> 添加入 Collection<Object> 时,因为 Java 泛型不型变的原因,就会出现编译错误,必须用 ? extends E 将 Collection<String> 囊括到 Collection<Object> 里。

从另一个角度看,对于一个 Collection<A>,我们从其中读取出一个对象,这个对象可以是 A 的子类型,也可以是 A 类型,这种特性叫 协变(Convariant);而要向 Collection<A> 写入一个对象时,我们既可以写入一个 A 类型对象,也可以写入 A 的父类型,这种特性叫 逆协变(contravariance),协变和逆协变都是类型安全的。

从这个角度来说,我们可以把那些只能保证读取数据时类型安全的对象叫做生产者,用 out T 标记;把那些只能保证写入数据安全时类型安全的对象叫做消费者,用 in T 标记。

如果你觉得太晦涩难懂,就这么记吧:out T 等价于 ? extends T,in T 等价于 ? super T,此外还有 * 等价于 ?。

声明处型变
Kotlin 对 Java 泛型最大的改动就是添加了声明处型变。看下面的例子:

interface Source<T> {
  T nextT();
}

void demo(Source<String> str) {
  // Java 中这种写法是不允许的
  Source<Object> obj = str;
  /*...*/
}

因为 Java 泛型是不型变的,Source<String> 不是 Source<Object> 的子类型,所以不能把 Source<String> 类型变量赋给 Source<Object> 类型变量。

现在用 Kotlin 改写上面的接口声明:

interface Source<out T> {
  T nextT();
}

我们在接口的声明处用 out T 做了生产者声明,因为这个接口只有一个读取数据的 nextT() 方法,可以视为生产者。把这个接口的类型参数声明为生产者后,就可以实现安全的类型协变了:

fun demo(Source<String> str) {
  val obj: Source<Any> = str // 合法的类型协变
  /*...*/
}

十. 枚举

enum class Color {
    RED,BLUE,GREEN
}
enum class Color(value : Int) {
    RED(100),BLUE(200),GREEN(200)
}
Color red = Color.valueOf("RED");
Color[] values = Color.values();

十一.数据类

data class User(val name : String , var age : Int)
//创建data类
data class User(name : String , age : Int)
val user = User("aaa",12)
// 拷贝过程中重新赋值
val userChangeCopy = user.copy(name = "小豆")
fun copy(name: String = this.name, age: Int = this.age) = User(name, age)

十二.密封类

sealed class Expr
data class Const(val number: Double) : Expr()
data class Sum(val e1: Expr, val e2: Expr) : Expr()
object NotANumber : Expr()

fun eval(expr: Expr): Double = when (expr) {
    is Const -> expr.number
    is Sum -> eval(expr.e1) + eval(expr.e2)
    NotANumber -> Double.NaN
}
fun eval(expr: Expr): Double = when(expr) {
    is Expr.Const -> expr.number
    is Expr.Sum -> eval(expr.e1) + eval(expr.e2)
    Expr.NotANumber -> Double.NaN
    // 不再需要 `else` 子句,因为我们已经覆盖了所有的情况
}

暂未了解清楚:
1.属性重写
2.标签return用法
3.约束泛型
4.型变
5.星号投射
6.密封类
7.数据类
待补充:
1.委托
2.扩展

上一篇下一篇

猜你喜欢

热点阅读