Kotlin基础学习-入门篇

本篇文章来自郭霖大佬的第一行代码中的Kotlin教程,笔者只是在学习Kotlin过程中记录学习过程。

Kotlin系列已更新:

Kotlin基础学习-入门篇

Kotlin基础学习-第二篇

Kotlin进阶学习-第三篇

Kotlin进阶学习-第四篇

Kotlin进阶学习-第五篇

kotlin的历史

Kotlin由JetBrains公司开发设计,2011年公布第一版,2012年开源。

2016年发布1.0正式版,并且JetBrains在IDEA加入对Kotlin的支持,安卓自此又有新的选择。

2019年谷歌宣布Kotlin成为安卓第一开发语言,安卓程序员由javaKotlin已经迫在眉睫。

Kotlin的工作原理

语言分为解释型和编译型两种

语言类型

编译型

编译器直接将源代码一次性编译成二进制文件,计算机可直接执行,例如C,C++

优点:一次编译,即可运行,运行期不需要编译,运行效率高。

缺点:不同操作系统需要不同的机器码,且修改代码需要真个模块重新编译

解释型

程序运行时,解释器会将源码一行一行实时解析成二进制再执行。例如JS,Python

优点:平台兼容性好,安装对应的虚拟机即可运行。

缺点:运行时需要解释执行,效率较低。

Java的语言类型

java准确来说属于混合型语言,但更偏向于解释型。

编译java存在JITAOTJIT即时编译将可将热点代码直接编译成机器码,AOT预先编译可再安装时把代码编译成机器码

解释java运行时需编译成class文件,java虚拟机再解释执行.class

Kotlin的运行原理

java虚拟机只认class文件, 虚拟机不会关心classjava文件编译来的,还是其他文件编译来的。那此时我们创造一套自己的语法规则,再做一个对应的编译器,,则可让我们的语言跑在java虚拟机上。Kotlin则是此原理,运行前会先编译成class,再供java虚拟机运行。

创建Kotlin项目

打开android studio,在选择语言时,选择Kotlin

在包下创建kotlin文件

创建File命名为HelloWorld

敲入下面代码则可运行打印Hello World!

package com.hbsd.demo


fun main() {
    println("Hello World!")
}

运行结果如下:

下面进入语法学习

语法

变量

变量的声明

Kotlin使用var,val来声明变量,注意:Kotlin不再需要;来结尾

var 可变变量,对应java非final变量

var b = 1

val不可变变量,对应javafinal变量

val a = 1

两种变量并未声明类型,这是因为Kotlin存在类型推导机制,上述的a,b会默认为Int。假设想声明具体类型,则需下面的方式

var c: Int = 1

基本类型

Kotlin不再存在基本类型,将全部使用对象类型

Java基本类型 Kotlin对象类型 对象类型说明
int Int 整型
long Long 长整型
short Short 短整型
float Float 单精度浮点型
double Double 双精度浮点型
boolean Boolean 布尔型
char Char 字符型
byte Byte 字节型

var和val的本质区别

打开Kotlin对应的Java文件

再点击下方按钮

则可查看对应的Java文件

public final class HelloWorldKt {
    private static final int a = 1;
    private static int b = 2;
    private static int c = 10;
    
    ...
}

发现val a对应的为finalvar bvar c 对应的为非final

Kotlin此设计的原因则是防止非final的滥用,若一个变量永远不被修改则有必要给其加上final,使其他人看代码时更好理解。

后期我们写代码时则可先使用val,若真的需要修改再改为var

函数

函数的声明

无参无返回值

fun test() {
}

有参有返回值

参数的类型需要写在形参名后面中间使用:连接多个参数使用,分割",“返回值使用”:"拼接

fun add(a: Int, b: Int): Int {
    return a + b
}

声明技巧

当函数体只有一行代码时可直接使用下面方式声明方法

fun add (a: Int, b: Int): Int = a + b 

Kotlin存在类型推导,返回值类型也可省略

fun add (a: Int, b: Int) = a + b

函数的调用

fun main() {
    test()
    println(add(1, 2))
}

//运行结果
//test
//3

if语句

Kotlin中的选择控制有两种方式。ifwhen

if

Javaif区别不大,实现一个返回最大值的函数

fun max(a: Int, b: Int): Int {
    if (a > b) return a
    else return b
}

Kotlin的if可以包含返回值,if语句的最后一行会作为返回值返回

fun max(a: Int, b: Int): Int {
    return if (a > b) a else b
}

上述我们说过一行代码可省略返回值

fun max(a: Int, b: Int) = if (a > b) a else b

查看对应的Java文件,其上述实现都与下面代码等价

public static final int max(int a, int b) {
   return a > b ? a : b;
}

when

实现一个查询成绩的函数,用户传入名字,返回成绩级别

if实现

Kotlinif语句必须要有else,不然会报错

fun getScore(name: String) = if (name == "Tom") "不及格"
else if (name == "Jim") "及格"
else if (name == "Pony") "良好"
else if (name == "Tony") "优秀"
else "名字非法"

Kotlin==等价于Javaequals比较的时是对象里的内容, === 等价于Java==,比较的为对象的引用。

when实现

也必须实现else,否则报错

fun getScore(name: String) = when(name) {
    "Tom" -> "不及格"
    "Jim" -> "及格"
    "Pony" -> "良好"
    "Tony" -> "优秀"
    else -> "名字非法"
}

when支持参数检查

fun checkNumber(num: Number) {
    when (num) {
        is Int -> println("Int")
        is Double -> println("Double")
        else -> println("others")
    }
}

when可不传递形参

使用Boolean使when更加灵活

fun getScore(name: String) = when {
    name == "Tom" -> "不及格"
    name == "Jim" -> "及格"
    name == "Pony" -> "良好"
    name == "Tony" -> "优秀"
    else -> "名字非法"
}

-> 后不仅可以只执行一行代码,可以多行,看一个比较复杂的例子:

fun getScore(name: String) = when {
    //若name以Tom开头则命中此分支
    name.startsWith("Tom") -> {
        //处理
        println("你好,我是Tom开头的同学")
        "不及格"
    }
    name == "Jim" -> "及格"
    name == "Pony" -> "良好"
    name == "Tony" -> "优秀"
    else -> "名字非法"
}

循环语句

Kotlin有两种循环方式,whilefor-inwhilejava中的while没有区别,for-in是对Java for-each的加强,Kotlin舍弃了for-i的写法

while不再赘述,在学习for-in之前需要明确一个概念-区间

val range = 0..10 //区间代表[0,10]

for-in需借助区间来使用

fun main() {
    val range = 0..10
    for (i in range) { //也可直接for (i in 0..10)
        println(i)
    }
    //输出结果为 从0打印到10
}

0..10 代表双闭区间,如果想使用左闭右开呢,需要借助until关键字

fun main() {
    for (i in 0 until 10) {
        println(i)
    }
    //输出结果为 从0打印到9
}

上述实现是逐步进行相当于i++Kotlin也支持跳步

fun main() {
    for (i in  0 until 10 step 2) {
        println(i)
    }
    //输出结果为0,2,4,6,8
}

上述实现都是升序,Kotlin也可降序循环

fun main() {
    for (i in  10 downTo 1) {
        println(i)
    }
    //输出结果为10 - 1
}

for-in不仅可对区间进行遍历,还可对集合进行遍历,后续在集合处进行展示。

类和对象

类的创建和对象的初始化

在创建页面选择Class创建

创建Person类,并声明nameage,创建printInfo方法

class Person {
    var name = ""
    var age = 0
    fun printInfo() {
        println(name +"'s age is " + age)
    }
}

main方法中声明一个Person对象并调用printInfo方法

fun main() {
    val person = Person()
    person.name = "zjm"
    person.age = 20
    person.printInfo()
}
//结果如下zjm's age is 20

继承

声明Student类继承PersonKotlin中继承使用**:**,后接父类的构造,为什么需要构造后续讲解

class Student : Person(){ //此时Person报错
    var number = ""
    var grade = 0
    fun study() {
        println(name + "is studying")
    }
}

Person类当前不可继承,查看Person对应的java文件

public final class Person {
    ...
}

Person类为final不可被继承,因此需借助open关键字

只需在Person类前加上open

open class Person {
	...
}

此时Personjava文件变为

public class Person {
	...
}

此时Student将不再报错

构造

构造分为主构造和此构造

主构造

主构造直接写在类后面

修改Student

class Student(val number: String, val grade: Int) : Person(){
	...
}

在创建Student对象时,如下创建

val student = Student("1234", 90)

因之前Person还有nameage,下面修改Person类的主构造

open class Person(val name: String, val age: Int) {
    ...
}

此时Student报错,因为继承Person时,后边使用的是Person()无参构造,上面我们修改了Person的构造,则不存在无参构造了。

再修改Student

class Student(name: String,  age: Int, val number: String, val grade: Int) : Person(name, age){
   	...
}

此时不在报错,声明方式如下

val student = Student("zjm", 20, "1234", 90)

在构造时需要进行特殊处理怎么办,Kotlin提供了init结构体,主构造的逻辑可在init中处理

open class Person(val name: String, val age: Int) {
    init {
        println("name is" + name)
        println("age is" + age)
    }
}

上述修改都为主构造,那如果类想有多个构造怎么办,此时需借助次构造

次构造

此时实现Student的另外两个构造

三个参数的构造,nameagenumbergrade不传参默认为``0

无参构造,字符串默认为"",int默认为0

class Student(name: String, age){
    constructor(name: String, age: Int, number: String) : this(name, age, number, 0) {
        
    }
    constructor() : this("", 0, "", 0) {
        
    }
    ...
}

创建如下:

fun main() {
    val student1 = Student("zjm", "123", 90)
    val student2 = Student("zjm", "123")
    val student3 = Student()
}

无主构造

若类不使用主构造,则后续继承类也不需要使用构造即可去掉继承类的(),次构造可以调用父类构造super进行初始化,但是次构造的参数在其他地方无法引用

class Student : Person {
    constructor(name: String, number: String) : super(name, age) {

    }
	fun study() {
        //name,age可使用
        println(name + "is studying")
        //使用number则会报错,若number是主构造的参数则可引用
        //println(number) 报红
    }
}

接口

接口的定义

Java中的接口定义类似

interface Study {
    fun study()
    fun readBooks()
    fun doHomework()
}

接口的继承

继承接口只需在后用","拼接,需实现Study声明的全部函数

class Student(name: String, age), Study{
    
    ...

    override fun study() {
        TODO("Not yet implemented")
    }

    override fun readBooks() {
        TODO("Not yet implemented")
    }

    override fun doHomework() {
        TODO("Not yet implemented")
    }
}

Kotlin支持接口方法的默认实现,JDK1.8以后也支持此功能,方法有默认实现则继承类无需必须实现此方法

interface Study {
    fun study() {
        println("study")
    }
    fun readBooks()
    fun doHomework()
}

权限修饰符

JavaKotlin的不同如下表所示:

修饰符 Java Kotlin
public 所有类可见 所有类可见(默认)
private 当前类可见 当前类可见
protected 当前类,子类,同包下类可见 当前类,子类可见
default 同包下类可见(默认)
internal 同模块下的类可见

Kotlin引入internal,摒弃了default

使用:

类上

public open class Person(val name: String, val age: Int){...}

变量上

private val value = 1

方法上

private fun test() {
    
}

数据类和单例类

数据类

数据类则只处理数据相关,与Java Bean类似,通常需要实现其getsethashCodeequalstoString等方法

下面实现UserBean,包含idnamepwd属性

Java编写入如下:

public class UserBean {
    private String id;
    private String name;
    private String pwd;

    public UserBean() {

    }

    public UserBean(String id, String name, String pwd) {
        this.id = id;
        this.name = name;
        this.pwd = pwd;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        UserBean userBean = (UserBean) o;
        return Objects.equals(id, userBean.id) && Objects.equals(name, userBean.name) && Objects.equals(pwd, userBean.pwd);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, name, pwd);
    }

    @Override
    public String toString() {
        return "UserBean{" +
                "id='" + id + '\'' +
                ",name='" + name + '\'' +
                ",pwd='" + pwd + '\'' +
                '}';
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPwd() {
        return pwd;
    }

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }
}

Kotlin编写此类将变得非常简单,新建一个kt文件,选择如下:

一行代码即可搞定,Kotlin会自动实现上述方法。

data class UserBean(val id: String, val name: String, val pwd: String)

若无data关键字,上述方法(hashCodeequalstoString)无法正常运行,去掉data查看Kotlin对应的java文件:

public final class UserBean {
   @NotNull
   private final String id;
   @NotNull
   private final String name;
   @NotNull
   private final String pwd;

   @NotNull
   public final String getId() {
      return this.id;
   }

   @NotNull
   public final String getName() {
      return this.name;
   }

   @NotNull
   public final String getPwd() {
      return this.pwd;
   }

   public UserBean(@NotNull String id, @NotNull String name, @NotNull String pwd) {
      Intrinsics.checkNotNullParameter(id, "id");
      Intrinsics.checkNotNullParameter(name, "name");
      Intrinsics.checkNotNullParameter(pwd, "pwd");
      super();
      this.id = id;
      this.name = name;
      this.pwd = pwd;
   }
}

发现上面代码既无hashCodeequalstoString也无set

加上data且把变量改为var,对应的java文件如下:

public final class UserBean {
   @NotNull
   private String id;
   @NotNull
   private String name;
   @NotNull
   private String pwd;

   @NotNull
   public final String getId() {
      return this.id;
   }

   public final void setId(@NotNull String var1) {
      Intrinsics.checkNotNullParameter(var1, "<set-?>");
      this.id = var1;
   }

   @NotNull
   public final String getName() {
      return this.name;
   }

   public final void setName(@NotNull String var1) {
      Intrinsics.checkNotNullParameter(var1, "<set-?>");
      this.name = var1;
   }

   @NotNull
   public final String getPwd() {
      return this.pwd;
   }

   public final void setPwd(@NotNull String var1) {
      Intrinsics.checkNotNullParameter(var1, "<set-?>");
      this.pwd = var1;
   }

   public UserBean(@NotNull String id, "pwd");
      super();
      this.id = id;
      this.name = name;
      this.pwd = pwd;
   }

   @NotNull
   public final String component1() {
      return this.id;
   }

   @NotNull
   public final String component2() {
      return this.name;
   }

   @NotNull
   public final String component3() {
      return this.pwd;
   }

   @NotNull
   public final UserBean copy(@NotNull String id, "pwd");
      return new UserBean(id, pwd);
   }

   // $FF: synthetic method
   public static UserBean copy$default(UserBean var0, String var1, String var2, String var3, int var4, Object var5) {
      if ((var4 & 1) != 0) {
         var1 = var0.id;
      }

      if ((var4 & 2) != 0) {
         var2 = var0.name;
      }

      if ((var4 & 4) != 0) {
         var3 = var0.pwd;
      }

      return var0.copy(var1, var2, var3);
   }

   @NotNull
   public String toString() {
      return "UserBean(id=" + this.id + ",name=" + this.name + ",pwd=" + this.pwd + ")";
   }

   public int hashCode() {
      String var10000 = this.id;
      int var1 = (var10000 != null ? var10000.hashCode() : 0) * 31;
      String var10001 = this.name;
      var1 = (var1 + (var10001 != null ? var10001.hashCode() : 0)) * 31;
      var10001 = this.pwd;
      return var1 + (var10001 != null ? var10001.hashCode() : 0);
   }

   public boolean equals(@Nullable Object var1) {
      if (this != var1) {
         if (var1 instanceof UserBean) {
            UserBean var2 = (UserBean)var1;
            if (Intrinsics.areEqual(this.id, var2.id) && Intrinsics.areEqual(this.name, var2.name) && Intrinsics.areEqual(this.pwd, var2.pwd)) {
               return true;
            }
         }

         return false;
      } else {
         return true;
      }
   }
}

此时则和手动编写的java bean功能一样了,所有方法都可正常运行

单例类

目前Java使用最广的单例模式的实现如下:

public class Singleton {
    private Singleton() {
    }
    
    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }
    
    public static Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
    public void test() {
        ...
    }
}

Kotlin中创建单例类需选择Object

生成代码如下:

object Singleton {
    fun test() {
        ...
    }
}

其对应的java文件如下,和上述使用最多的java单例实现类似

public final class Singleton {
   @NotNull
   public static final Singleton INSTANCE;

   public final void test() {
   }

   private Singleton() {
   }

   static {
      Singleton var0 = new Singleton();
      INSTANCE = var0;
   }
}

使用如下:

fun main() {
    Singleton.test() //对应的java代码为Singleton.INSTANCE.test();
}

Lambda

许多高级语言都支持Lambdajavajdk1.8以后才支持Lamda语法,LamdaKotlin的灵魂所在,此小节对Lambda的基础进行学习,并借助集合练习。

集合的创建和遍历

List

fun main() {
    //常规创建
    val list = ArrayList<Int>()
    list.add(1)
    list.add(2)
    list.add(3)
    
    //listOf不可变,后续不可添加删除,只能查
    val list1 = listOf<Int>(1, 2, 3 ,4 ,5)
    list1.add(6)//报错
    
    //mutableListOf,后续可添加删除
    val list2 = mutableListOf<Int>(1,5)
    list2.add(6)
    
    //循环
    for (value in list2) {
        println(value)
    }
}

Set

set用法与List类似,只是把listOf替换为mapOf

Map

fun main() {
    val map = HashMap<String, String>()
    map.put("1", "zjm")
    map.put("2", "ljn")
    //Kotlin中map支持类似下标的赋值和访问
    map["3"] = "lsb"
    map["4"] = "lyx"
    println(map["2"])
    println(map.get("1"))

    //不可变
    val map1 = mapOf<String, String>("1" to "zjm", "2" to "ljn")
    map1["3"] = "lsb" //报错
    
    //可变
    val map2 = mutableMapOf<String, "2" to "ljn")
    map2["3"] = "lsb"
    
    for ((key, value) in map) {
        println(key + "   " + value)
    }
    
}

Lambda的使用

方法在传递参数时都是普通变量,而Lambda可以传递一段代码

Lambda表达式的语法结构

{参数名1: 参数类型, 参数名2:参数类型 -> 函数体}

Kotlinlist提供了maxByOrNull函数,返回当前list中xx最大的元素,XX是我们定义的条件,可能为长度,可能是别的,我们拿长度举例。

若不使用maxBy,实现如下

fun main() {
    val list = listOf<String>("a", "aba", "aabb", "a")
    var maxStr = ""
    for (str in list) {
        if (str.length > maxStr.length) {
            maxStr = str;
        }
    }
    println(maxStr)
}

maxByOrNull是一个普通方法,需要一个Lambda参数,下面结合Lambda使用maxByOrNull

fun main() {
    val list = listOf<String>("a", "a")
    var lambda = {str: String -> str.length}
    var maxStr = list.maxByOrNull(lambda)
    println(maxStr)
}

直接当成参数也可传递

var maxStr = list.maxByOrNull({str: String -> str.length})

Lambda为方法的最后一个参数,则可将{}提到外面

var maxStr = list.maxByOrNull() {str: String -> str.length}

若有且仅有一个参数且是Lambda,则可去掉()

var maxStr = list.maxByOrNull {str: String -> str.length}

Kotlin拥有出色的类型推导机制,Lambda参数过多时可省略参数类型

var maxStr = list.maxByOrNull {str -> str.length}

Lambda只有一个参数,则可用it替代参数名

var maxStr = list.maxByOrNull {it.length}

集合还有许多此类函数

创建list,后续操作都由此list转换

val list = listOf<String>("a", "a")

map 映射,返回新集合,将集合中的元素映射成另一个值

val newList = list.map { it.toUpperCase() }//将集合中的元素都准换成大写

filter过滤,返回新集合,将集合中的元素进行筛选

val newList = list.filter { it.length > 3 }//筛选出长度大于3的元素

any返回Boolean,集合中是否存在元素满足Lambda的条件,有则返回true,无则false

val isAny = list.any {it.length > 10} //返回false

all返回Boolean,集合中元素是否全部满足满足Lambda的条件,有则返回true,无则false

val isAll = list.all {it.length > 0} //返回true

Lambda的简单使用到这就结束了

Java函数式API的使用

Kotlin调用Java方法,若该方法接收一个Java单抽象方法接口参数,则可使用函数式APIJava单抽象方法接口指的是接口只声明一个方法,若有多个方法则无法使用函数式API

Java单抽象方法接口例如Runnable

public interface Runnable {
    void run();
}

Java中启动一个线程如下:

new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("test");
    }
}).start();

Kotlin启动线程如下:

Kotlin摒弃了new,若想声明匿名内部类必须使用object

Thread(object : Runnable {
    override fun run() {
        println("test")
    }
}).start()

RunnableJava单抽象方法接口,可对代码进行简化

Thread(Runnable {
        println("test")
    }).start()

Runnable接口只用一个方法,使用Lambda也不会有歧义,Kotlin知道此Lambda一定实现的为run函数,借用Lambda进一步简化:

Thread({
    println("test")
}).start()

又因Thread只需一个参数Runnable参数,则可省略()

Thread {
    println("test")
}.start()

与上类似的,click也使用上述方法

button.setOnClickListener { println("test") }

这种方式可极大缩减代码量

空指针检查机制

国外统计程序出现最多的异常为空指针异常,Kotlin存在编译时检查系统帮助我们发现空指针异常。

查看下面Java代码

public void doStudy(Study study) {
    study.doHomework();
    study.readBooks();
}

上述代码时存在空指针风险的,传入null,则程序崩溃,对其进行改进

public void doStudy(Study study) {
    if (study != null) {
        study.doHomework();
        study.readBooks();
    }
}

对于Kotlin来讲任何参数和变量不能为空

fun study(study: Study) {
    study.doHomework()
    study.readBooks()
}

fun main() {
    study(null) //报错
    study(Student()) //正确
}

Kotlin把空指针异常的检查提前到了编译期,若空指针则编译期就会崩溃,避免在运行期出现问题

若我们有特殊的需求可能需要传递null参数,参数则按照下面声明

fun study(study: Study?) {
    study.doHomework() //报错
    study.readBooks()	//报错
}

?的意思则是当前参数可为空,如果可为空的话,则此对象调用的方法必须要保证对象不为空,上面代码没有保证,则报错,修改如下

fun study(study: Study?) {
    if (study != null) {
        study.doHomework()
        study.readBooks()
    }
}

也可借助判空辅助工具

判空辅助工具

?.

其含义是前面对象不为空才执行.后面的方法

fun study(study: Study?) {
    study?.doHomework()
    study?.readBooks()
}

?:

其含义是前不为空则返回问号前的值,为空则返回后的值

比如

val c = if (a !=null ) {
    a
} else {
    b
}

借助?:则可简化为

val c = a ?: b

再比如

fun getTextLength(text: String?): Int {
    if (text != null) {
        return text.length
    }
    return 0
}

借助?: 则可简化为

fun getTextLength(text: String?) = text?.length ?: 0

!!

有些时候我们想要强行通过编译,就需要依靠!!,这时就是程序员来保证安全

fun study(study: Study?) {
    //假设此时为空抛出异常,则和java一样
    study!!.doHomework()
    study!!.readBooks()
}

let函数

let不是关键字,而是一个函数,提供了函数式API的编程接口,会将调用者作为参数传递到Lambda表达式,调用之后会立马执行Lambda表达式的逻辑

obj.let { it -> //it就是obj
    //编写操作
}

比如上面函数

fun study(study: Study?) {
    study.doHomework()  //报错
    study.readBooks()	//报错
}

借助let则可改为

fun study(study: Study?) {
    //此时靠?.则保证了study肯定不为空,才会执行let函数
    study?.let {
        //it为study
        it.doHomework()
        it.readBooks()
    }
}

全局判空注意事项

//全局变量
var study: Study? = null
fun study() {
    //报错
    if (study != null) {
        study.readBooks()
        study.doHomework()
    }
}

因全局变量随时有可能被其他线程修改,即使判空处理也不能保证其没有空指针风险,而let则可规避上述问题

var study: Study? = null
fun study() {
    study?.let {
        it.doHomework()
        it.readBooks()
    }
}

内嵌表达式

之前我们拼接字符串都是下面这样

var name = "zjm"
var age = 20
println("My name is " + name + ". I am " + age + ".")
//打印结果
//My name is zjm. I am 20.

现在靠着Kotlin提供的内嵌表达式则不需要拼接,只需要下面这样则可实现

var name = "zjm"
var age = 20
println("My name is $name. I am $age." )
//打印结果
//My name is zjm. I am 20.

内嵌表达式还支持复杂的操作

${程序员想要的操作}

var name = "zjm"
var age = 20
println("My name is ${if (1 < 2) "zjm" else "ljn"}. I am $age." )
//打印结果
//My name is zjm. I am 20.

函数的参数默认值

Kotlin支持函数存在默认值,使用如下

fun main() {
    myPrint(1)
    myPrint(1, "lalala")
}

fun myPrint(value: Int, str: String = "hello") {
    println("num is $value,str is $str")
}

//结果如下
//num is 1,str is hello
//num is 1,str is lalala

value想为默认值,则会报错,因为在使用时传入的第一个参数他认为是int的,传入字符串会类型不匹配

fun main() {
    myPrint("zjm")//报错
}

fun myPrint(value: Int = 100, str: String) {
    println("num is $value,str is $str")
}

Kotlin提供了一种键值对传参来解决上述问题

fun main() {
    myPrint(str = "zjm") //正确调用
}

fun myPrint(value: Int = 100,str is $str")
}

回顾之前的主次构造,Student如下

class Student(name: String, 0) {

    }
    ...
}

上述的此构造借助参数默认值技巧是可以不写的,将第四个参数默认值为0 即可

class Student(name: String, val grade: Int = 0) : Person(name, age){
	...
}

上述关于Kotlin的使用,已经够日常开发需要,后续笔者会更新一些进阶使用

原 创 不 易 , 还 希 望 各 位 大 佬 支 持 一 下 \textcolor{blue}{原创不易,还希望各位大佬支持一下}

原文地址:https://blog.csdn.net/zjm807778317

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


更新Android SDK到3.0版本时,遇到Failed to rename directory E:\android\tools to E:\android\temp\ToolPackage.old01问题,导致无法更新,出现该问题的原因是由于3.0版本与较早的sdk版本之间文件结构有冲突,解决
Android 如何解决dialog弹出时无法捕捉Activity的back事件 在一些情况下,我们需要捕捉back键事件,然后在捕捉到的事件里写入我们需要进行的处理,通常可以采用下面三种办法捕捉到back事件: 1)重写onKeyDown或者onKeyUp方法 2)重写onBackPressed方
Android实现自定义带文字和图片的Button 在Android开发中经常会需要用到带文字和图片的button,下面来讲解一下常用的实现办法。一.用系统自带的Button实现 最简单的一种办法就是利用系统自带的Button来实现,这种方式代码量最小。在Button的属性中有一个是drawable
Android中的&quot;Unable to start activity ComponentInfo&quot;的错误 最近在做一款音乐播放器的时候,然后在调试的过程中发现一直报这个错误&quot;Unable to start activity ComponentInfo&quot;,从字面
Android 关于长按back键退出应用程序的实现最近在做一个Android上的应用,碰到一个问题就是如何实现长按back键退出应用程序。在网上查找了很多资料,发现几乎没有这样的实现,大部分在处理时是双击back键来退出应用程序。参考了一下双击back键退出应用程序的代码,网上主流的一种方法是下面
android自带的时间选择器只能精确到分,但是对于某些应用要求选择的时间精确到秒级,此时只有自定义去实现这样的时间选择器了。下面介绍一个可以精确到秒级的时间选择器。 先上效果图: 下面是工程目录: 这个控件我也是用的别人的,好像是一个老外写的,com.wheel中的WheelView是滑动控件的主
Android平台下利用zxing实现二维码开发 现在走在大街小巷都能看到二维码,而且最近由于项目需要,所以研究了下二维码开发的东西,开源的二维码扫描库主要有zxing和zbar,zbar在iPos平台上应用比较成熟,而在Android平台上主流还是用zxing库,因此这里主要讲述如何利用zxing
Android ListView的item背景色设置以及item点击无响应等相关问题 在Android开发中,listview控件是非常常用的控件,在大多数情况下,大家都会改掉listview的item默认的外观,下面讲解以下在使用listview时最常见的几个问题。1.如何改变item的背景色和按
如何向Android模拟器中导入含有中文名称的文件在进行Android开发的时候,如果需要向Android模拟器中导入文件进行测试,通过DDMS下手动导入或者在命令行下通过adb push命令是无法导入含有中文文件名的文件的。后来发现借用其他工具可以向模拟器中导入中文名称的文件,这个工具就是Ultr
Windows 下搭建Android开发环境一.下载并安装JDK版本要求JDK1.6+,下载JDK成功后进行安装,安装好后进行环境变量的配置【我的电脑】-——&gt;【属性】——&gt;【高级】 ——&gt;【环境变量】——&gt;【系统变量】中点击【新建】:变量名:CLASSPATH变量值:……
如何利用PopupWindow实现弹出菜单并解决焦点获取以及与软键盘冲突问题 在android中有时候可能要实现一个底部弹出菜单,此时可以考虑用PopupWindow来实现。下面就来介绍一下如何使用PopupWindow实现一个弹出窗。 主Activity代码:public void onCreat
解决Android中的ERROR: the user data image is used by another emulator. aborting的方法 今天调试代码的时候,突然出现这个错误,折腾了很久没有解决。最后在google上找到了大家给出的两种解决方案,下面给出这两种方法的链接博客:ht
AdvserView.java package com.earen.viewflipper; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory;
ImageView的scaleType的属性有好几种,分别是matrix(默认)、center、centerCrop、centerInside、fitCenter、fitEnd、fitStart、fitXY。 |值|说明| |:--:|:--| |center|保持原图的大小,显示在ImageVie
文章浏览阅读8.8k次,点赞9次,收藏20次。本文操作环境:win10/Android studio 3.21.环境配置 在SDK Tools里选择 CMAKE/LLDB/NDK点击OK 安装这些插件. 2.创建CMakeLists.txt文件 在Project 目录下,右键app,点击新建File文件,命名为CMakeLists.txt点击OK,创建完毕! 3.配置文件 在CMa..._link c++ project with gradle
文章浏览阅读1.2w次,点赞15次,收藏69次。实现目的:由mainActivity界面跳转到otherActivity界面1.写好两个layout文件,activity_main.xml和otherxml.xmlactivity_main.xml&lt;?xml version="1.0" encoding="utf-8"?&gt;&lt;RelativeLayout ="http://schemas..._android studio 界面跳转
文章浏览阅读3.8w次。前言:最近在找Android上的全局代理软件来用,然后发现了这两款神作,都是外国的软件,而且都是开源的软件,因此把源码下载了下来,给有需要研究代理这方面的童鞋看看。不得不说,国外的开源精神十分浓,大家相互使用当前基础的开源软件,然后组合成一个更大更强的大开源软件。好吧,废话不多说,下面简单介绍一下这两款开源项目。一、ProxyDroid:ProxyDroid功能比较强大,用到的技术也比较多,源码也_proxydroid
文章浏览阅读2.5w次,点赞17次,收藏6次。创建项目后,运行项目时Gradle Build 窗口却显示错误:程序包R不存在通常情况下是不会出现这个错误的。我是怎么遇到这个错误的呢?第一次创建项目,company Domain我使用的是:aven.com,但是创建过程在卡在了Building 'Calculator' Gradle Project info这个过程中,于是我选择了“Cancel”第二次创建项目,我还是使用相同的项目名称和项目路_r不存在
文章浏览阅读8.9w次,点赞4次,收藏43次。前言:在Android上使用系统自带的代理,限制灰常大,仅支持系统自带的浏览器。这样像QQ、飞信、微博等这些单独的App都不能使用系统的代理。如何让所有软件都能正常代理呢?ProxyDroid这个软件能帮你解决!使用方法及步骤如下:一、推荐从Google Play下载ProxyDroid,目前最新版本是v2.6.6。二、对ProxyDroid进行配置(基本配置:) (1) Auto S_proxydroid使用教程
文章浏览阅读1.1w次,点赞4次,收藏17次。Android Studio提供了一个很实用的工具Android设备监视器(Android device monitor),该监视器中最常用的一个工具就是DDMS(Dalvik Debug Monitor Service),是 Android 开发环境中的Dalvik虚拟机调试监控服务。可以进行的操作有:为测试设备截屏,查看特定进程中正在运行的线程以及堆栈信息、Logcat、广播状态信息、模拟电话_安卓摄像头调试工具