当前位置: 首页 > ops >正文

Kotlin入门学习(非常详细),从零基础入门到精通,看完这一篇就够了

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!


`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`有两种循环方式,**while**和**for-in**,`while`与`java`中的`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`创建![](https://img-blog.csdnimg.cn/2876e7b093ac428487856be9e2806e81.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6LCB6LCB6LCB5Yqo5LqG5oiR,size_18,color_FFFFFF,t_70,g_se,x_16)创建`Person`类,并声明`name`,`age`,创建`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`类继承`Person`,`Kotlin`中继承使用\*\*:\*\*,后接父类的构造,为什么需要构造后续讲解

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 {

}


此时`Person`的`java`文件变为

public class Person {

}


此时`Student`将不再报错#### 构造**构造分为主构造和此构造**##### 主构造主构造直接写在**类后面**修改`Student`类

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

}


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

val student = Student(“1234”, 90)


因之前`Person`还有`name`和`age`,下面修改`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`的另外两个构造三个参数的构造,`name`,`age`,`number`,`grade`不传参默认为``0无参构造,字符串默认为"",int默认为`0`

class Student(name: String, age: Int, val number: String, val grade: Int) : Person(name, age){
constructor(name: String, age: Int, number: String) : this(name, age, number, 0) {

}
constructor() : this("", 0, "", 0) {}
...

}


创建如下:

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


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

class Student : Person {
constructor(name: String, age: Int, 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: Int, val number: String, val grade: Int) : Person(name, 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()
}


### 权限修饰符`Java`和`Kotlin`的不同如下表所示:| 修饰符 | 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`类似,通常需要实现其`get`,`set`,`hashCode`,`equals`,`toString`等方法下面实现`UserBean`,包含`id`,`name`,`pwd`属性`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`文件,选择如下:![](https://img-blog.csdnimg.cn/424ea881e4ae4d879031bc73b01c6a02.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6LCB6LCB6LCB5Yqo5LqG5oiR,size_18,color_FFFFFF,t_70,g_se,x_16)一行代码即可搞定,Kotlin会自动实现上述方法。

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


若无`data`关键字,上述方法(`hashCode`,`equals`,`toString`)无法正常运行,去掉`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;
}
}


发现上面代码既无`hashCode`,`equals`,`toString`也无`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, @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;
}

@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, @NotNull String name, @NotNull String pwd) {
Intrinsics.checkNotNullParameter(id, “id”);
Intrinsics.checkNotNullParameter(name, “name”);
Intrinsics.checkNotNullParameter(pwd, “pwd”);
return new UserBean(id, name, pwd);
}

// F F : s y n t h e t i c m e t h o d p u b l i c s t a t i c U s e r B e a n c o p y FF: synthetic method public static UserBean copy FF:syntheticmethodpublicstaticUserBeancopydefault(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`![](https://img-blog.csdnimg.cn/dc68fe23ea7748bc87071a79b5c5f804.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6LCB6LCB6LCB5Yqo5LqG5oiR,size_18,color_FFFFFF,t_70,g_se,x_16)生成代码如下:

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许多高级语言都支持`Lambda`,`java`在`jdk1.8`以后才支持`Lamda`语法,`Lamda`是`Kotlin`的灵魂所在,此小节对`Lambda`的基础进行学习,并借助集合练习。#### 集合的创建和遍历##### List

fun main() {
//常规创建
val list = ArrayList()
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, 2, 3 ,4 ,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, String>("1" to "zjm", "2" to "ljn")
map2["3"] = "lsb"for ((key, value) in map) {println(key + "   " + value)
}

}


#### Lambda的使用方法在传递参数时都是普通变量,而`Lambda`可以传递一段代码`Lambda`表达式的语法结构**{参数名1: 参数类型, 参数名2:参数类型 -> 函数体}**`Kotlin`的`list`提供了`maxByOrNull`函数,返回当前`list`中xx最大的元素,XX是我们定义的条件,可能为长度,可能是别的,我们拿长度举例。若不使用`maxBy`,实现如下

fun main() {
val list = listOf(“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(“a”, “aba”, “aabb”, “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(“a”, “aba”, “aabb”, “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`单抽象方法接口参数,则可使用函数式`API`。`Java`单抽象方法接口指的是接口只声明一个方法,若有多个方法则无法使用函数式`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()


因`Runnable`是`Java`单抽象方法接口,可对代码进行简化

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()
}
}


也可借助**判空辅助工具**#### 判空辅助工具##### ?.![img](https://img-blog.csdnimg.cn/img_convert/adfa79b4b0de092b68cd82c87ab9bfce.png)
![img](https://img-blog.csdnimg.cn/img_convert/9ff7b0ed45b65b630e482d6241b08c02.png)**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。****[需要这份系统化的资料的朋友,可以添加戳这里获取](https://bbs.csdn.net/topics/618658159)****一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**。查看下面`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()
}
}


也可借助**判空辅助工具**#### 判空辅助工具##### ?.[外链图片转存中...(img-JU3su4pg-1715904762084)]
[外链图片转存中...(img-iZqH6eln-1715904762084)]**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。****[需要这份系统化的资料的朋友,可以添加戳这里获取](https://bbs.csdn.net/topics/618658159)****一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**
http://www.xdnf.cn/news/11414.html

相关文章:

  • jmeter之jtl文件解析(生成测试报告)
  • C语言程序设计(初识C语言后部分)
  • Java中常用术语简称
  • 小米10Pro手机双击android,小米10pro上手感受
  • Data Matrix码
  • DLX算法
  • 操作系统sp1、sp2、sp3是什么意思
  • SQL的索引详细介绍
  • 什么是脚本,脚本语言?
  • biji
  • BitBlt函数用法
  • ByConity 替换 ClickHouse 构建 OLAP 数据平台,资源成本大幅降低
  • EDK2之debug
  • 专业之选,Duplicate Cleaner Pro,高效清理重复文件,代码与硬盘双清爽!
  • 一句话明白:什么是统计?什么是概率?
  • 华为交换机基本命令
  • iTunes Connect 基本使用说明
  • dfsdf
  • JPA使用指南 javax.persistence的注解配置
  • Young For You - 歌词
  • Android TV开发之VerticalGridView
  • DataBus(数据同步组件)
  • mysql中使用逻辑判断,20.5-20.9 shel:l脚本中的逻辑判断,文件目录属性判断,if特殊用法 ,case判断...
  • centos 下安装ati显卡驱动方法
  • Java开源工具库使用之性能测试JMH
  • windows 2000 系统安装和配置
  • 【SQL注入】(1)原理,框架
  • elk logstash 详解
  • 网站建设经验分享:如何进行网站内容更新与维护?
  • 缓冲区(buffer)与缓存(cache)