目录
不定期更新,记录自己使用中遇到的常用方法
1.可空类型
var test:String?=null
声明变量时候指定可空声明,非空类型则必须赋初始值
2.延迟初始化声明
lateinit var test:String
声明变量在之后的流程中赋值,不能为空
3.非空断言
var test: String? = null
fun test() {
val length = test!!.length
}
告诉编译器这个值不为空,不需要校验
否则会报可空,不让编译运行
如果执行途中为空,仍然会抛异常
4.可空断言
var test: String? = null
fun test() {
val length = test?.run {
println("strLength= $length")
}
}
当调用的对象为空时,该判定后面的代码都不会执行
fun test(){
val length = test?.length
println("$length")
}
这种会打印null
5.懒加载
val test by lazy {
println("lazy load start")
"1234"
}
fun test() {
println("other things")
test.run {
println("run start")
println("$this")
}
}
by lazy声明的属性只能是val,在具体使用到该属性的时候才会初始化,常和单例配合使用
class Test {
private object INSTANCE {
val instance by lazy {
Test()
}
}
companion object {
@JvmStatic
fun getInstance(): Test {
return INSTANCE.instance
}
}
}
6.匿名内部类
lateinit var view: View
fun test() {
view.setOnClickListener(object :View.OnClickListener{
override fun onClick(v: View?) {
TODO("not implemented")
}
})
}
7.方法上下文
class MyActivity : AppCompatActivity() {
private val toast: String = "Toast"
fun test() {
GlobalScope.launch {
Toast.makeText(this@MyActivity, this@MyActivity.toast, Toast.LENGTH_LONG).show()
}
}
}
内部方法需要通过 this@XXX方法获取到所在的外部环境对象
8.初始化判断
private lateinit var test: String
fun main() {
if (!this::test.isInitialized) {
test = "test"
}
}
:: 表示当前上下文内的引用对象,isInitialized是判断是否初始化
9.类引用
Test::class.java
等同于Test.Class
10.继承与方法重写(open)
open class Test1{
open fun test1(){}
}
class Test2 :Test1(){
override fun test1(){
}
}
使用open标记被继承的类与需要被重写的方法,因为kotlin默认生成的方法都是final型,需要声明open属性 才能被修改
比如上面不加open生成的是
public final class TestCsdn {
public final void main() {
}
}
加了open之后生成的是
public class Test1 {
public void test1() {
}
}
public final class Test2 extends Test1 {
public void test1() {
}
}
可见open标记的子类方法也是可以被重写的,而子类没声明open生成的还是final类型,不能被继承
11.静态对象(object)
fun main() {
Test.ObjTest.test
Test.ObjTest.objTest()
}
class Test {
object ObjTest {
val test: String? = null
fun objTest() {
}
}
}
object声明一个静态对象,里面的所有属性和方法得可以对象类直接调用,但object方法实际是生成了一个静态的单例,调用方法实际是也是调用这个单例的方法
public final void main() {
Test.ObjTest.INSTANCE.getTest();
Test.ObjTest.INSTANCE.objTest();
}
public static final class ObjTest {
@Nullable
private static final String test;
public static final Test.ObjTest INSTANCE;
@Nullable
public final String getTest() {
return test;
}
public final void objTest() {
}
private ObjTest() {
}
static {
Test.ObjTest var0 = new Test.ObjTest();
INSTANCE = var0;
}
}
12.伴生对象(companion object)
fun main() {
Test.test
Test.comObjTest()
}
}
class Test {
companion object {
val test: String? = null
fun comObjTest(){
}
}
}
compain object 和 object类似,但这个没有对象声明,并且会在所在的外部类的成员变量中生成一个静态的该对象,我们调用外部类的相关的伴生方法,最终是会调用到这个静态对象的方法;
@Nullable
private static final String test;
public static final Test.Companion Companion = new Test.Companion((DefaultConstructorMarker)null);
public final void main() {
Test.Companion.getTest();
Test.Companion.comObjTest();
}
public static final class Companion {
@Nullable
public final String getTest() {
return Test.test;
}
public final void comObjTest() {
}
private Companion() {
}
// $FF: synthetic method
public Companion(DefaultConstructorMarker $constructor_marker) {
this();
}
}
object和 compain object 其实原理都一样,只是生产的位置不一样,调用的方式也就不一样;object是生成在自己内部 compain object是生成在所在的外部类中
13.内部类(inner)
class Test1 {
val test = "test"
inner class InnnerTest {
fun test() {
Log.e("test", this@Test1.test)
}
}
}
inner属性声明的内部类可以访问外部类的属性,kotlin里的所有内部类都是静态的,可以减少内存泄露风险,如果我们不加inner属性,生成的类结构是
public final class Test1 {
@NotNull
private final String test = "test";
@NotNull
public final String getTest() {
return this.test;
}
public static final class InnnerTest {
public final void test() {
}
}
}
可见内部类是静态的,显然不能访问外部类的属性;
这里提一下,所有类属性的get方法都会自动生成的
14.强转换(as)
var textView: TextView? = null
var view: View? = null
fun main() {
// textView = view as TextView
textView = findViewById(R.id.textView) as TextView
textView = findViewById(R.id.textView) as? TextView
}
可空转换用 as?
15.类型检查(is)
fun main() {
var i1 = Test1() is Test1
var i2 = Test2() !is Test1
println("$i1 $i2")
}
相当于java里面的 instanceof
16.when选择
fun main() {
val position = 1;
when(position){
1 -> log(1)
2 -> log(2)
3 -> log(3)
else -> log(-1)
}
}
fun log(value:Int){
println("$value")
}
17.解构
fun main() {
val student = Student("Name1",1)
val(_name,_age) = student
println("name -> $_name ; age -> $_age")
}
data class Student constructor(var name: String, var age: Int)
就是把一个对象的属性用字段接收,这里用_name和_age去接收了student的两个对应属性,必须是构造方法的格式接收
每个data的属性都会在编译时生成相应的component获取的方法
public final class Student {
@NotNull
private String name;
private int age;
//这里略去了get和set方法
public Student(@NotNull String name, int age) {
Intrinsics.checkParameterIsNotNull(name, "name");
super();
this.name = name;
this.age = age;
}
@NotNull
public final String component1() {
return this.name;
}
public final int component2() {
return this.age;
}
}
而在调用结构操作之后,会自动拆成单个属性返给我们,比如上面拆成的是
fun main(){
Student student = new Student("Name1", 1);
String _name = student.component1();
int _age = student.component2();
String var3 = "name -> " + _name + " ; age -> " + _age;
System.out.println(var3);
}
注意,结构的格式必须安装构造方法来
18.事务处理
主要的链式处理有apply ,let , also ,run ,with
fun main() {
val mCode = Code(1)
mCode?.also {
println("${it.code}")
}
mCode?.run {
println("$code")
}
mCode?.apply {
println("$code")
}
mCode?.let {
println("${it.code}")
}
with(mCode) {
println("$code")
}
}
data class Code constructor(var code: Int)
总体来说,如果没有返回类型,其实用法都差不多,只是let和also的方法的上下文环境得用it,而其他的上下文环境都是this,此外,with需要把变量传进去
18.1 apply
val result = mCode?.apply {
code = 2
"insert message"
}
println("${result}")
输出结果是
Code(code=2)
appy可以直接调用对象内属性,而且返回值是本身
18.2 let
val result = mCode?.let {
it.code = 2
"insert message"
}
println("${result}")
输出结果是
insert message
let需要用it去调用内部属性,返回值是执行中最后的返回值
18.3 also
val result = mCode?.also {
it.code = 2
"insert message"
}
println("${result}")
输出结果是
Code(code=2)
also需要用it去调用内部属性,返回值是本身
18.4 run
val result = mCode?.run {
code = 2
"insert message"
}
println("${result}")
输出结果是
insert message
run可以直接调用对象内属性,返回值是执行中最后的返回值
18.5 with
val result = with(mCode) {
code = 2
"insert message"
}
println("${result}")
输出结果是
insert message
with可以直接调用对象内属性,返回值是执行中最后的返回值
方法 | 说明 | 返回 |
---|---|---|
apply | 返回当前的上下文对象 | T -> T this |
let | 返回计算后的 | T -> R it |
also | 返回当前的上下文对象 | T -> T it |
run | 返回计算后的 | T -> R this |
with | 返回计算后的 | T -> R this |
19.多行字符串(""")
var testStr =
"""||第一行
||第二行
||第三行"""
println(testStr)
println(testStr.trimMargin("||"))
输出结果是
||第一行
||第二行
||第三行
第一行
第二行
第三行
20.拓展函数
kotlin支持对类的方法进行推展,拓展类未定义的方法,拓展本身支持自定义的或者android库中的类
class Student {
val name = "s_name"
val age = 10
}
fun Student.test() = println("name -> ${this.name} \nage -> ${this.age}")
fun File.aaa() = println("file extends path ->>${path} : ${exists()}")
fun main() {
var stu = Student()
stu.test()
var file = File("E:/test.test")
file.aaa()
}
上面我定义了一个类Student,然后对这个类进行方法拓展,可以获取到类中的属性,可以通过类对象直接调用;这个对系统类库同样适用,比如这里定义的File也是可以进行拓展的
输出结果是
name -> s_name
age -> 10
file extends path ->>E:\test.test : false
21.复数声明(vararg)
在java中,我们定义复数声明的格式一般是 int... values
,kotlin中也有类似的结构声明,使用vararg
关键字进行复数声明
fun main() {
test("start", 1, 3, 5)
}
fun test(str: String, vararg values: Int) {
println(str)
for (i in values) {
println("value -> $i")
}
}
输出结果
start
value -> 1
value -> 3
value -> 5