想了很久,一直在想怎么记录笔记最高效,最后感觉还是结合代码比较好。
1.整数的遍历,in表示是否在一个区间内,!in表示不再某个区间内
fun fizzBuzz(i:Int) = when {
i%15==0->"FizzBuzz "
i%3==0->"Fizz "
i%5==0->"Buzz "
else ->"$i "
}
>>>for(i in 100 downTo 1 step 2) {print(fizzBuzz(i))}
2.类似java,Pair的用法val list = arrayListOf("10", "11", "1001")
for((index, element) in list.withIndex()) {println("$index: $element")}
3.类似java中的.class
>>>println(set.javaClass)
***4.给别人的类添加方法:扩展函数和属性,注意包名要对
package strings
fun:String.lastChar():Char = this.get(this.length()-1)
接收者类型 接收者对象
可以像调用类的普通成员函数一样去调用这个函数
>>>println("Kotlin".lastChar())
***扩展函数不能访问私有的或者是受保护的成员
5.导入和扩展函数
对于你定义的一个扩展函数,它不会自动地在整个项目范围内生效。相反,如果你要使用它,需要进行导入,(果然不出我所料),就像其他任何的类或者函数一样。Kotlin允许用和导入类一样的语法来导入单个的函数
import strings.lastChar或者import strings.*
val c ="Kotlin".lastChar()
用as来修改导入的类或者函数名称
import strings.lastChar as last
val c = "Kotlin".last()
6.不可重写的扩展函数
扩展函数并不是类的一部分,它是声明在类之外的。尽管可以给积累和子类都分别定义一个同名的扩展函数,此时需要调用时,会按照类的定义类型来判定到底会调用哪个函数。
fun View.showoff() = println("I'm a View!")
fun Button.showOff() = println("I'm a button!")
>>>val view:View = Button()
>>view.showOff()
I'm a View!
注意:扩展函数和成员函数同时存在时,成员函数的优先级要高于扩展函数。
扩展函数相当于静态函数,所以不存在重写的问题。
7.字符串的分割split方法
按照正则表达式来进行分割
>>>println("12.345-6.A".split("\\.|-".toRegex)))
[12,235,6,A]
Kotlin中的split扩展函数的其他重载支持任意数量的纯文本字符串分隔符
>>>println("12.345-6.A".split(".", "-"))
输出结果相同
8.正则表达式和三重引用的字符串
fun parsePath(path:String) {
fun parsePath(path:String) { val directory = path.substringBeforeLast("/") val fullName = path.substringAfterLast("/") val fileName = fullName.substringBeforeLast(".") val extension = fullName.substringAfterLast(".") println("Dir: $directory, name: $fileName, ext: $extension") }
fun parsePath(path:String) { val regex = """(.+)/(.+)\.(.+)""".toRegex() val matchResult = regex.matchEntire(path) if(matchResult != null) { val (directory, filename, extension) = matchResult.destructured println("") } }
正则表达式写在一个三重引号的字符串中。在这样的字符串中,不需要对任何字符进行转义。
9.提取逻辑到扩展函数
class User(val id:Int, val name:String, val address:String) fun User.validateBeforeSvae() { fun validate(value :String, fieldName:String) { if(value.isEmpty()) { throw IllegalArgumentException("Can't save user $id:empty $fieldName") } } validate(name, "name") validate(address, "address") }
10.Kotlin的声明默认是final和public的。嵌套的类默认并不是内部类:他们并没有包含对其外部类的隐式引用。
Kotlin编译器能够生成有用的方法来便面荣誉。将一个类声明成data类可以让编译器为这个类生成若干标准方法。
11.kotlin接口可以带默认实现,在一个类实现了两个接口,并且这两个接口拥有同一个名称的方法时,调用这个方法时,“任何一个都不会被调用”,需要显式地实现对应的方法。
override fun showOff() { super.showOff() super.showOff() }
12.如果想创建一个类的子类,需要使用open修饰符来标示这个类。
注意:脆弱的基类问题,因为基类代码的修改不再符合在其子类中的假设。如果类没有提供子类应该怎么实现的明确规则(那些方法选用被重写及如何重写),当事人可能会有按基类作者预期之外的方式来重写方法的风险。因为不可能分析所有的子类,这种情况写基类是如此的脆弱,任何修改都有可能导致子类出现语气之外的行为改变。
13.internal可见性的优势在于它提供了对米小实现细节的真正封装。使用java时,这种封装很容易被破坏,因为外部代码可以将类定义到与你代码相同的包中,从而得到访问你的包私有声明的权限。
14.密封类:定义受限的类继承结构
使用when的时候,如果你添加了一个信息的子类,编译器并不能发现有地方改变了,如果你忘了添加一个新分支,就会选择默认的选项,这有可能导致潜在的bug。
kotlin解决方案,sealed类。
sealed class Expr { class Num(Val value:Int) :Expr() class Sum(Val left:Expr, val right:Expr):Expr() } fun eval(e:Expr) :Int = when(e) { is Expr.Num -> e.value is Expr.Sum -> eval(e.right) + eval(e.left) }
sealed修饰符隐含的这个类是一个open类
Kotlin1.1解除了这些限制并允许在同一文件的任意位置定义子类
欲知后事如何,请听下回分解,enjoy yourselves!