1、kotlin 可见性修饰符
Java有四种:
- public:包内及包外的任何类均可以访问
- protected:包内的任何类,及包外的那些继承了此类的子类才能访问
- 默认:包内的任何类都可以访问它,包外的任何类都不能访问
- private:包内包外的任何类均不能访问
Kotlin也是有四种:
- public:默认值,什么都不写表示是public。
- protected:和Java不同的是,即使在同一个包内,也不能访问protected方法。比private多了子类可以调用这一范围。
- internal:所在的整个 module 可见
- private:只在这个类内部可见。
2、kotlin 主构造函数
主构造函数 写在类头中 如果你不希望别的类访问到这个变量,可以用private修饰
class Person constructor(firstName: String) {
}
如果主构造函数没有注解或可见性说明,则 constructor 关键字是可以省略:
class Person (firstName: String) {
}
如果构造函数有注解或可见性声明,则 constructor 关键字是不可少的,并且可见性应该在前
class Customer public @inject constructor (name: String) {...}
主构造函数不能包含任意代码。初始化代码可以放在以 init 做前缀的初始化块内
class Person (firstName: String) {
init {
logger,info("Customer initialized with value ${firstName}")
}
}
总结
- 主构造函数 constructor写在类头中 ,没有修饰符或者注解修饰可以省略constructor关键字
- 主构造函数中,如果参数加var会自动生成对应的属性
- 主构造函数中,如果你不希望别的类访问到这个变量,可以用private修饰
- init代码块也属于主构造器的一部分,也可以引用主构造函数中的变量
- 如果没有主构造函数,也会隐式地创建一个无参构造函数,
- 创建对象不需要 new
3、kotlin 次构造函数
类也可以有二级构造函数,需要加前缀 constructor:
- 次级构造函数
不能直接将参数转换为属性(不能加var)
- 如果有主构造器,那么次构造器必须直接或者间接引用到主构造器
在同一个类中代理另一个构造函数使用this
关键字:
class Person(var firstName: String) {
init {
println("Customer initialized with value ${firstName}")
}
//var firstName: String? = null
constructor() : this("Xiao ming")
//不能直接将参数转换为字段,
constructor(firstName: String, lastName: String) : this(firstName) {
this.lastName = lastName
}
var lastName: String? = null
}
4、 重写get set方法
声明一个属性的完整语法是
var <propertyName>[: <PropertyType>] [= <property_initializer>]
[<getter>]
[<setter>]
其初始器(initializer)、getter 和 setter 都是可选的。属性类型如果可以从初始器 (或者从其 getter 返回值,如下文所示)中推断出来,也可以省略。
var allByDefault: Int? *错误:需要显式初始化器,隐含默认 getter 和 setter
var initialized = 1 * 类型 Int、默认 getter 和 setter
在主构造函数中 初始器(initializer) 才可以省略
class User {
constructor(name: String, sex: Int) {
this.name = name
this.sex = sex
}
var name: String? = null
var sex: Int? = null
set(value) {
// 此处 如果调用 sex 赋值 会造成死循环 sex=0
if (0 == value) { // 正确
sexStr = "男"
} else {
sexStr = "女11"
}
}
var sexStr: String? = null
// get() {
// // 此处 如果调用 sexStr 取值 会造成死循环 if ("".equals(sexStr))
// if (0 == sex) { // 正确
// return "男"
// }
// return "女"
// }
}
一般不需要重写get set方法,在某些特定场景下重写即可,但注意避免死循环
5、 继承
kotlin 中所有的类和方法默认都是final
,不能直接继承或者重写,如果要继承或重写,需要加上open
关键字
open class Parent(var name: String) {
var sex: String? = null
init {
this.name = "人"
}
// 没有加open关键字,不能重写
fun showParent() {
}
// 加open关键字可以重写
open fun showSelf() {
}
}
class Child( name: String):Parent (name){
// 没有加open关键字,不能重写
// fun showParent(){
//
// }
// 重写加 override 一般写法不换行
override fun showSelf(){
}
}
6、 接口
接口用关键字 interface 来定义:
个类或对象可以实现一个或多个接口
interface TestInterface {
//可以在接口中声明属性,但属性必须是抽象的 或 提供访问实现。
//private var name: Int //这种写法错误
//var name: String? = null //这种写法错误
var name: String
abstract var sex: Int
fun test()
}
class TestInterfaceImpl(override var name: String, override var sex: Int) : TestInterface {
override fun test() {
println(name+"--"+sex)
}
}
接口中声明的,必须是抽象的 或 提供访问实现
7、 抽象
abstract class A {
//abstract val name: String ? = null 写法错误
//val name: String ? = null 写法正确
abstract val name: String //写法正确
//抽象类里已经提供实现的方法 要想被重写必须加open
open fun test() {
println(name)
}
abstract fun testNobody()
//抽象类里的方法,可以不提供提供实现的时候需要用abstract关键字来描述 抽象的方法默认是open的
}
class B:A() {
override val name: String=""
override fun test() {
println(name)
}
override fun testNobody(){
}
}
抽象类里,抽象的方法默认是open的,非抽象方法是final的
可以不提供提供实现的时候需要用abstract关键字来描述
抽象类里 可以有属性,属性必须是非null的或者抽象的
8、可以使用默认参数来实现java重载类似的功能
//函数参数可以设置默认值,当参数被忽略时会使用默认值。这样相比其他语言可以减少重载
fun reformat(name: String, sex: Boolean = true,age: Int= 18) {
}
reformat("TOM")
reformat("Tom", true, 18)
9、data
在Kotlin中一些只保存数据的类,称为数据类(data class),
为了确保自动生成的代码一致性和有意义,数据类(data class)必须满足以下要求:
- 主构造函数至少有一个参数;
- 主构造函数的所有参数需标记为val 或 var;
- 数据类不能是抽象、开放、密封或者内部的;
编译器会为数据类(data class)自动生成以下函数:
- equals()/hashCode()
- toString() 默认输出"User(name=John, age=42)"
- componentN() 按声明顺序对应于所有属性
- copy()
10、copy
- 当要复制一个对象,只改变一些属性,但其余不变,copy()就是为此而生:
data class DataUser(val name: String, val age: Int)
val u = DataUser(name = "lioil", age = 1)
val u1 = u.copy("win") //传递第一参数,第二参数默认
val u2 = u.copy("win",2) //传递所有参数
val u3 = u.copy(age = 3) //命名参数,传递指定参数
println("$u1,$u2,$u3")
DataUser(name=win, age=1),DataUser(name=win, age=2),DataUser(name=lioil, age=3)
11、apply
- apply函数,在函数范围内,可以任意调用该对象的任意方法,并返回该对象
data class DataUser(val name: String, var age: Int){
fun test (){
println("test")
}
}
val u = DataUser(name = "lioil", age = 1)
val u1 = u.apply {
age = 15
test()
}
println("$u1")
mame 是无法修改的 因为是val