Kotlin学习笔记(三)—面向对象(2)
传送门🚪:
Kotlin学习笔记(三)—面向对象(1)
Kotlin学习笔记(三)—面向对象(2)
Kotlin学习笔记(三)—面向对象(3)
7.类及其成员的可见性
我们直接用一张表格和Java语言类比:
Java | Kotlin |
---|---|
private | private |
protected | protected |
- | default(包内可见) |
internal(模块内可见) | - |
public | public |
8.object
在Kotlin中,object代表只有一个实例的类,即通常所说的单例。用object关键字定义的类可以继承父类,也可以实现接口,但不能自定义构造函数,通过Kotlin字节码反编译其本质上就是单例模式(饿汉式)
kotlin代码如下:
object home{
}
通过反编译后的.java文件如下:
public static final class home {
@NotNull
public static final object.home INSTANCE;
private home() {
}
static {
object.home var0 = new object.home();
INSTANCE = var0;
}
}
9.伴生对象和静态方法
在java中,有一些工具类是不需要属性去支撑的,所以它们里面的方法大多数都以静态方法的形式存在。
在Koltin中,无法直接声明静态方法,只能委托伴生对象去实现静态方法。
class Method private constructor(val params:Int){
//伴生对象
companion object{
//静态方法
fun build( params: Int):Method{
return Method(params)
}
}
}
fun main() {
val method = Method.build(1)
}
如果你需要在java代码中调用这个方法,
public class test {
public static void main(String[] args) {
Method build = Method.Companion.build(1);
}
}
写起来比较复杂,如果需要频繁调用的话,可以在对应的方法上加注解 @JvmStatic,这样就可以直接使用类名.方法名的方式去访问这个方法。
同样,静态变量也是类似的
class Method private constructor(val params: Int) {
//伴生对象
companion object {
@JvmStatic //静态方法
fun build(params: Int): Method {
return Method(params)
}
@JvmField //静态变量
val TAG = "Method"
}
}
fun main() {
val method = Method.build(1)
println(Method.TAG)
}
在加了 @JvmField 注解后,在java代码中就可以直接使用了。
public class test {
public static void main(String[] args) {
Method build = Method.build(1);
System.out.println(Method.TAG);
}
}
在kotlin中,更推荐使用包级变量或者包级方法。
10.方法重载与默认参数
10.1 方法重载
方法重载的特征总结起来只有一句话:同名不同参数
也就是说
fun test(int:Int){
}
fun test(str:String){
}
这样的方法就叫做方法重载。方法能够重载的根本原因是他们的方法签名不同,方法签名主要由方法名和参数列表组成。
要注意,如果两个方法的方法名和参数列表相同,但是返回值的类型不相同,那么这两个方法不能重载。
###10.2默认参数
在定义方法时,可以给形参列表赋值,那么在调用方法时,就可以不传这个值,编译器会自动将默认值当做实参。例如:
class Method{
fun test(int: Int = 1) {
println("int: $int")
}
fun test(str0: String, str: String = "qwerdf") {
println("str0: $str0 str: $str")
}
}
fun main() {
val method = Method(1)
method.test(1)
method.test("123")
}
运行结果:
方法重载一般会搭配默认参数进行实现,这一点在我们重载一些构造函数的时候非常常见。
在Java代码中,如果调用Kotlin类中有默认参数的方法,需要使用 @JvmOverloads 注解去注解有默认参数的方法,否则就必须传入参数。
11.扩展方法与扩展属性
11.1 扩展方法
在java代码中,我们经常需要写一些工具类去完成我们较为常用的功能,例如多次打印一个字符串,在java中是这样的:
public static void printTimes(String arg, int times) {
for (int i = 0; i < times; i++) {
System.out.println(arg);
}
}
而在Koltin中,我们可以直接定义一个扩展方法:
fun main() {
val name = "panghu"
name.printTimes(10)
}
fun String.printTimes(times: Int) {
for (i in 0 until times) {
println(this)
}
}
我们甚至可以使用之前运算符重载的方法
fun main() {
val name = "panghu"
name *10
}
operator fun String.times(times: Int) {
for (i in 0 until times) {
println(this)
}
}
代码一下子变得清爽起来了。然后在java中,如果需要使用这个扩展方法,则需要
public static void main(String[] args) {
ExtendKt.times("panghu",10);
}
}
通过类名去调用。在kotlin反编译的java文件中,其实也是这样去实现的。
11.2扩展属性
扩展属性的定义与扩展方法很像,但有一点需要注意的是扩展属性没有backingfiled,不能被初始化。这点和我们在接口中定义属性是一样的。我们看个例子:
fun main() {
println("panghu".no)
println("panghu".zero)
}
val String.no: String
get() = "NO"
var String.zero: Int
set(value) {}
get() = 0
12.属性代理
我们在上边提到过接口代理 使用了by关键字。属性代理也是使用by关键字。
在kotlin中,我们见过:
val name by lazy {
"hello"
}
这里的lazy就是属性代理。而想要实现属性代理,就必须实现getValue方法。也就是说如果通过属性代理的方式声明属性,那个这个属性的get方法就会调用代理的getValue方法
自定义的一个String类型的代理:
class P{
private var value:String?=null
operator fun getValue(thisRef:Any?, property:KProperty<*>):String{
println("getValue $thisRef --->${property.name}")
return value?:""
}
operator fun setValue(thisRef:Any?,property:KProperty<*>, value:String){
println("setValue $thisRef --->${property.name} === $value")
this.value = value
}
}
当我们使用代理属性初始化后,在进行读取或者赋值的时候回自动 调用getValue和setValue方法。
完整的案例:
class Extend {
val name by lazy {
"helloword"
}
val name2 by P()
var name3 by P()
}
class P{
private var value:String?=null
operator fun getValue(thisRef:Any?, property:KProperty<*>):String{
println("getValue $thisRef --->${property.name}")
return value?:""
}
operator fun setValue(thisRef:Any?,property:KProperty<*>, value:String){
println("setValue $thisRef --->${property.name} === $value")
this.value = value
}
}
fun main() {
var extend = Extend()
println(extend.name)
println(extend.name2)
println(extend.name3)
extend.name3 = "23456"
println(extend.name3)
}
运行结果如下:
其中 Extend@5a10411是我们创建的那个一个对象