Kotlin基础——基础内容

文章目录

  • 1 函数和变量
    • 1.1 基本程序
    • 1.2 函数
    • 1.3 变量
      • 1.3.1 变量的类型推导
      • 1.3.2 可变变量和不可变量
      • 1.3.3 变量使用规则
    • 1.4 字符串模板
  • 2 类和属性
    • 2.1 属性
    • 2.2 自定义访问器
    • 2.3 目录和包
      • 2.3.1 同包访问
      • 2.3.2 不同包导入
      • 2.3.3 包名类名定义规则
  • 3 枚举和“when”
    • 3.1 声明枚举类
    • 3.2 when结构使用
    • 3.3 when结构包含对象
    • 3.4 使用不带参数的“when”
    • 3.5 合并类型检查和转换
    • 3.6 用“when”代替“if”
    • 3.7 代码块作为“when”的分支
  • 4 循环语句
    • 4.1 while循环
    • 4.2 for循环
    • 4.3 迭代map
    • 4.4 使用“in”检查集合和区间成员
  • 5 异常
    • 5.1 抛异常和捕获异常
    • try作为表达式

1 函数和变量

1.1 基本程序

fun main(args: Array<String>) {println("Hello World!")
}

程序从“Hello World”打印开始,从这个简单的程序中,包含Kotlin语言的以下特性:

  • 函数使用关键字fun声明
  • 主函数依然为main函数
  • Kotlin中没有Java中数组类型,数组就是Array类
  • 函数可以定义在文件的最外层,可以不用放到类中
  • 参数类型在参数的后面
  • Java中的很多语句Kotlin做了更简易的封装,比如println
  • 语句结尾不需要分号

1.2 函数

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

函数仍然由函数名,参数列表和返回值类型组成。不同的是函数使用fun定义,参数类型和返回值类型在后面

  • Kotlin不支持三元运算符(?😃
  • Kotlin中很多逻辑运算是表达式,可以直接返回值

上面的可以简化为:

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

这样的函数拥有表达式体,上面有大括号的函数拥有代码块体。
还可以进一步简化为:

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

对于拥有表达式体的函数,可以省略其返回值类型,因为Kotlin具有类型推导能力。

1.3 变量

Java中声明变量从类型开始,而Kotlin中很多时候不需要声明变量的类型,因为Kotlin有强大的类型推导功能,能够根据上下文推导出具体的类型。

1.3.1 变量的类型推导

val a = 10
val b = 12.3
val c = "test"

a被推导为Int类型
b被推导为Double类型
c被推导为String类型
Kotlin中没有Java中的基本数据类型,所有类型都是类对象
如果要显示指定数据的类型,可以在变量后面加变量的类型

val d: Byte = 10

1.3.2 可变变量和不可变量

Kotlin中通常有两个变量修饰符

  • val(value):不能在初始化后再次赋值,对应于Java中使用final修饰的变量
  • var(variable):可变变量,对应于Java中的非final修饰符

默认情况下,应该首先使用val修饰符,当变量确实需要改变时,才替换成var修饰符

1.3.3 变量使用规则

在这里插入图片描述
val类型赋值之后不可改变,否则编译不过
在这里插入图片描述
如果变量不在定义的时候初始化,则需要确定其类型,因为Kotlin虽然可以类型推导,但还是静态类型的语言,每个变量都有确定的类型。不在定义的时候确定其类型,编译器无法推导,无法编译通过

val b: Int
if (a > 5) {b = 1
} else {b = 0
}

val变量只能赋值一次,如果编译器能够保证只执行一条初始化语句,则可以编译通过

val list = listOf(1, 3, 4)
list.addLast(5)

val变量定义的引用不可变,但是其引用对象的内容可变。list指向一个List对象,不能改变其引用直系指向,但是该List对象可以改变其中存储的元素
在这里插入图片描述
对于var可变类型变量,不能改变其数据类型,当a定义的时候,类型推导为Int类型,此时该变量的类型就已经被确定,不能改变其类型,否则编译失败

1.4 字符串模板

开发中很多时候涉及到字符串拼接,Java中拼接如下

"Hello, " + name + "!"

在Kotlin中可以使用更简便的写法,就是字符串模板

"Hello, $name!"

字符串模板不止可以引用简单变量,还可以引用复杂的变量

val names = listOf("World", "Kotlin")
println("Hello, ${names[0]}!")

这里可以使用大括号引用字符串数组的第一个元素

println("Hello, ${if (args.size > 0) args[0] else "World"}!")

大括号中还可以嵌套表达式

2 类和属性

Kotlin也是面向对象的语言,是JVM语言,在Java虚拟机上运行,所以也是有类和属性一说
Java中有一个JavaBean的概念,表达的是一种Java中规范类的写法

public class Person {private final String name;public Person(String name) {this.name = name;}public String getName() {return name;}
}

通常这些构造函数和get方法都是比较重复的代码,与具体的业务逻辑无关
可以将上面的代码拷贝到kotlin文件中,能够自动将Java代码转换成kotlin代码

class Person(val name: String)

Kotlin中只需要一行代码就能够表示上面的一段Java代码
public类修饰符消失了,因为在Kotlin中public是默认的可见性

2.1 属性

类的概念是把数据和处理数据的代码封装成一个单一的实体
类包含属性和行为,在Java中字段和访问器(settergetter)的组合常常被叫做属性
Kotlin中,属性是头等的语言特性,完全替代了字段和访问器方法
在类中声明一个属性和声明一个变量一样:使用val和var关键字,当声明属性的时候,就默认声明了对应的访问器。声明成val的属性是只读的,默认会提供对应的get方法,而声明成var的属性是可变的,默认会提供getset方法

class Person(val name: String, var isMarried: Boolean)

这里声明了两个属性,一个是只读属性,只提供getter方法,另一个是可变属性,提供gettersetter方法,使用Java访问Kotlin声明的类

public class Test {public static void main(String[] args) {Person person = new Person("zhangsan", false);person.setMarried(true);System.out.println(person.getName());System.out.println(person.isMarried());}
}

输出

zhangsan
true

Kotlin声明的属性,是一个类的字段都是私有的类,在Java代码中可以访问Kotlin声明的类,可以看到,声明为val的属性,只有getter方法,声明为var的属性,有gettersetter方法。
如果属性声明为XXX,默认提供的是setXXXgetXXX方法,其中有一个例外是isXXX开头的属性,这种属性,默认提供的是setXXXisXXX方法,需要注意。
上面是Java中访问Kotlin中声明的类,下面代码为Kotlin中访问

fun main(args: Array<String>) {val person = Person("zhangsan", false)person.isMarried = true //1println(person.name) //2println(person.isMarried)
}

上面的Kotlin代码中,看起来像是直接访问的定义的属性。但是上面说过,Kotlin中声明的属性变量,默认是private的,Kotlin中也没有改变类中private变量无法从类外访问的特性。Kotlin中,不需要显示调用gettersetter方法,而是像访问public属性一样调用访问器。注释1处默认调用的是person对象的isMarried类变量的setter方法,而注释2处则是调用的getter方法。

2.2 自定义访问器

上面属性默认的访问器都是编译器生成的,而如果要实现自己的逻辑,就需要自己自定义访问器

class Rectangle(val height: Int, val width: Int) {val isSquare: Booleanget() {return height == width}
}

Rectangle类定义了一个属性isSquare,该属性用val修饰,只提供getter方法,而这个getter方法没有使用默认的getter,而是使用自定义的getter方法。自定义访问器就是对属性创建一个get函数或者set函数来自定义getter方法和setter方法。

2.3 目录和包

kotlin文件中以package语句开头,文件中定义的所有声明(类、函数、属性)都在该包中,如果其他文件中定义了相同的包,则他们属于同一包中,可以直接使用,如果包不同,则需要导入,导入使用import关键字。

2.3.1 同包访问

TestOne

package com.testclass TestOne(val num: Number)fun TestOnePrint() {println("TestOnePrint")
}

TestTwo

package com.testclass TestTwo(){
}fun main() {val testOne = TestOne(3)TestOnePrint()
}

TestTwo文件中的main函数可以直接访问TestOne文件中。
与Java不同的是Java中包路径与项目的实际路径对应,一个点是一个文件夹,而在Kotlin中,包名可以不与文件路径相对应,可以将该文件放到项目中的任意位置,但是他们仍处于相同的包下,且不会导致编译错误。

2.3.2 不同包导入

Kotlin中import可以导入任何声明
导入顶层函数

import com.test.TestOnePrint

导入类

import com.test.TestOne

导入包中所有元素

import com.test.*

2.3.3 包名类名定义规则

类名:
首先来看Java,Java中一个类文件可以包含多个类定义,但是只能有一个public定义的,且必须和类文件相同。
而对于Kotlin来说,则没有这么严格的显示,同样的,一个文件中可以定义多个类,类文件文件名可以任意选择。
包名:
对于包名来说,虽然Kotlin没有限制,但是建议参考Java中的实现方式,能够使代码结构更加清晰

3 枚举和“when”

3.1 声明枚举类

enum class Color {RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET
}

kotlin中创建枚举类比Java多一个关键字,需要enum class一起使用,enum是一个软关键字,只有放在class前面才有意义。

3.2 when结构使用

fun printColor(color: Color) {when (color) {Color.RED -> println("red")Color.BLUE -> println("blue")Color.VIOLET -> println("violet")else -> println("no such color")}
}

kotlin中没有switch...case,kotlin中多重判断使用when结构。

fun getWarmth(color: Color) = when (color) {Color.RED, Color.ORANGE, Color.YELLOW -> "warm"Color.GREEN -> "neutral"Color.BLUE, Color.INDIGO, Color.VIOLET -> "cold"
}

when结构也可以合并处理
需要注意的是when结构使用枚举类的时候,需要对所有变量进行定义,或者定义else,否则无法编译通过

3.3 when结构包含对象

when结构比switch更加强大,switch只能使用常量(枚举常量、字符串常量或者数字字面量),而when结构可以使用任何类型对象

fun max(c1: Color, c2: Color) = when (setOf(c1, c2)) {setOf(Color.RED, Color.YELLOW) -> Color.ORANGEsetOf(Color.YELLOW, Color.BLUE) -> Color.GREENsetOf(Color.BLUE, Color.VIOLET) -> Color.INDIGOelse -> throw Exception("Dirty color")
}

这里使用when结构,包含的是一个set对象

3.4 使用不带参数的“when”

when结构可以不带参数

fun mixOptimized(c1: Color, c2: Color) {when {(c1 == Color.RED && c2 == Color.YELLOW) ||(c1 == Color.YELLOW && c2 == Color.RED) ->Color.ORANGE(c1 == Color.BLUE && c2 == Color.YELLOW) ||(c1 == Color.YELLOW && c2 == Color.BLUE) ->Color.GREEN(c1 == Color.BLUE && c2 == Color.VIOLET) ||(c1 == Color.VIOLET && c2 == Color.BLUE) ->Color.INDIGOelse -> throw Exception("Dirty color")}
}

如果没有提供when的参数,分支条件就是任意的布尔表达式

3.5 合并类型检查和转换

Java中,用于判断对象是否是一个类的实例,需要使用instanceof关键字。通常传入的参数是父类类型时,需要转换成子类类型,还需要使用强转。

interface Expr
class Num(val value: Int) : Expr
class Sum(val left: Expr, val right: Expr) : Exprfun eval(e: Expr): Int {if (e is Num) {val n = e as Numreturn n.value}if (e is Sum) {return eval(e.left) + eval(e.right)}throw IllegalArgumentException("Unknown expression")
}

上面是类似于Java中的写法,is关键字用于判断对象是否是Num类对象,相当于instanceof。as关键字用于强转。
但是Kotlin中合并了类型检查和转换

val n = e as Num

这一行是不需要的,因为is关键字在检查的时候,如果返回true,就自动的将e转换成了Num对象

3.6 用“when”代替“if”

上面的例子可以使用when结构进行改造

fun eval(e: Expr): Int =when (e) {is Num -> e.valueis Sum -> eval(e.left) + eval(e.right)else -> throw IllegalArgumentException("Unknown expression")}

直接返回when运算的值,这里的when结构中,用于判断对象类型。

3.7 代码块作为“when”的分支

fun evalWithLogging(e: Expr): Int =when (e) {is Num -> {println("num : ${e.value}")e.value}is Sum -> {val left = evalWithLogging(e.left)val right = evalWithLogging(e.right)println("sum: $left + $right")left + right}else -> throw IllegalArgumentException("Unknown expression")}

when结构的分支中可以是代码块。这里由于when直接充当返回值,所以各个分支的最后一行就是返回值

4 循环语句

Kotlin支持两种循环:while循环和for循环

4.1 while循环

语法

while (condition) {...
}do {...
} while (condition)

4.2 for循环

Kotlin中的for循环和Java中不太一样,使用的是区间和数列
区间:
表示两个范围内的数,使用..运算符

val oneToTen = 1..10

这个区间是一个闭合的区间,两边临界都能取到

for (i in 0..10) {println(i)
}

使用for循环遍历0到10,i不需要提前定义,这里使用的时候就直接定义了

for (i in 0..10 step 2) {println(i)
}

可以使用step跳过其中的一些值

for (i in 10 downTo 0 step 2) {println(i)
}

可以使用downTo做倒序的遍历

for (i in 0 until 10) {println(i)
}
for (i in 0 ..<10) {println(i)
}

可以使用until关键字或者..<来做一个左闭右开的区间

4.3 迭代map

循环常用的就是用来遍历集合

val binaryReps = TreeMap<Char, String>()
for (c in 'A'..'F') {val binary = Integer.toBinaryString(c.code)binaryReps[c] = binary
}
for ((letter, binary) in binaryReps) {println("$letter = $binary")
}

map添加元素可以使用使用赋值这种简写方式,遍历的时候可以将key-value展开到两个变量中

val list = arrayListOf("10", "12", "2343")
for ((index, element) in list.withIndex()) {println("$index = $element")
}

遍历的时候也可以不用定义索引值,而是通过withIndex获取

4.4 使用“in”检查集合和区间成员

使用in检查元素是否在其中或者!in检查元素是否不在其中

fun isLetter(c: Char) = c in 'a' .. 'z' || c in 'A' .. 'Z'
fun inNotDigit(c: Char) = c !in '0' .. '9'

这两个判断也适用于when表达式

fun recognize(c: Char) = when (c) {in '0'..'9' -> "It's a digit"in 'a'..'z', in 'A'..'Z' -> "It's a letter"else -> "I don't know"
}

5 异常

5.1 抛异常和捕获异常

Kotlin中的异常和Java中相似,一个函数可以正常结束,也可以抛出异常。异常可以处理,也可以向上抛出。
抛出异常:

if (percentage !in 0 .. 100) {throw IllegalArgumentException("Invalid percentage")
}

捕获异常

fun readNumber(reader: BufferedReader): Int? {try {val line = reader.readLine()return Integer.parseInt(line)} catch (e: NumberFormatException) {return null} finally {reader.close()}
}

同样使用try...catch...finally结构

try作为表达式

Kotlin中try可以作为表达式

fun readNumber(reader: BufferedReader): Int? =try {val line = reader.readLine()Integer.parseInt(line)} catch (e: NumberFormatException) {null} finally {reader.close()}

try是一个表达式,可以直接返回,运算中的最后一行就是返回值

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/267700.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

医学多模态模型总结(一)

概念 医学多模态大模型是指利用多种不同的医学数据源和模型&#xff0c;通过深度学习和人工智能技术&#xff0c;构建一个综合性的大型模型&#xff0c;以实现更加准确和全面的医学数据分析和预测。 这种模型可以同时处理多种医学数据类型&#xff0c;如医学图像、病历文本、…

【Jeecg Boot 3 - 第二天】2.1、nginx 部署 JEECGBOOT VUE3

一、场景 二、实战 ▶ 2.1、打包&#xff08;build 前端&#xff09; &#xff1e; Stage 1&#xff1a;修改配置文件 .env.production&#xff08;作用&#xff1a;指向后端接口地址&#xff09; &#xff1e; Stage 2&#xff1a;点击build&#xff08;作用&#xff1…

vue宝典之项目结构介绍

文章目录 &#x1f341;前言&#x1f341;Vue.js基本概念&#x1f341;Vue.js核心特性&#x1f341;Vue.js应用场景&#x1f341;Vue项目结构&#x1f341;Vue开发流程 目前在学习vue项目&#xff0c;之前只是学习vue中基本语法&#xff0c;当接触项目时发现vue项目结构之间配置…

我的NPI项目之Android 显示 -- 背光的电路小知识

由于使用的高通平台一直在演化&#xff0c;从SDM660,QCM4290,QCM4490再到QCM6490。产品的背光设计也是一直在迭代。 简单罗列了一下所经历的一些设计&#xff0c;简单的背光也涉及到了很多学问。 先说有哪些类型&#xff1a; 1. SDM660上由PMIC提供了wled给背光, 透过驱动直…

cordic 算法学习记录

参考&#xff1a;b站教学视频FPGA&#xff1a;Cordic算法介绍与实现_哔哩哔哩_bilibili FPGA硬件实现加减法、移位等操作比较简单&#xff0c;但是实现乘除以及函数计算复杂度高且占用资源多&#xff0c;常见的计算三角函数/平方根的求解方式有①查找表&#xff1a;先把函数对应…

记录 DevEco 开发 HarmonyOS 应用开发问题记录 【持续更新】

HarmonyOS 应用开发问题记录 HarmonyOS 应用开发问题记录一、预览器无法成功运行?如何定位预览器无法编译问题? 开发遇到的问题 HarmonyOS 应用开发问题记录 一、预览器无法成功运行? 大家看到这个是不是很头疼? 网上能看到许多方案,基本都是关闭一个配置 但是他们并…

【ZYNQ】AXI4总线接口协议学习

建议翻看着底部的参考文档资料和本文一起辅助阅读 本文带你详细的了解AXI总线协议&#xff0c;并且基于官方手册&#xff0c;能够提高你的手册阅读能力。 什么是AXI AXI 的英文全称是 Advanced eXtensible Interface&#xff0c;即高级可扩展接口&#xff0c;它是 ARM 公司所提…

LeetCode力扣每日一题(Java):58、最后一个单词的长度

一、题目 二、解题思路 1、我的思路 先将字符串转换成字符数组 由于我们需要获取最后一个单词的长度&#xff0c;所以我们从后往前遍历字符数组 我们还需判断所遍历的字符是不是字母&#xff0c;即判断每个字符对应的ASCII值即可&#xff0c;用计数器count来储存单词长度 …

智能优化算法应用:基于头脑风暴算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于头脑风暴算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于头脑风暴算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.头脑风暴算法4.实验参数设定5.算法结果6.…

使用torch解决线性回归问题

数据处理 import torch import numpy as np import pandas as pd import matplotlib.pyplot as pltdatapd.read_csv(./datasets/Income1.csv) #数据准备data.head(5)#展示数据 #以上所有的代码都是用jupyter notebook写&#xff0c;形成了阶段性的结果展示 查看数据信息 dat…

FFmpeg-基础组件-AVFrame

本章主要介绍FFmpeg基础组件AVFrame. 文章目录 1.结构体成员2.成员函数AVFrame Host内存的获取 av_frame_get_bufferAVFrame device内存获取av_hwframe_get_buffer&#xff08;&#xff09; 1.结构体成员 我们把所有的代码先粘贴上来&#xff0c;在后边一个一个解释。 typede…

编程实战:自己编写HTTP服务器(系列4:查看文件、下载等一般功能)

系列入口&#xff1a;编程实战&#xff1a;自己编写HTTP服务器&#xff08;系列1&#xff1a;概述和应答&#xff09;-CSDN博客 本文介绍各种功能的实现。大部分是特定内置入口。 目录 一、默认页 二、查看文件 三、关闭服务 四、下载页面 一、默认页 前面在已经介绍过重定…