构造函数
Java 代码块 和Kt的init块的区别
- Java 构造函数代码块无法访问构造函数的参数
- Kt的init块可以返回构造函数参数
属性必须被初始化
class Person(var age: Int, Name: String) {
var name: String
var firstname: String
// 必须可空类型才能赋值null
var firstname2: String?=null
init {
name=Name
// 这里注释掉的话,firstname报错
// firstname = Name
}
}
副构造器的使用
class Person(var age: Int, Name: String) {
// 副必须调用主, 保证主必须被执行
constructor(age:Int):this(age,"unknown")
}
使用注解@JvmOverloads,使得Java可以使用
class Person constructor(var age: Int, Name: String) : Animal() {
// 副必须调用主
@JvmOverloads
constructor(age: Int) : this(age, "unknown")
}
构造函数的工厂函数,提供了对调用形式的便利
@kotlin.internal.InlineOnly
public actual inline fun String(chars: CharArray): String =
java.lang.String(chars) as String
Java VS Kotlin 可见性对比
可见性类型 | Java | Kotlin |
---|---|---|
public | 公开 | 默认 |
internal | x | 模块内可见 |
default | 包内可见 | x |
protected | 包内已经子类可见 | 类以及子类 |
private | 类可见 | 类或者文件 |
模块的概念: 一个Java ,或者aar
internal vs default
- 一般由SDK 或者公共组件开发者用于隐藏模块内部细节实现
- default 可通过外部创建相同包名来访问
- default 会导致不同抽象层次的类聚集到相同包之下
- internal 可方便处理内外隔离,提升模块代码内聚减少接口暴露
- internal 修饰的Kotlin 在java 当中可直接访问
假定一种情景,我制作一个SDK,我使用的类在内部调用,又不想被外部使用. Java之类防止在一个包名下面,并修改为
default
--不分层.Kotlin 可以使用internal
有趣的是:kotlin编译的SDK,使用internal
修饰的类,java的使用者可以直接访问,虽然代码会报错.这是因为,Java没有internal
, 这个时候我们使用注解@JvmName("%abcd")
,使用一个不正确的name
就不能使用了
class CoreApiKotlinA {
@JvmName("%abc")
internal fun a(){
println("Hello A")
}
}
延时初始化lateinit
,不支持基本类型
findViewByID的使用
方法1:
lateinit var view:View
view:View = findViewById(Id)
方法2:
private val View by lazy{
findViewByID<View>(Id)
}
带来 delegate
接口代理--属性代理
接口代理: 对象x 代替当前类A实现接口B的方法
属性代理: 对象X 代替属性a 实现getter/setter方法
interface Api {
fun a();
fun b();
fun c();
}
class ApiImp : Api {
override fun a() {
}
override fun b() {
}
override fun c() {
}
}
// 使用 `by 属性实例`,就能够完成代理
class ApiImpWrapper(val api: Api) : Api by api {
override fun c() {
println("c is called")
api.c()
}
}
属性代理
lazy
class Student(var name: String) {
val firstName by lazy {
"firstName ${name.split(" ")[1]}"
}
}
fun main() {
val stu = Student("li mei")
println(stu.firstName)
stu.name="xiao qiang"
println(stu.firstName)
// 两次打印是一样的,说明lazy 的值只会初始化一次
}
属性代理的案例
// by x, x 是方法,必须返回类, 类实现 getter 和setter
class PropertiesDelegate(
private val path: String, private val defaultValue: String = "",
) {
private lateinit var url: URL
protected val properties: Properties by lazy {
val prop = Properties()
url = try {
javaClass.getResourceAsStream(path)
.use {
prop.load(it)
}
javaClass.getResource(path)
} catch (e: Exception) {
try {
ClassLoader.getSystemClassLoader().getResourceAsStream(path).use {
prop.load(it)
}
ClassLoader.getSystemClassLoader().getResource(path)!!
} catch (e: Exception) {
FileInputStream(path).use {
prop.load(it)
}
URL("file://${File(path).canonicalPath}")
}
}
prop
}
operator fun getValue(config: Config, property: KProperty<*>): String {
return properties.getProperty(property.name, defaultValue)
}
operator fun setValue(config: Config, property: KProperty<*>, value: String) {
properties.setProperty(property.name, value)
File(url.toURI()).outputStream().use {
properties.store(it, "Hello~")
}
}
}
abstract class AbsProperties(path: String) {
protected val prop = PropertiesDelegate(path)
}
class Config : AbsProperties("Config.properties") {
var author by prop
var version by prop
var desc by prop
}
class K {
// by xxxx , xxxx 是函数的调用. 该调用必须返回类, 由类实现 getValue 和setValue的方法
val x: Int by myLaze {
1
}
private fun myLaze(function: () -> Int) = X(function)
}
class X(function: () -> Int) {
operator fun getValue(k: K, property: KProperty<*>): Int {
return 1
}
}
单例
// 饿汉式的单例
object Singleton {
// 其实x和y 已经是静态了
var x: Int = 2
@JvmStatic
var y: Int = 3
@JvmField
var z :Int =4
}
public static void main(String[] args) {
int x = Singleton.INSTANCE.getX();
int y = Singleton.getY();
int z = Singleton.z;
}
注: Kotlin没有静态的关键字
companion object 伴生对象
相当于静态方法
内部类
class Outer {
//内部类: 默认是静态
class Inner1 {
}
// 普通内部类,可以访问Outer
inner class Inner2 {
}
}
fun main() {
// 静态
val inner1 = Outer.Inner1()
// 非静态
val inner2 = Outer().Inner2()
}
内部object
就是单例/静态
匿名内部类/ 面试
fun main() {
fun localFunc() {
println("Hello")
class local : Cloneable, Runnable {
override fun run() {
}
}
// 交叉类型
object : Outer(), Runnable, Cloneable {
override fun run() {
}
}
}
}
本地函数, 函数里面定义函数
数据类 data class
下列方法直接生成
- 主构造器的参数,会变成 componentX
- equals/hashCode/toString/copy
- 数据类 data class 不能
被继承
- 最好是基本类型
- 最好是val
插件
noarg.. dataClass 多一个无参构造方法,可配置init 的执行
allopen