我们常常困惑,学习了很多东西,react, mongodb,java currreny, netty,但是我们一个时间段只能专注于某个技术的开发,某个领域的开发,但是,那个时候还能理解bytebuffer的底层实现是什么样子的,长时间不接触,很快就会遗忘,所以鼓励自己多输出博客加深对知识的理解
zhangjin-007 / developer-blog Goto Github PK
View Code? Open in Web Editor NEWblog
blog
开头我们介绍下kotlin的接口,kotlin接口跟java的接口差不多,jdk8中接口增加了默认方法实现,是为了兼容jdk向下兼容,还有考虑stream少写了很多代码,在kotlin中是否也可以写具体的方法,答案是肯定的。在多实现继承中有这样的问题,接口A有method方法的实现,父类B也有method方法实现,子类C怎么办,子类C必须override相同的方法签名,还有一个问题,怎样在子类C中指定调用A的实现,还有B的实现,这里kotlin也考虑的十分充分😆
interface A {
fun method() {
println("A")
}
}
open class B{
open fun method(){
println("B")
}
}
/**
* 接口,父类中都有方法实现,子类必须自己实现一套
*/
class C: A, B(){
override fun method() {
//语法太风*
super<A>.method()
super<B>.method()
println("C")
}
}
fun main(args: Array<String>) {
var c = C()
c.method()
}
kotlin抽象类没什么好说的,只有一点,父类BaseClass中有method方法实现,子类ChildClass可以把父类的实现变成抽象方法
//抽象类
open class BaseClass{
open fun method() {
}
}
/**
* 可以用abstract方法override父类
*/
abstract class ChildClass : BaseClass() {
override abstract fun method()
}
伴生对象的概念是什么,可以用java语言方式理解,它是静态内部类,为什么要设计这样的伴生对象?
首先我们了解对象声明的概念,java中没有提供直接对象,但是js中提供了对象,面向对象是靠对象来实现的,即使ts语法糖里有class关键字,但是本质还是对象,对象就可以不用实例化,直接调用。
//object declaration,对象声明
object MyObject {
fun method() {
println("method")
}
}
fun main(args: Array<String>) {
MyObject.method()
}
下面来说明kotlin的伴生对象,下面的例子就是伴生对象的使用例子
class MyTest {
companion object MyObject{
var a: Int = 100
// @JvmStatic
fun method() {
println("method invoked!")
}
}
}
fun main(args: Array<String>) {
MyTest.MyObject.method()
println("------")
println(MyTest.a)
MyTest.method() //类似于静态方法,Kotlin中没有静态方法
println("------")
val v = MyTest.MyObject
println(v.javaClass)
}
伴生对象是为了提供给kotlin像java一样,可以使用一个静态的使用方式,《effetive java》 中static是特别推荐用的,有很多好处,初始化的次数少,可以做缓存,推荐使用静态工厂方法来构造一个类的实例。
如上图看,根据我们调用方式虽然可以 使用MyTest.method(),但是MyTest反编译结果并没有method静态方法
2.我们加上@JvmStatic,然后重新build
如图就是对每条tips的最好的证明😝
结合上一篇的博客,kotlin class中的构造方法分为primary constructor 只有一个, secondary constructor可以有多个,主构造方法可以给定参数,那么这些参数的初始化会在class 的init代码块中执行,而secondary constructor 的初始化跟参数是在一起的, 且secondary必须直接或者间接调用primary constructor,这部分内容跟java有着很大的不同。constructor 如果没有修饰符,默认是public的修饰符,而java中是default修饰符,这点也有区别
来,上代码
class Person constructor(userName: String) {
private var userName: String? = null
private var age:Int
private var adderss:String
init {
println(userName)
this.userName = userName
this.age = 20
this.adderss = "beijing"
}
//直接或者间接调用primary方法
constructor(userName: String, age: Int) : this(userName){
println("$userName, $age")
this.age = age
this.adderss = "beijing"
}
//直接或者间接调用primary方法
constructor(userName: String, age: Int, address: String) : this(userName, age){
println("$userName, $age, $address")
this.adderss = adderss
}
fun printInfo() {
println("username: ${this.userName}, age: ${this.age}, ${this.adderss}")
}
}
fun main(args: Array<String>) {
var person = Person("zhangsan")
var person2 = Person("lisi", 12)
var person3 = Person("lisi", 20, "nanjing")
person.printInfo()
person2.printInfo()
person3.printInfo()
}
由执行结果可以看出调用顺序,先走primary,再走secondary
kotlin还提供了一种简约的类的定义方式
我们可以直接在构造方法入参中,直接定义成员变量,可以给定成员变量的默认值,这种方式一般在真是的成产开发中比较常见,因为谁都不愿意多写代码😠,虽然java有lombok这样的框架减少了很多代码
class Student(private val userName: String, private val age: Int, private var address: String) {
fun printInfo() {
println("username: $userName, age: $age, address: $address")
}
}
/**
* constructor 有修饰符,或者注解的情况下,constructor关键字不可以省略
*
*/
class Student2 private constructor(userName: String){
}
/**
* 构造方法提供默认参数, 如果primary构造方法都有默认值,
* 在jvm上面如果所有的构造方法都有默认值,编译器会帮我们生成一个不带参数的构造方法,为了去兼容
第三方比如spring框架
*/
class Student3 (val userName: String = "zhangsan"){}
fun main(args: Array<String>) {
val student = Student("zhangsan", 20, "beijing")
student.printInfo()
}
通过代码可以看出来,方法直接可以引用到构造方法定义的值,这个可以通过模板字符串的引用可以看清楚
还有就是一点值得提 在jvm上面如果所有的构造方法都有默认值,编译器会帮我们生成一个不带参数的构造方法,目的是为了去兼容第三方比如spring框架,初始化实例的时候会调用那个不带参数的构造方法,而这个构造方法的初始值会调用所有参数的默认值😙 kotlin规矩确实有点多啊,期待后面新的不同,更有深度的学习输出😊也很期待,在生成环境中使用kotlin浪一把
以前看过的东西不知道输出,最近春节看了kotlin,从最基础的开始,用这样博客的形式开始文档输出,旨在加强学习印象
首先
这个函数转化入参为字符串
fun main(args: Array<String>) {
println(convert2Uppercase("hello world"))
println(convert2Uppercase(23))
}
fun convert2Uppercase(str: Any) : String?{
if(str is String){
return str.toUpperCase()
}
return null
}
在java中可能需要instanceof 判断然后再进行强制类型装换,kotlin编译器自动帮我们识别类型
在数组循环中,跟es6/typescript支持的有点相似,既能取出元素,也能取出index
fun main(args: Array<String>) {
var array = intArrayOf(1, 2, 3, 4, 5)
for (item in array) {
println(item)
}
println("-----")
for (index in array.indices) {
println("array[$index] = ${array[index]}")
}
println("-----")
for ((index, value) in array.withIndex()) {
println("array[$index] = $value")
}
}
可以打印一个元素,可以打印数组里面的index,可以打印index跟数组内容
看kotlin Int的实现可以看出,在面向jvm的时候,Int是原生数据类型,而intArrayOf返回的是int[]
我们再来看下强大的when
fun main(args: Array<String>) {
println(myPrint("hello"))
println(myPrint("world"))
println(myPrint("hello world"))
println(myPrint("nothing"))
println("------")
var a = 6
var result = when(a){
1 -> {
println("a = 1")
10
}
2 -> {
println("a = 2")
20
}
3, 4, 5-> {
println("a =3 or a = 4 or 5")
30
}
in 6..10-> {
println("in range")
40
}
else -> 50
}
}
fun myPrint(str: String): String {
return when (str) {
"hello" -> "HELLO"
"world" -> "WORLD"
"hello world" -> "HELLO WORLD"
else -> "other input"
}
}
fun myPrint2(str: String): String = when (str) {
"hello" -> "HELLO"
"world" -> "WORLD"
"hello world" -> "HELLO WORLD"
else -> "other input"
}
when的使用相对于java中的switch case, ->这样的写法并不是lambda表达式,但是看看myPrint函数,语法比起java要风*👍,也可以按照myPrint2函数的写法,直接返回一个表达式,语法更加简约👍,在最后的例子中,when的条件可以是枚举数,可以是枚举数范围,也可以是一个区间。由上面的例子可以看出kotlin when的语法糖对开发很友好,十分适合写我们平时复杂的业务开发🚀
kotlin里面提供了扩展,用起来像js这些动态语言,可以给一个既有的类,提供一个方法,也可以提供一个属性,java中的装饰模式,也是对既有的实现类中,添加额外的功能。
class ExtensionTest {
fun add(a: Int, b: Int) = a + b
fun substract(a: Int, b: Int) = a - b
}
//不使用设计模式实现
fun ExtensionTest.multiply(a: Int, b: Int) = a * b
fun main(args: Array<String>) {
var extensinTest = ExtensionTest()
println(extensinTest.add(1, 2))
println(extensinTest.substract(1, 2))
println(extensinTest.multiply(1, 2))
myPrint(BB())
CC().foo()
}
open class AA
class BB: AA()
fun AA.a() = "a"
fun BB.a() = "b"
fun myPrint(aa: AA) {
println(aa.a())
}
class CC {
fun foo() {
println("member")
}
}
fun CC.foo() {
println("member2")
}
/**
* 对any进行扩展
*/
fun Any?.toString(): String {
if (null == this) {
return "null"
}
return toString()
}
属性的扩展
class MyExtensionProperty {
}
val MyExtensionProperty.name: String
get() = "hello"
fun main(args: Array<String>) {
var myExtensionProperty = MyExtensionProperty()
println(myExtensionProperty.name)
}
伴生对象的扩展
class CompanionObjectExtension {
companion object MyObject{
}
}
fun CompanionObjectExtension.MyObject.method() {
println("extension companion")
}
fun main(args: Array<String>) {
CompanionObjectExtension.method()
}
以上的作用域是全局的,我们来看下koltin的作用域
class ExtensionReciver {
fun method() {
}
}
class DispatchReceiver {
fun method2() {
}
fun ExtensionReciver.hello() {
//can call two method
method()
method2()
}
/**
* 在分发接收者里面可以调用扩展方法
*/
fun world(extensionReciver: ExtensionReciver) {
extensionReciver.hello()
}
/**
* toString()的优先级最高 3
*/
fun ExtensionReciver.output() {
println(toString())
//如果必须用分发接受这的话,语法是这样
println(this@DispatchReceiver.toString())
}
fun test() {
var extensionReciver = ExtensionReciver()
extensionReciver.output()
}
}
fun main(args: Array<String>) {
//扩展只能在DispatchReceiver范围内使用
DispatchReceiver().test()
}
为啥要扩展,在jdk中有很多辅助类,Collections 很对静态方法,提供了排序,二分查找的功能,如果koltin中可能直接给list扩展一个业务方法,这样相对简单。但是Collections可以做到复用,不知道koltin这方面怎么实践的。
实现第一个程序,我们不需要编辑器
直接vim
结合上篇文章,kotlin里面的range使用..来表示,java中的range一般是前闭后开,kotlin中的则不一样,2..8是表示2到8,也包含8,首先我们看个例子
val a = 5
val b = 10
if (a in 2..b) {
println("in the range")
}
if (a !in 2..b) {
println("out of the range")
}
println("------")
for (i in 2..10) {
println(i)
}
println("------")
for (i in 2.rangeTo(10)) {
println(i)
}
println("------")
//步进
for (i in 2..10 step 2) {
println(i)
}
println("------")
//10-2 步进4
for (i in 10 downTo 2 step 4) {
println(i)
}
第一个跟第二循环表示的意思相同,第三个通过step来进行步进,第四个则是反过来步进,很直观
java8中stream操作一个数组很方便,那么在kotlin中是什么样的呢,我们看如下例子
fun main(args: Array<String>) {
var array = listOf<String>("hello", "world", "hello world", "welcome", "bye")
for (item in array) {
println(item)
}
println("------")
when {
"world" in array -> println("world in collection")
}
//找出长度超过5 字符串大写,默认字符排序,打印控制台 awsome
array
.filter { it.length > 5 }
.map { it.toUpperCase() }
.sorted().forEach { println(it) }
}
1.找出集合里面的world 使用when表达式 替代了传统的if,这个跟之前的when的使用又不一样
2.实现的流的操作,比之java8的语法更加优雅, it代表lambda表达式的入参
最后一个例子是写class的,跟java中做对比
class EmptyClass
如果往class前面添加public也是可以的,但是编辑器提醒public是多余的,说明默认class就是public的,加不加都可以,其次java中要求public class 类名跟文件名保持一致,在kotlin中没有这样的规定,如果类中什么也没有,可以不带花括号
在看下面
class MyClass constructor(userName : String){
private val userName: String = userName.toUpperCase()
init {
println(userName)
}
}
fun main(args: Array<String>) {
val myClass: MyClass = MyClass("zhangsan")
}
1.在kotlin中,一个类可以有个primary构造方法以及一个或者多个secondary构造方法
2.primary构造方法是类头(class head) 的一部分,它位于类名后面,可以拥有若干参数
3.如果primary构造方法没有任何注解或者可见性关节字修饰,那么constructor关键字可以省略
4.初始化MyClass,省略了new关键字
上面的例子可以看到init代码块其实就是类似之前java构造方法的逻辑,这里构造方法,跟初始化构造方法逻辑做了拆分,构造方法要么用于初始化成员变量,要么用于init代码块逻辑,如上面例子,上面例子运行结果
zhangsan
kotlin getter,setter 跟java的不一样,我们直接看代码
class ThePerson(address: String, name: String) {
val age: Int
get() = 20
var address = address
get(){
println("get invoke")
//backing field
return field
}
set(value) {
println("set invoke")
field = value
}
var name = name
// private set
}
fun main(args: Array<String>) {
var person = ThePerson("shanghai", "zhangsan")
println(person.age)
println(person.address)
person.address = "beijing"
println(person.address)
println(person.name)
person.name = "hello"
println(person.name)
}
Kotlin中要求非空类型属性必须在构造方法中初始化:joy:,跟spring一起使用的时候,比如依赖注入,单元测试属性赋值,所以加上lateinit关键字
class TheClass {
lateinit var name: String
fun init() {
this.name = "zhangsan"
}
fun print() {
println(this.name)
}
}
fun main(args: Array<String>) {
var theClass = TheClass()
theClass.init()
theClass.print()
}
我一直在想如何写好这一篇文章,因为此章节应该比之前面的章节更有价值,内容更加有趣,学习的其中一个乐趣在于看完一个理论,又在另外一个地方看到了理论的实践,随着开发经验的增加,发现技术并不是井喷式的增加,而是破冰式的,怎么说呢,技术在某个地方都有着相似的地方,看完koltin的继承,重载设计,还有很多关键字如 open ,override, final就不得不佩服koltin的设计👍,因为它在很多程度上遵守了《effective java》里面的items,下面容我娓娓道来😝。
// 在kotlin中, 所有类在默认情况下都是无法被继承的,
// 在kotlin中,所有类默认情况都是final的
// open的含义与final相反
open class Parent(name: String, age: Int){
}
class Child(name: String, age:Int): Parent(name, age) {
}
open class Parent2(name: String){
}
/**
* 在kotlin中,如果一个类没有primary构造方法,那么这个类的secondary构造方法就需要通过
* super关键字来初始化父类型,或者通过其他secondary 构造方法完成这个任务
* 不同的secondary构造方法可以调用父类型的不同的构造方法
*/
class Child2: Parent2{
constructor(name: String): super(name){
}
}
open class Fruit{
open fun name(){
println("fruit")
}
fun expirationDate(){
println("1 month")
}
}
class Apple: Fruit(){
override fun name(){
println("apple")
}
}
open class Orange: Fruit(){
//orange name不可以被子类改写的
final override fun name() {
println("orange")
}
}
fun main(args: Array<String>) {
var apple = Apple()
apple.name()
apple.expirationDate()
}
open class MyParent{
open val name: String = "parent"
}
class MyChild : MyParent() {
override val name: String = "child"
}
fun main(args: Array<String>) {
var myChild = MyChild()
println(myChild.name)
println("----")
var myChild3 = MyChild3()
myChild3.method()
println(myChild3.name)
}
class MyChild2(override val name: String) : MyParent() {
}
open class MyParent3{
open fun method() {
println("parent method")
}
open val name: String get()= "parent"
}
/**
* 1.val 可以 override val
* 2.var 可以 override val
* 2.val 不可以 override var
* 本质上 val相当于get方法, var相当于get和set方法
*/
class MyChild3: MyParent3(){
override fun method() {
super.method()
println("child method")
}
override val name: String
get() = super.name + "and child"
}
这里var修饰的 get()方法,不能被val修饰的成员变量重载,原因是,子类不能缩小父类的读写权限
effective java对于后端程序员如圣经般的存在,需要好好研读:innocent:
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.