Android kotlin在实战过程问题总结与开发技巧详解

news2024/11/25 2:24:20

1、介绍

        目前Android开发中,分为两派,Java派和Kotlin派,Java是宇宙开发第一语言,地位一直处于领先位置,但是Java会出现一个空指针的情况,所以kotlin的出现,填补了java的一些缺陷,但是也导致一些人习惯了Java语言,在转kotlin的时候,会经常写成java字段。所以我接下来把kotlin在开发过程常见的关键字和一些用法进行介绍,以及一些错误如何处理,看完基本就能正常上手写kotlin项目。

二、常见使用介绍

似曾相识,就是不会。看完恍然大悟。接下来对高频用法和高频关键字进行介绍

1、var 和val,变量声明

1.1 var 是声明为常量,有读与写权限

        var a:Int=10,

        a=20

1.2val 是声明为常量,相当于final,只能读,没有写权限

val b:Int=10

b=20//这行报错

2、对象的创建

var  chidl:Child

如果直接使用报错

var child=Child()直接new一个新的

3、!!和?区别

!!:如果有空指针会被抛出

?:如果当前对象是空指针,将不会执行后面的操作

如下:

 4、"?"的使用

1.var child:Child?=null

这种表示child为null,


如果你直接写成

var child:Child=null

直接报错

 变成的初始化可以这样

var child:Child= Child()
声明成Child的类型,然后初始化

var child1=Child()

直接初始化成child类型

5、可变数组与不可变数组

在kotlin中,数组分为可变和不可变,可变是可以添加值,不可变就是声明后,就不能再add进去。

 可变素组正常都是mutable开头,常见的有如下:

mutableListOf<>()
mutableMapOf<>()
mutableSetOf<>()

在这边,var和val对对象的修饰不是那么明显,即使你申请为val,可变数组还是可以操作的

6、静态类,关键字:object

我们在Java中会使用静态变量通过static来修饰,kotlin在修饰静态变量直接用object修饰类

object StaticMian {

    fun log() {
        MyLog.log("object is static")
    }

}

使用:StaticMian.log()

如果设置类为静态,里面的方法都不需要再进行修饰,和其他类一样使用

静态类的内部类也可以

object DemoOut {

    object DemoIn{

        fun log(){
            MyLog.log("DemoIn")
        }
    }

    fun log(){
        MyLog.log("DemoOut")
    }


}

7、单利模式:

1.Synchronized


单利在Java作为工具类用的好多地方,kotlin的单利模式是通过在get方法中

object StaticMian {
    private var mian: StaticMian? = null
    @get:Synchronized
    val instance: StaticMian?
        get() {
            synchronized(StaticMian::class.java) {
                if (mian == null) {
                    mian = StaticMian
                }
            }
            return mian
        }


    fun log() {
        MyLog.log("object is static")
    }

}

关于在对象下方的get(),可以参考我的另一篇:Kotlin语法详解与实践教程,区分JAVA以及如何闭坑

修饰该对象是同步,只需要修饰该方法的get,指向Synchronized,和申明变量差不多

@+get:+关键字

var +变量名:+类型


第二种单利写法:

class TestSing {

    companion object {
        private var test: TestSing? = null;


        fun getInstance(): TestSing {
            synchronized(TestSing::class.java) {
                if (test == null)
                    test = TestSing()
            }

            return test!!
        }

    }
}

8、常量const关键字用法

const是修饰val的,val是只有读权限,如果用const来修饰,那就变成了一个常量,const 只允许在top-level级别和object,也就是是说当前类必须是通过object修饰的,否则不能使用

而且const修饰的变量必须要被初始化。

1.正确写法

const val a:Int = 0;

2.错误写法
const val a:Int;

3.const的出现:只能出现在静态类或者静态模块中,否则报错

9、接口使用使用

1.接口创建

interface MyInterface {

    public fun change(msg: String): String;

    public fun add(a: Int, b: Int): Int {
        return a + b
    }

}

也是通过关键字interface 来修饰

写法没有啥区别,唯独有争议的地方就是方法可以有方法体,有方法体只能当方法使用

2.继承接口

类和的继承和接口都是通过":"实现的

如果接口中定义的方法有方法体,在接口继承将不会需要重写,已被定义为方法了,可以直接调用,也可以重写

class MyTestDemo :MyInterface {
    override fun change(msg: String): String {
        return msg+"===change";
    }

    override fun add(a: Int, b: Int): Int {

        return super.add(a, b)

    }

}

fun main() {

    var  demo=MyTestDemo()
    MyLog.log(demo.change("123"))
    MyLog.log(demo.add(2,3))

}

3.参数为接口,如果View的onclick实践

1.直接和java写法一致:

    demo.setInterface(object : MyInterface {
        override fun change(msg: String) {

        }
    })


2.lambda表达式:

无参:直接{}在空号内写回调

demo.setOnclick {

}

有参:直接将参数名按顺序列出来,指向方法体->

demo.addOnDestinationChangedListener {controller,destination,arguments->
    
    toast("${destination.displayName}")
    
}

10、多构造器以及继承类的构造器传参

非继承类构造器

class MyConstrDemo() {


    constructor(name: String) : this() {

    }

    constructor(name: String,age:Int) : this() {

    }

}

fun main() {
   var  demo1=MyConstrDemo()

    var  demo2=MyConstrDemo("")

    var  demo3=MyConstrDemo("",12)
}

默认构造器通过类名后面追加。如果多重载,通过关键字来完成constructor(),返回值就是默认构造器类型

类名后带参数的构造器又叫默认构造器,如果在类的内部通过constructor定义构造器,返回值类型一定是this(),this就是类名后面接的默认构造器。

继承类构造器:

open class Parent(name: String = "parent") {
}

class MyConstrDemo(name:String):Parent(name) {

    constructor() : this("") {

    }

    constructor(name: String,age:Int) : this() {

    }

}

和单类一样,只是要传参给父类。其他写法和非继承一样

11、lateinit 关键字

lateinit 关键是需要对变量进行初始化,切变量属性是private类型,切用来修饰var

在Android开发过程中,比较常见的就是lateinit var来定义view

lateinit var text=findViewById(id)as TextView

 这种修饰是申请变量可以为null,一般简单类型不适合

1.错误,这种直接报错

lateinit var age:Int 

同样,这样修饰过的变量不能去修改set()和get()方法

 可以为null和不可以的示例:

lateinit var mp1:HashMap<String,String>
 var mp2:HashMap<String,String>

12、强制转换 as

as在kotlin中作为类型的强制转换,Java中  int a=(int) 100.123f

kotlin: 

对象类型

a=b as Int

常见的view初始化如下:

var text=findViewById(id) asTextView

13、构造器对象使用

我们如果在kotlin中构造器中有对象变量,需要引用构造器变量,无须将构造器变量赋值到类的内部变量,可以直接通过var修饰完直接引用

class DataMapConst(var map:HashMap<String,String>?) 
class DataMapConst(var map:HashMap<String,String>?) {

    lateinit var mp1:HashMap<String,String>
   
    constructor( msg:String):this(null){

    }

    fun log(){
        MyLog.log(map!!?.toString())

    }

    inner class Child{

        fun log(){
            MyLog.log(map!!?.toString())
        }
    }
}


fun main() {
    var map:HashMap<String,String>?=null
    map= HashMap()
    DataMapConst("ssss")
    var demo=DataMapConst(map);
    map.put("one","1")
    map.put("two","1")
    map.put("three","1")
    demo.Child().log()


}

14、对象默认set()和get()使用

kotlin的变量都提供了set()和get() 方法,但是lateinit修饰过的变量,无法修改set()和get()方法

 

class People {
    var name: String=""
        set(value) {
            field=value+"=123"
        }
        get() {
            return field + "==modify"
        }
    var age: Int = 0

}

fun main() {

    var people=People()
    people.name="zhangshan"
    MyLog.log(people.name)
}

set(value):这个value是 val,只能读,不可修改

get():需要一个return

field:是变量自身的值,如果了解Java反射的,应该明白,field是class获取到的变量

想了解Java反射,可以参考我的另一篇文字  Android Java反射与Proxy动态代理详解与使用基础篇(一)

这样我们就能随意修改field值,以及返回值。这类似Java hook技术。同时,也破坏了数据原有的安全性,谨慎使用。

15、companion关键字

companion只能修饰object,且该object必须是内部类静态模块。

常见的用法如下

class TestSing {

    companion object {
        //类的静态模块
      
       
      
    }
}

所以object有两种用法

1.修饰类为静态内

2.和companion搭档,companion object修饰非静态类的静态模块

如果类为静态类,就不能这样使用,因为静态类,里面的方法和熟悉都可以直接使用,再修饰成静态模块就会报错。

所以 :只能出现在非静态类中

companion object{

}

这种用法最为非静态类中的静态模块

16、open关键字

 kotlin中的类和方法都是无法直接被继承或者重写,类似Java中被修饰了,但是可以通过open来修饰就变成了开放型类和方法。

open class Base {

   open fun log(){

    }
}

class TestBase :Base(){

    override fun log() {
        super.log()

    }

}

17、Any,Unit,Nothing,Void

1.Any:相当于java中的object使用

Unit:是一个object类,类似java中的void

fun aa(): Unit {
    
}

Nothing:是一个有私有构造器的类,常作为定义异常抛出类使用

fun  bb():Nothing=throw java.lang.Exception("error");

也经常在继承提示作为TD使用

@kotlin.internal.InlineOnly
public inline fun TODO(reason: String): Nothing = throw NotImplementedError("An operation is not implemented: $reason")

Void:作为空来使用,常作为返回一个空类型。

fun cc(): Void? {
    var map:Any;
    return null;
}

上面四种类型,使用最多的是Any和Nothing,关于unit和void可以作为了解,不做参考

18、inner:内部类修饰

如果类中嵌套类,我们常叫成为内部类,在Java中直接写,但是kotlin中,如果需要使用内部类,需要用一个inner来修饰

class People {


    inner class MySon {
        var name: String = ""

        fun log() {
            MyLog.log(name)
        }
    }
}

fun main() {


    var sun = People().MySon()
    sun.name="123"
    sun.log()


}

   注意: 在使用过程中,内部类的使用如下

 正确:

var sun = People().MySon()

错误:

var sun = People.MySon()

19、when

when的使用和Java中的Switch一个逻辑,但是格式右边

val a = 10
when (a) {
    0, 10 -> {
        MyLog.log("0-10")
    }
    20 -> {
        MyLog.log("==20")
    }
    30 -> {
        MyLog.log("==30")
    }
    else -> {
        MyLog.log("not value")
    }
}

when( 表达式)

0,10:a>=0&&a<=10

相当于

case 0:

case10:

break

else相当于default

注意:任何模块结束自带break。

20.、is的使用

在kotlin中,类型的判断是 is,和java instanceof一样

var b=10
if (b is Int)
{
    MyLog.log("Int")
}

21、in在for中的使用

 in在for循环中使用比较多,和迭代去关联。但是,关于for的使用如下

1.for (i in 1 until 100 )

  相当于 [1,100)的区间类,步长是1,相当于i ++

2.for (i in 1 until 100 step 2)

指定步长是多少,step跟上步长

 3.for (i in 0..100)

区间[0,100],步长为1

step:是步长,在for循环中是特有的

结果如下:

22、参数泛型

在kotlin中,对参数类型的泛型要求蛮高的,即使,实参和形参的泛型不一致都会提示错误

所以在使用过程中,定义参数泛型后,实参和形参一定要匹配,否则很容易报错,这种错误和java中不一样,java只要容器一样,参数是默认类型的。

 有时候在设置泛型一定要格外小心,避免新手排查问题无法定位到

解决:

如果你是在不想预先定义好,可以如下:

class FanxingDemo(var map:HashMap <*,*>) {

    fun log(){
        map.keys;
    }
}


fun main() {
    var map=HashMap<Any,Any>()

    var demo=FanxingDemo(map)

}

形参指定*

var map:HashMap <*,*>

 实参:

var map=HashMap<Any,Any>()

或者

var map: HashMap<*, *> = HashMap<Any?, Any?>()

或者先定义,后初始化

var map: HashMap<*, *> 

map= HashMap<Any?, Any?>()

参数put的时候需要注意:

key和value要转换成Nothing,否则报错

map.put("one" as Nothing, 1 as Nothing);
map.put("two" as Nothing, 1 as Nothing);

但是这种在编写没有问题,但是在执行的时候会报错

Nothing是Void类型,所以String不能转Void

所以在实战中,实参的泛型不要通过*来修饰,Demo如下

正确:

var map: HashMap< Any,  Any> = HashMap<Any, Any>()
var key = Any()
map.put("123",123)

23、Bean的封装

在kotlin中,类有两种写法

1.正常有类体的

class MyBean() {
    var name: String = ""
    var age: Int = 0
    var map: HashMap<*, *> = HashMap<Any?, Any?>()
}

2.无类体,只通过默认构造器完成

class MyBean(var name: String = "", var age: Int, var map: HashMap<*, *> = HashMap<Any?, Any?>())

3.空类

class  MyBean()

由于kotlin所有的变量都提供了set()和 get()方法,所以如果做bean来使用,无法处理结果,直接用第二种即可。

第二种写法也常和Gson、Json配合解析使用

正常使用如下:


    var bean = MyBean("zhangshan", 100, map)

    MyLog.log(bean.name + "," + bean.age + "," + bean.map.toString())

24、String的快捷内置API的使用

val value="123"
value.toFloat()
value.toInt()
value.toDouble()
value.toLong()
value.toCharArray()
value.toList()
value.toBigDecimal()
value.toByte()
value.toShort()
value.toBoolean()

kotlin的String类型,已提供了好多快捷的转换。我们可以直接使用,这样不用我们自己去换了

25、异常的抛出方法

kotlin中有两个异常抛出的方法

1.在方法体中抛出

try {

    Thread.sleep(122)
} catch (e: Exception) {

}

2.在方法外面抛:通过@Throws跟上异常类

@kotlin.jvm.Throws(Exception::class)
fun testException() {
    Thread.sleep(12)
}

26、Synchronized同步锁使用

kotlin的同步锁用两种用法

第一种:变量默认方法加锁

我们都知道,kotlin的变量默认有set和get方法。所以同步锁在锁变量的时候,可以单独对变量的set和get进行加锁。

Synchronized

class TestSyn {
    @set:Synchronized
    @get:Synchronized
    var instance = TestSyn()
}

加锁格式:@+(set、get)+ :+Synchronized

field域不能直接对变量加锁,因为变量不支持,锁只支持方法

错误写法:

@Synchronized
var instance = TestSyn()

 

第二种:自定义方法加锁

自定义方法加锁直接在方法名上方插入,如下:

@Synchronized
fun test(){

}

格式 :@Synchronized

日常我们了解这两种方式已够开始使用

27、Volatile:原子一致性

这些都是属于jvm的,直接@引入即可

@Volatile
var a: Int = 10;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/50815.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

擎创技术流 | ClickHouse实用工具—ckman教程(5)

哈喽~友友们&#xff0c;又到了一期一会的技术分享时刻了&#xff0c;本期继续以视频形式与大家分享&#xff0c;话不多说&#xff0c;我们直接上干货&#xff0c;建议收藏分享马住 戳↓↓↓链接&#xff0c;一键回看前期内容&#xff1a; 擎创技术流 | ClickHouse实用工具—c…

独立IP和共享IP的区别以及各自的优势有哪些

如果您在网上做生意&#xff0c;您可能对什么是IP地址有一个大概的了解。然而&#xff0c;您可能不知道的是&#xff0c;IP 地址分为两种类型。下面将介绍在选择独立服务器时最常遇到的两种IP的区别和联系&#xff1a; 简而言之&#xff0c;独立IP地址是标识您的网站的唯一数字…

基于云原生技术的融合通信是如何实现的?

孵化于云端&#xff0c;云通信成为时代的主流。01 云通信的「前世今生」 通信与每个人息息相关。 生态合作和渠道的规模上量&#xff0c;给传统通信模式带来巨大的挑战&#xff0c;由此衍生出云通信。 云通信&#xff0c;即基于云计算平台&#xff0c;将传统通信能力进行云化&a…

常用测试用例模板大全

一些常用模块的测试用例 1、登录  2、添加  3、查询  4、删除 1、登录 ①用户名和密码都符合要求&#xff08;格式上的要求&#xff09; ②用户名和密码都不符合要求&#xff08;格式上的要求&#xff09; ③用户名符合要求&#xff0c;密码不符合要求&#xff08;格…

LeetCode HOT 100 —— 75 .颜色分类

题目 给定一个包含红色、白色和蓝色、共 n 个元素的数组 nums &#xff0c;原地对它们进行排序&#xff0c;使得相同颜色的元素相邻&#xff0c;并按照红色、白色、蓝色顺序排列。 我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。 必须在不使用库内置的 sort 函数的情况下…

【ESP32-Face】ESP32人脸检测MTMN 模型以及face_detect()函数详解

ESP32-Face 人脸检测MTMN模型以及 face_detect 函数详解1. MTMN 模型2. 模型网络3. API 函数接口介绍4. 模式选择5. 参数配置1. MTMN 模型 MTMN 是一个人脸检测的轻量级模型&#xff0c;专门应用于嵌入式设备。它是由 MTCCN 和 MobileNets 结合而成。 2. 模型网络 MTMN由三个…

搬砖日记:关于sync用不了的问题

自己封装了个输入框的组件&#xff0c;想要实现的输入框的值的修改可以实时修改到父组件的值 印象中看到过人家用.sync修饰符去实现这个功能&#xff0c;大抵是 //父组件 <searchInput :value.sync"value"></searchInput> //子组件 <input v-model&qu…

(4E)-TCO-PEG4-DBCO,1801863-88-6,反式环辛烯-四聚乙二醇-二苯并环辛炔

(4E)-TCO-PEG4-DBCO物理数据&#xff1a; CAS&#xff1a;1801863-88-6 | 中文名&#xff1a;(4E)-反式环辛烯-四聚乙二醇-二苯并环辛炔 | 英文名&#xff1a;(4E)-TCO-PEG4-DBCO 结构式&#xff08;Structural&#xff09;&#xff1a; (4E)-TCO-PEG4-DBCO物理数据补充&…

vue3 组件篇 tag

文章目录组件介绍标准用法自定义背景色和字体颜色点击和关闭的回调组件代码参数说明关于dxui组件库组件介绍 tag组件&#xff0c;是前端开发常用组件之一&#xff0c;无论是移动端&#xff0c;还是pc端&#xff0c;我们都能经常看到。tag组件的交互也比较简单&#xff0c;需要…

用了4年,终于发现了这款国产报表工具的魅力

第一次接触FineReport应该是在2018年&#xff0c;当时刚从美团出来进了现在的国企IT部门。一晃用了快4年了。4年前&#xff0c;我觉得FineReport是一款万能的企业级系统&#xff0c;4年后&#xff0c;我的这个想法依旧没有改变。先别开喷&#xff0c;看完我为什么这么想再说。 …

计算化学:如何在云平台上计算声子谱

内容摘自北鲲云五月份直播内容【声子谱的计算、后处理与分析实例】 另有文章【不同压强下ZnO的声子谱计算及其收敛性测试】可在发布的内容中查阅。 所有计算皆在北鲲云超算平台上完成。 计算声子谱所需软件&#xff1a; 1 VASP(Vienna Ab-initio Simulation Package) 结构计…

护理床控制板开发,帮您解决卧床护理难题

多功能护理床是一款针对术后康复、老年人、下肢瘫痪等行动不便人群设计的一款高科技产品&#xff0c;帮助他们解决日常生活问题&#xff0c;减轻护理压力。相对于国外成熟的护理床产品&#xff0c;中国的护理床市场尚处于初期发展阶段。护理床控制板通过按键控制&#xff0c;完…

BOSS直聘新财报:用户、技术两手抓

与传统招聘模式相比&#xff0c;网络招聘具有信息传播速度快、时效性强、沟通效率高等特点&#xff0c;再加上受疫情这一外界因素影响&#xff0c;线上面试频率增高&#xff0c;广大求职者们对网络招聘的接受度开始日益提升。随着线上招聘市场规模的逐渐扩大&#xff0c;行业内…

一文学会Canal怎么用

文章目录一.概念1.什么是Canal2.Canal的基本原理二.Mysql配置1. 安装2. 开启mysql的binlog3.mysql创建cannl用户并授权三.安装配置ES&#xff0c;kibana四.安装canal-server五.安装canal-admin六.安装canal-adapter七.通过canal和RabbitMQ将mysql数据同步ES一.概念 1.什么是Ca…

java EE初阶 — synchronized 关键字 - 监视器锁 monitor lock

文章目录1.synchronized 的特性1.1 互斥1.2 可重入2.synchronized 使用示例3.Java 标准库中的线程安全类1.synchronized 的特性 1.1 互斥 synchronized 会起到互斥效果, 某个线程执行到某个对象的 synchronized 中时, 其他线程如果也执行到同一个对象 synchronized 就会阻塞等…

大数据培训之Hadoop序列化

序列化概述 1.1什么是序列化 序列化就是把内存中的对象&#xff0c;转换成字节序列(或其他数据传输协议)以便 于存储到磁盘(持久化)和网络传输。 反序列化就是将收到字节序列(或其他数据传输协议)或者是磁盘的持久化 数据,转换成内存中的对象。 1.2为什么要序列化 一般来说&am…

【leetcode】2259. 移除指定数字得到的最大结果(js实现)

1. 题目 2259. 移除指定数字得到的最大结果 2. 思路 根据题意进行模拟&#xff0c;每次找到与digit相同的元素就将其移除&#xff0c;将剩余的字符串与存储最大值的字符串进行比较&#xff0c;一直保持max中保存的是最大值&#xff0c;最终将max返回。 3. 代码 /*** para…

用强化学习玩《超级马里奥》

Pytorch的一个强化的学习教程&#xff08; Train a Mario-playing RL Agent&#xff09;使用超级玛丽游戏来学习双Q网络(强化学习的一种类型)&#xff0c;官网的文章只有代码&#xff0c; 所以本文将配合官网网站的教程详细介绍它是如何工作的&#xff0c;以及如何将它们应用到…

[附源码]Python计算机毕业设计SSM科技类产品众筹系统(程序+LW)

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

[附源码]计算机毕业设计JAVA乡村振兴惠农推介系统

[附源码]计算机毕业设计JAVA乡村振兴惠农推介系统 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM myb…