IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> 学习笔记-Kotlin(5) -> 正文阅读

[移动开发]学习笔记-Kotlin(5)

目录

1.Filed

2.初始化?

2.1.主构造函数

?2.2.在主构造函数里定义属性

2.3.次构造函数

2.4.延迟初始化

2.5. 惰性初始化

2.6初始化陷阱?

3.继承

3.1.关键字open

3.2.子类转父类用关键字as

3.3.关键字:object

? ? ? ? 3.3.1、单例?

? ? ? ? 2、匿名内部类?

? ? ? ? 3、伴生对象

1.Filed

????????针对你定义的每一个属性,Kotlin都会产生一个filed、getter和setter。你不能直接定义field,kotlin封装号了field,保护它的数据,只暴露了getter和setter使用。只有可变属性才会有setter方法。但在需要控制如何读写属性数据时,你也可以自定义它们。需要注意的是,在java中没有给field定义访问模式时,默认的是public。而kotlin,没有定义访问模式时,默认的是private。

    class Player {
        var name = "abc"
    }

    fun main() {
        val player = Player()
        println(player.name)
    }

????????这并不能看得出咱们上边的说法,我们来看看字节码中是怎样给的。

   public final void main() {
      FiledInstanceExtendsTest.Player player = new FiledInstanceExtendsTest.Player();
      boolean var2 = false;
      System.out.println(player);
   }

   @Metadata(
      mv = {1, 5, 1},
      k = 1,
      d1 = {"\u0000\u0014\n\u0002........"},
      d2 = {"Lcom/example/kotlinstudy/FiledInstanceExtendsTest$Player;", "", "()V", "name", "", "getName", "()Ljava/lang/String;", "setName", "(Ljava/lang/String;)V", "kotlinStudy.app"}
   )
   public static final class Player {
      @NotNull
      private String name = "abc";

      @NotNull
      public final String getName() {
         return this.name;
      }

      public final void setName(@NotNull String var1) {
         Intrinsics.checkNotNullParameter(var1, "<set-?>");
         this.name = var1;
      }
   }

? ? ? ? 这样就显而易见了,name的访问模式是private,我们声明的时候没有用?号,是NotNull。以及提供了我们getter、setter方法。但如果我们自己给name声明private时,就不能用了。

    class Player {
        private var name = "abc"
    }

    fun main() {
        val player = Player()
        println(player)
    }

这里我们声明private,我们看看字节码。

   public final void main() {
      FiledInstanceExtendsTest.Player player = new FiledInstanceExtendsTest.Player();
      boolean var2 = false;
      System.out.println(player);
   }

   @Metadata(
      mv = {1, 5, 1},
      k = 1,
      d1 = {"\u0000\u0012\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\b\u0002\n\u0002\u0010\u000e\n\u0000\u0018\u00002\u00020\u0001B\u0005¢\u0006\u0002\u0010\u0002R\u000e\u0010\u0003\u001a\u00020\u0004X\u0082\u000e¢\u0006\u0002\n\u0000¨\u0006\u0005"},
      d2 = {"Lcom/example/kotlinstudy/FiledInstanceExtendsTest$Player;", "", "()V", "name", "", "kotlinStudy.app"}
   )
   public static final class Player {
      private String name = "abc";
   }

按照我们刚开始的概念,kotlin帮我们设置好了filed、getter和setter。再根据默认为public(其实你给访问模式为public是一样的),在字节码反编译成java中,却是private。我们就知道了,平常使用的时候不用给访问模式,直接定义即可。如果你给的访问权限是private,就无法在外部直接引用了,像player.name这样使用,只能自己在类里边写一个函数,自行返回了。这样使用方式就跟java类似了,那这样就失去了咱们的优势。代码如下:

    class Player {
        private var name = "abc"

        fun getName():String {
            return name;
        }

        fun setName(name:String) {
            this.name = name;
        }
    }

    fun main() {
        val player = Player()
        player.setName("bbc")
        println(player.getName())
    }

运行结果:bbc?

? ? ? ? 我们也可以自己实现getter和setter方法。

    class Player {
        var name = "abc"
            get() = field.capitalize()
        var age = 10
            get() = field.absoluteValue;
    }

    fun main() {
        val player = Player()
        player.name = "bbc"
        player.age = -50
        println("${player.name} + ${player.age}")
    }

运行结果:Bbc + 50

? ? ? ? 上边例子只写了get方法,set方法也是一样的,就没有写了。?

2.初始化?

2.1.主构造函数

? ? ? ? 我们在Player1类中定义一个主构造函数,使用临时变量作为Player的各个属性提供初始值,Kotlin中,在()括号中我们可以定义参数,这就是我们的主构造函数。临时变量,通常都以下划线开头来命名,为便于识别。临时变量赋值完就会被回收了!

    class Player1(
        _name:String,
        _age:Int,
        _isNormal:Boolean
    ) {
        var name = _name;
        var age = _age;
        var isNormal = _isNormal
    }

    fun instanceTest() {
        var player1 = Player1("hua", 24, true)
        println("name:${player1.name},age:${player1.age},isNormal:${player1.isNormal}")
    }

?运行结果:name:hua,age:24,isNormal:true

?2.2.在主构造函数里定义属性

? ? ? ? 咱们还可以更简洁一点,直接在主构造函数中去定义属性。

    class Player1(
        _name:String,
        var age :Int,
        var isNormal:Boolean
    ) {
        var name = _name;
    }

    fun instanceTest() {
        var player1 = Player1("hua", 24, true)
        println("name:${player1.name},age:${player1.age},isNormal:${player1.isNormal}")
    }

运行结果和之前是一样的,这样是不是更方便了,又省了几行代码。

2.3.次构造函数

? ? ? ? 有主就有次,不然没有次也实在是满足不了我们各种各样的需求。

    class Player1(
        _name:String,
        var age :Int,
        var isNormal:Boolean
    ) {
        var name = _name;

        constructor(name:String) : this(name, 100, false)

    }

    fun instanceTest() {
        var player1 = Player1("hua", 24, true)
        var player2 = Player1("zhang")
        println("name:${player1.name},age:${player1.age},isNormal:${player1.isNormal}")
        println("name:${player2.name},age:${player2.age},isNormal:${player2.isNormal}")
    }

运行结果:name:hua,age:24,isNormal:true
????????????????name:zhang,age:100,isNormal:false

2.4.延迟初始化

? ? ? ? 延迟初始化可以在声明时不直接初始化,放在后边使用时初始化。关键字:lateinit

    //延迟初始化
    class Player9(var name: String) {
        lateinit var age:Any
        fun findAge() {
            age = 5
        }

        fun finish() {
            if (::age.isInitialized) println(age)
        }
    }

    fun lateInitTest() {
        val player = Player9("hua")
        player.findAge()
        player.finish()
    }

运行结果: 5

? ? ? ? 我们lateinit定义了age,然后在findAge函数中初始化了它。最后在finish中判断age是否初始化,初始化了才输出它。如果我们注释player.findAge()那么运行结果就什么都没有输出了。?

2.5. 惰性初始化

? ? ? ? 延迟初始化不是唯一的推后初始化方式,你也可以暂时不初始化某个变量,直到首次使用它,再初始化它,这叫惰性初始化。使用方式:val name by lazy{.....}

    //惰性初始化
    class Player10(var name: String) {
        val age by lazy { 10 }
    }

    fun lazyTest() {
        val player = Player10("hua")
        println("${player.name} + ${player.age}")
    }

?初始化:hua + 10

2.6初始化陷阱?

? ? ? ? 一:声明变量应该放在初始化块(init{....})之前。

? ? ? ? 二:一个属性放在初始化块里进行初始化,但其他函数中又直接使用该属性,会报空指针。

? ? ? ? 三:编译器看到所有属性都初始化了,所以代码编译没问题,但运行结果为null

还有初始化顺序,这个看字节码就能明白理解了。哈哈哈,懒得写上来了

3.继承

3.1.关键字open

? ? ? ? 父类要有open关键字,才可以被继承。
? ? ? ? 父类函数要有open关键字,才可以被子类重载。

? ? ? ? 从字节码上看,不写open关键字,类和函数都被final定义了,所以无法被继承和重载。

    //继承
    open class Product(val productName:String) {
        open fun printlnProductName() = "println $productName"

        fun notOpenFun() {
            println(productName)
        }
    }

    class Car : Product("Car") {
        override fun printlnProductName(): String {
            return "println $productName xxx"
        }
    }
   @Metadata(
      mv = {1, 5, 1},
      k = 1,
      d1 = {"..."},
      d2 = {"....."}
   )
   public static class Product {
      @NotNull
      private final String productName;

      @NotNull
      public String printlnProductName() {
         return "println " + this.productName;
      }

      public final void notOpenFun() {
         String var1 = this.productName;
         boolean var2 = false;
         System.out.println(var1);
      }
      .....
   }

   @Metadata(
      mv = {1, 5, 1},
      k = 1,
      d1 = {"....."},
      d2 = {.....}
   )
   public static final class Car extends FiledInstanceExtendsTest.Product {
      @NotNull
      public String printlnProductName() {
         return "println " + this.getProductName() + " xxx";
      }
      .....
   }

????????看到转换成java的大家应该就很明了了,car被final修饰,product被open关键字修饰,所以没有被final修饰。函数也是这样如此。

3.2.子类转父类用关键字as

car as Product

????????kotlin有类型推断,如果一个函数需要父类,你直接传子类就行,也可以不用转成父类。java的话就要(Product)car转换成父类传进去了。

3.3.关键字:object

? ? ? ? 关键字object用处挺多。1、用于单例。2、匿名内部类。3、伴生对象

? ? ? ? 3.3.1、单例?

    //单例
    object SingleUtil {
        init {
            println("loading instance")
        }

        fun getPiuPiu() {
            println("piupiu")
        }

    }

    fun singleTest() {
        SingleUtil.getPiuPiu()
        SingleUtil.getPiuPiu()
    }

运行结果:loading instance
????????????????piupiu
????????????????piupiu

? ? ? ? 2、匿名内部类?

    //匿名内部类
    open class Player11(var name:String) {
        open fun meilidepaomo() {
            println("++++++$name")
        }
    }
    
    fun noNameTest() {
        var lala = object : Player11("huahua") {
            override fun meilidepaomo() {
                println("------$name")
            }
        }
        lala.meilidepaomo()
    }

运行结果:------huahua

????????匿名内部类用的比较多,经常自定义Listner,或者回调。只用一次就丢了,

? ? ? ? 3、伴生对象

? ? ? ? 如果你想将某个对象的初始化和一个类的实例捆绑在一起,就可以考虑伴生对象,使用companion修饰符,一个类里只能有一个伴生对象

    //伴生对象
    class companionObject() {
        companion object {
            private final const val URL = "www.baidu.com"
            
            fun openUrl() {
                println("正在打开URL:$URL")
            }
        }
    }

伴生对象companion object 只初始化一次,用的时候才会加载内部资源。?

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-05-01 15:53:47  更:2022-05-01 15:54:49 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 23:44:48-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码