变量延迟加载
// 某些成员变量在声明时无法初始化,且不想使用可空类型(也就是带?的类型)。可使用 lateinit 和 by lazy
// 不知道具体值,后面再赋值使用;所以必须var
lateinit var name: String
// 知道具体值,用到的时候再加载,表示不可变的值,所以必须val
// {}中的最后一行代码返回初始化的结果,加载时机为第一次调用常量的时候,且只会加载一次
private val book by lazy {
LogUtil.i("这行代码不会影响book赋值")
"Android"
}
访问权限修饰符
public: 公开,可见性最大,哪里可以引用 Kotlin 的类默认是 public 的
private: 私有,可见性最小,根据声明位置不同可分为类中可见和文件中可见
protected: 保护,相当于private+ , 子类可见
internal: 内部,仅对module内可见
构造方法,init代码块
/**
* 构造函数单独用了一个 constructor 关键字来和其他的 fun 做区分,分主构造和次构造
* 如果类中有主构造器,所有次构造器都需要通过this关键字调用主构造器
*
* 从主构造器的特性出发,一旦在类中声明了主构造器,就包含两点:
* 必须性:创建类的对象时,不管使用哪个构造器,都需要主构造器的参与
* 第一性:在类的初始化过程中,首先执行的就是主构造器
*/
class User constructor(var name: String) {
// init 代码块是先于次构造器执行的。
init {
// 如果把主构造器看成身体的头部,那么 init 代码块就是颈部,次构造器就相当于身体其余部分
}
// 直接调用主构造器
constructor(name: String, age: Int) : this(name)
// 通过上一个次构造函数,间接调用主构造器
constructor(name: String, age: Int, id: Int) : this(name, age) {}
}
constructor 关键字省略,私有,参数
// 主构造器中 constructor 关键字如果没有被 可见性修饰符 或 注释 标注可以省略
class User(var name: String) {
constructor(name: String, age: Int) : this(name)
}
// 主构造器被修饰为私有的,外部就无法调用该构造器
class User private constructor(var name: String) {
}
// 主构造函数里面声明属性,前面加 var / val 构造参数同时成为成员变量
class User(var name: String) {
}
// ↑↓ 上下等价
class User(name: String) {
var name: String = name
}
静态方法
一共三种实现方式:①object ②伴生对象 ③顶层函数
/**
* 当用 object 声明一个类时,表明这个类是一个单例类,可继承其他类
* object 可以定义在全局也可以在类的内部使用
* object声明不能用在方法和inner内部类中,但是能嵌套在其他object声明和嵌套类中
* object 定义后即刻实例化,因此 object 不能有定义构造函数
*/
object SystemUtil{
}
/**
* 和 object 不同, companion object 的定义完全属于类的本身,
* 因此 companion object 不能脱离类而定义在全局之中。
* 类似 Java 里的 static 变量
*/
class ScreenUtil {
// companion object 修饰为伴生对象,伴生对象在类中只能存在一个
companion object {
}
}
真实项目中推荐的写法是使用伴生对象和 object
关键字结合的方式,示例如下:
class UmengEventUtil {
companion object {
@JvmStatic
fun getInstance(): UmengEventUtil {
return Holder.instance
}
}
private object Holder {
val instance = UmengEventUtil()
}
fun onRegister(mContext: Context) {
MobclickAgent.onEvent(mContext, "__cust_event_1")
}
}
顶层声明 top - level property / function
又称顶层函数,直接在文件中定义函数和属性,这种顶层函数不要声明在module内最顶层的包中,至少要在一个包中
/*
顶层声明属于 package,不在 class/object 内
属性和函数,不属于任何 class,而是直接属于 package
它和静态变量、静态函数一样是全局的,用起来更方便:在其它地方用的时候,类名都不用写
*/
fun stringToDouble(money: String): Double {
return money.toDouble()
}
get,set 方法
// 默认kotlin已自动生产set,get方法,可省略
class User() {
var name: String? = null
set(value) {
field = value
}
get() = field
}
// 上下等价 ↑↓
class User{
var name: String? = null
}
// 如只想让外部使用,不想外部set,可在set前面添加private将set方法私有化
class User {
var name: String
private set
init {
name = "设置name值,外部只能调用get方法"
}
}
数据类
相比JavaBean手动生成各种方法,kotlin data class要简单很多
/**
* var user = User("zs",18,"10001")
* 自动生成
* toString() LogUtil.e("user.toString = $user")
* copy() var user2 = user.copy(id = 2)
* equals() user.equals(user2) 输出 true
* hashCode() user.hashCode 输出内存地址
* componentN() 解构声明 val (name, age, code) = User("zs", 0, "1001")
*/
data class User(
var name: String,
var age: Int,
var code: String
)
扩展函数
// 原本使用
fun dp2px(dp: Float): Float {
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, Resources.getSystem().displayMetrics)
}
dp2px(3.4f)
// 扩展函数
fun Float.dp2px(): Float {
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, this, Resources.getSystem().displayMetrics)
}
3.2f.dp2px()
持续更新中...