记录学习过程,用简短的话描述核心价值。
本文主要对kotlin的一些基本知识进行简单的介绍。
1、函数
kotlin中,代码末尾不需要分号(;)结束, 用fun声明一个函数,以下是声明一个无返回值的函数:
/**
* fun:声明一个函数
*/
fun main(args: Array<String>) {//参数名字冒号接上参数的类型
println("Hello world")
}
声明一个有返回值的函数,需要在形参括号后面加上冒号及返回类型:
fun sum(a: Int, b: Int): Int {
return a + b
}
2、变量
kotlin的所有变量用var和val两个关键字声明,var表示可变变量,来源于单词variable, val表示不可变变量,来源单词value,相当于java中的final变量;
val test1 = "value" //不可变变量, 用val声明final变量,只能赋值一次
var test2 = "variable" //可变变量,可以改变赋值
错误的代码示范:
val test = "value"
test = "value2" //这会报错
编译器都可以根据变量的值自动推导类型, 所以通常忽略了具体的类型,当然也可以显示的加上, 如:
val test: String = "value"
3、变量的打印
除了使用传统的java格式外,还能使用一下方式:
val question = "value"
println("Hello, $question")//这里编译为class文件后,实际上打印的是一个StringBuilder,从而提升性能
直接在双引号中,使用符号$跟上变量的形式,即可打印这个变量, 如果打印的是一个表达式,比如a+b,那么要用大括号括起来, 例如 println(“Hello, ${a+b}”)
4、类和属性
以下是java表示的javabean对象,按照标准必须要声明get和set方法:
/* Java */
public class Person {
private final String name;
public Person(String name) {
this.name = name;
}
public String getName(){
return name;
}
}
用kotlin只需要如下声明:
class Person(val name: String)
所以有时候,有多个这样的类,我们可以统一放到一个kt文件中,就不用像java一样要创建多个java文件,更好的管理bean类。
kotlin中这种只有数据,没有其他代码的类,称为值对象
5、kotlin自定义属性的get/set方法
class Rectangle(val height: Int, val width: Int) {
val isSquare: Boolean //这里必须显示声明属性的类型
get() {
return height == width
}
}
这个长方形的类,除了宽高,还多了一个是否是正方向的boolean属性,并为它设置了get方法,这个变量是val类型的,只能赋值一次,所以没有set方法, 自定义属性访问器,则必须要显示的声明这个属性的类型
6、kotlin源码的包目录结构
这个和java类似,包名就是路径名。同一个包下不需要导入,不同包需要import导入。
但是区别就是kotlin可以直接导入顶层函数的名称, 即java中使用某个类的的静态方法,需要导入这个类,然后用 类名.方法名 进行使用, 而kotlin导入方法的全路径名后,直接使用方法即可。kotlin代码如下:
import geometry.shapes.createRandomRectangle//导入另一个文件中的createRandomRectangle()方法
fun main(args: Array<String>) {
println(createRandomRectangle().isSquare)//在这个kt文件中直接使用方法名调用;
}
7、枚举类型
一个普通的颜色枚举类型声明:
enum class Color {
RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET
}
一个有属性的枚举类声明:
/**
* 带属性的枚举类,必须声明枚举类的属性的类型
*/
enum class Color2(val r: Int, val g: Int, val b: Int) {//圆括号中声明了枚举类三个属性对应的类型,这里全是Int类型
RED(255, 0, 0),//RED这个枚举常量三个属性赋值为255,0,0
ORANGE(255, 165, 0),
YELLOW(255, 255, 0),
GREEN(0, 255, 0),
BLUE(0, 0, 255),
INDIGO(75, 0, 130),
VIOLET(238, 130, 238)
}
8、关键字when的使用
when是kotlin中一个非常强大的功能,比java中的switch更强大, switch要求使用常量(枚举、字符串、数字)作为分支条件,when允许使用任何对象。
/**
* when比java中的switch强大很多,可以使用任意对象
*/
fun test(color : Color) =
when (color) {
Color.RED -> println("red color")//->符号类似于switch中的冒号:
Color.ORANGE -> println("orgnge color")
Color.YELLOW -> {//如果有多行代码,则必须用大括号包起来
println("yellow color 01")
println("yellow color 02")
}
Color.GREEN -> println("green color")
Color.BLUE -> println("blue color")
Color.INDIGO -> println("indigo color")
Color.VIOLET -> println("violet color")
else -> println("not a color") //如果没有把枚举类型全部在when列出,则必须有else分支
}
使用when时,可以可以不带参数,直接通过任意布尔表达式做为分支条件:
fun mixOptimized(c1: Color, c2: Color): Color {//返回类型是Color
when {//这里when没有圆括号和参数
(c1 == c2) -> {
println("Color.ORANGE")
return Color.ORANGE
}
c1 == Color.YELLOW -> {
println("Color.YELLOW")
return Color.YELLOW
}
c2 == Color.VIOLET -> {
println("violet")
return Color.VIOLET
}
else -> return Color.RED
}
}
9、类型智能转换
定义一个接口和两个继承接口的类:
interface Expr
class Num(val value: Int) : Expr
class Sum(val left: Expr, val right: Expr) : Expr
定义一个方法返回 Expr类型的值:
fun eval(e: Expr): Int {
if (e is Num) {//判断e具体是 Num还是Sum类型
val n = e as Num //显示的把e转化为Num类型,这一步是多余的
return n.value
}
if (e is Sum) {
return eval(e.right) + eval(e.left)
}
throw IllegalArgumentException("Unknown expression")
}
通过关键字 is 可以判断e是不是我们想要的类型, 关键字 as可以强转类型, 但是一般如果通过了 is判断,那么不需要再强转就能直接使用。
10、用when代替if
fun evalWithLogging(e: Expr): Int = //这个方法返回值类型为Int
when (e) {
is Num -> {
println("num: ${e.value}")
e.value //最后一行直接作为值返回, 这里省略了return
}
is Sum -> {
val left = evalWithLogging(e.left)
val right = evalWithLogging(e.right)
println("sum: $left + $right")
left + right
}
else -> throw IllegalArgumentException("Unknown expression")
}
kotlin中,除了while、do…while, 绝大部分表达式都是有值的,上面直接用表达式的值作为返回值,并且省略了return。
11、区间、数列、步长
java中,如果我们要给一个数组初始化1-10的值,比如:
int[] a = {1,2,3,4,5,6,7,8,9,10};
在kotlin中,这个被简化了,可以直接用两个点…作为运算符表示区间:
val a = 1..10 //这个表示取值1-10,是闭区间,包含开头和结尾的值
这样的区间乘坐数列,再比如我们要打印1-100的值,用循环打印:
fun test() {
for (i in 1..100) {//从1开始打印到100
println(i) //每次执行后,i会自动+1
}
}
规则在复杂一点,我们设置一个步长,每次执行后加上步长的值,比如每间隔2个值打印
fun test() {
for (i in 1..100 step 2) {//每次间隔2个值,打印出来1,3,5,7,9。。。
println(i)
}
}
还有更多的规则,后面到讲kotlin方法的博客中继续探究。
12、迭代map集合
kotlin中创建对象,不需要使用new
fun test() {
val binaryReps = TreeMap<Char, String>()
for (c in 'A'..'F') {//把A到F存到集合binaryReps中
val binary = Integer.toBinaryString(c.toInt())
binaryReps[c] = binary //把字母作为key,转化为的二进制作为value保存到map集合中
}
for ((key, value) in binaryReps){
println("$key = $value")
}
}
这里for循环中用到了in,每次循环从map中取出一个键值对。
13、when和in组合使用
fun test(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…"
}
14、kotlin中的异常
如果a的大小不是0到100,则排抛异常,和kotlin中使用类一样,这里也不需要new关键字
if (a !in 0..100) {
throw IllegalArgumentException(
"a value must be between 0 and 100")
}
15、try catch代码块作为表达式
fun readNumber(reader: BufferedReader) {
val number = try {
Integer.parseInt(reader.readLine())
} catch (e: NumberFormatException) {
return
}
}
通过解析BufferedReader中的值,然后把整个try catch代码块作为返回值赋给 number
参考资料:
1、《kotlin 实战》
2、网络资料