[AS3.6.1]Kotlin学习笔记2

前言

kotlin学习第二篇文章!直接开始!
历史文章
[AS3.6.1]Kotlin学习笔记1

init

上篇我们讲到类的使用JavaC.classKotlinC.kt继续扩展,首先我们讲的是初始化代码块,java和kotlin的不同!不太懂可以看下这篇文章Java初始化块(静态代码块和非静态代码块)


public class JavaC {
    private String name = "JavaC";
    private List strs;
    {
        strs = new ArrayList<>();
        strs.add("a");
        strs.add("b");
        strs.add("c");
    }

    public JavaC() {
    }

    public JavaC(String name) {
        this.name = name;
    }

    public String getName() {
        return name + ".class";
    }

    public void setName(String name) {
        this.name = "set " + name;
    }

    public void logList(){
        for (String str : strs) {
            Log.e(name, str);
        }
    }
}

class KotlinC {
    var name: String = "KotlinC"
        //由于kotlin使用的是field代表变量所以必须直接写在变量下方
        get() {
            return field + ".kt"
        }
        set(value) {
            field = "set " + value
        }
    var strs: Array? = null

    init {
        strs = arrayOf("a", "b", "c")
    }

    constructor()

    constructor(name: String) {
        this.name = name
    }

    fun logList(){
        for (str in strs!!){
            println(str)
        }
    }
}

还是原来的代码,就是新增了一个代码块!java中直接使用{}就可以了而在kotlin中需要加入标示init{}来实现,直接实例化两个方法调用

    javaC.logList()		// a b c
    println("-------------")
    kotlinC.logList()	// a b c

都是同样的结果。这边再次回顾了下!!的用法!你可以这么认为加上!!的标示就是让kotlin的Null安全取消。


常量

在java中我们设置一些常量的时候基本都是使用static final但是在kotlin中没有了静态变量和静态方法,新的实现如下

	//java
    public static final String CONSTANT = "JavaC常量";

	//kotlin
    companion object{
        const val CONSTANT:String = "KotlinC常量"
    }

	//调用
    println(JavaC.CONSTANT) //JavaC常量
    println(KotlinC.CONSTANT)   //KotlinC常量

我们发现kotlin中完全就变了,使用了companion object const一堆的关键字修饰一个常量。

object

上述一堆关键字我们就从object开始讲解。在java中我们有Object代表一切类的基类,但是在kotlin中Object变成了Any,而object是一个关键字,代表了对象的意思。
我们是可以直接创建一个对象的,即对象类

object Object {
    val name = "我是一个对象"

    fun log(){
        println(name)
    }
}

我们发现直接可以看到创建类的class直接被替换成了object也可以直接调用

	println(Object.name)   //我是一个对象
	Object.log()   //我是一个对象
  • 单例类

这边我们还需要了解到kotlin的object其实是一个自带实现饿汉式单例的单例对象
我们来比对下java和kotlin的饿汉式单列代码

//java
public class JHungry {
    private static final JHungry hungry = new JHungry();
    private String name = "Java Hungry";

    public static JHungry getInstance() {
        return hungry;
    }

    private JHungry() {
    }

    public String getName() {
        return name;
    }
}

//kotlin
object KHungry {
    var name: String = "Kotlin Hungry";
}

	//调用
    println(JHungry.getInstance().name)   //Java Hungry
    println(KHungry.name)   //Kotlin Hungry

我们很明显的可以看到使用kotlin的object对象直接生成的饿汉式的单例比java简便了非常的多!
并且object是可以直接继承classinterface的能让继承的类既有 class 关键字的功能,又实现了单例。快捷且方便!

  • 匿名类

java中我们也会经常用到匿名类,kotlin中也可以实现,下面我们看下代码区别

	//java
    View.OnClickListener listener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
        	//override
        }
    };
    //Convert to lambda
    View.OnClickListener listener2 = v ->{
        	//override
    };

	//kotlin
    val listener = object: View.OnClickListener {
        override fun onClick(v: View?) {
        	//override
        }
    }
    //Convert to lambda
    val listener2 = View.OnClickListener {
        //override
    }

可以看到由于kotlin没有new这个关键字所以使用了object来替代,转化成lambda的时候java省略了newkotlin就省略打了object

companion

经过上面object的说明我们了解到只要用了object生成的对象类就一定使整个类都变成了静态的,如果我们只想要部分代码静态就需要用到companion代码就是我们一开始常量目录下的JavaC类和KotlinC类

//java
public class JavaC {
    private String name = "JavaC";
    
    public static final String CONSTANT = "JavaC常量";
    //...省略其他代码
}

//kotlin
class KotlinC {
    var name: String = "KotlinC"
    
    companion object Const{
        const val CONSTANT:String = "KotlinC常量"
    }
    //...省略其他代码
}

我们就可以这么理解companion:可以理解为伴随、伴生,表示修饰的对象和外部类绑定。
这边我们为companion object设置了一个名字Const但是我们调用的代码是可以跳过object对象的名称直接调用的

    println(JavaC.CONSTANT) //JavaC常量
    println(KotlinC.CONSTANT)   //KotlinC常量

所以就有了常量目录下最开始的直接写法

    companion object{
        const val CONSTANT:String = "KotlinC常量"
    }

top-level property / function 声明

kotlin中的top-level property顶层声明 这可以直接去调用一个kt文件里面的方法,只需要导入包名就可以使用,非常的方便。
首先我们创建一个expand.kt文件

package com.gjn.kotlindemo

fun funExpand(){
    println("fun Expand")
}

里面就一个方法,那么我们在同级目录下的其他类中可以完美的直接使用,不在同级只需要导入包名也是可以直接使用的

package com.gjn.kotlindemo

class MainActivity : AppCompatActivity() {

	override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        funExpand()	//fun Expand
	}
	
}

在java中我们经常会写一些工具类,在kotlin中就可以使用top-level property完美简化工具类的调用,还有就是我们先在经常直接使用的println方法我们会发现明明我们什么都都没导入直接就可以使用系统的System.out.println了,其实你点进println就可以看到其实是官方写了一个kt方法来实现的。

使用objectcompanion objecttop-level情况

那在实际使用中,在 objectcompanion objecttop-level 中该选择哪一个呢?
简单来说按照下面这两个原则判断:
如果想写工具类的功能,直接创建文件,写 top-level「顶层」函数。
如果需要继承别的类或者实现接口,就用 object 或 companion object。

const

与java的常量有区别,kotlin的常量是有规则的

  1. 必须声明在对象object(包括伴生对象companion object)或者「top-level 顶层」中,因为常量是静态的。
  2. 必须加修饰常量的const关键字。
  3. 只有基本类型和String类型可以声明成常量。

这边kotlin和java有一点很大的区别,就是不能把非基本类型设置成常量。这是因为kotlin中的常量就是代表了在编译之后百分百不会变动的才是常量,而很多非基本类都是设置一个伪常量对象,实际运行中是会被修改内部的属性的,所以属于伪常量。
我这边觉一个例子,我们在app运行前并没有获取服务器部分数据,拿到json数据之后转换成常量对象,所以我们会先设置一个常量对象设置null当服务器获取数据之后在来配置一些基本值。这个时候
我们开始设置的常量对象其实就只是一个伪常量因为我们获取到数据之后其实改变了常量对象内的值,所以在kotlin中直接就去掉这个概念,防止一些错误产生。


数组、集合、序列

第一篇中讲for的调用的时候,稍微写了些数组和集合。下面我们来正式讲一下kotlin的数组和集合

数组

首先我们看下java和kotlin创建数组的区别

	//java
    private String[] arrayStrs = {"java1", "java2", "java3"};

	//kotlin
    val arrayStrs: Array = arrayOf("kotlin1", "kotlin2", "kotlin3")

我们可以看到kotlin中的数组其实是一个对象是可以直接调用一些常用的方法的,为了更加便捷。
取值和修改和java中是一样的

    println(kotlinC.arrayStrs[1]) //kotlin2
    kotlinC.arrayStrs[0] = "test"
    println(kotlinC.arrayStrs[0]) //test

集合

kotlin和java一样有三种集合类型:List、Set 和 Map。
和创建数组一样集合也是可以快速创建的

	//java
    private List strList = new ArrayList<>();
    strList.add("a");
    strList.add("b");
    strList.add("c");
    strList.add("b");
    strList.add("a");
    
    private Set strSet = new HashSet<>();
    strSet.add("a");
    strSet.add("b");
    strSet.add("c");
    strSet.add("b");
    strSet.add("a");

    private Map strMap = new HashMap<>();
    strMap.put(1, "a");
    strMap.put(2, "b");
    strMap.put(3, "c");
    strMap.put(4, "b");
    strMap.put(5, "a");

	//kotlin
    val strList = listOf("a", "b" , "c", "b" , "a")
    val strSet = setOf("a", "b" , "c", "b" , "a")
    val strMap = mapOf(1 to "a", 2 to "b", 3 to "c", 4 to "b", 5 to "a")

我们能够看到,kotlin创建数组添加数据比java方便了许多。
这边要注意一下使用listOf setOf mapOf生成的集合是只读集合,是无法修改值的。想要修改值可以使用toMutableList toMutableSet toMutableMap方法或者直接创建一个mutableListOf mutableSetOf mutableMapOf集合,可以发现可变的集合都是使用mutable前缀修饰

序列(Sequence)

这是kotlin引入的新容器。它和Iterable一样用来遍历一组数据并可以对每个元素进行特定的处理。
基本使用如下

    val strSeq =sequenceOf("a", "b", "c", "b", "a")
    //strList是上面创建的	基本上最常用的创建方法
    val strSeq2 = strList.asSequence()
    //generateSequence按方法推断生成	直到返回结果为null
    //无限序列
    val strSeq3 = generateSequence(0){ it + 1}
    //有限序列
    val strSeq4 = generateSequence(0){
        if (it < 10){
            it + 1
        }else{
            null
        }
    }

那么问题来了,这个有啥用呢?我们可以把序列简单理解为Java8中的流,序列简单一点说就是实现对集合的操作进行延迟,专业的说法叫惰性集合操作,就是把你对集合的一系列操作拖到最后一刻才执行。序列和集合的区别就是惰性求值及早求值的区别,集合会在每次形式新的集合的时候全部遍历一遍,而序列是执行完后续步骤之后才会走下一个元素,不是很明白可以看下Kotlin系列之序列


修饰符

  • public:公开,哪都可以引用
  • private:私有,声明类或者文件内引用
  • protected:保护,在kotlin中可以理解为private+子类引用
  • internal:内部,kotlin新增加的修饰符,仅在module内引用

这边我们说下 privateinternal
首先private和java中有点区别,就是private的范围更小,在一个外部类新增一个内部类,如果对内部类的参数或者函数设置了private,那么在外部类也无法直接访问或者调用内部类的参数和函数,这是和java的区别。

然后是internal,这是kotlin新加的修饰符,可以理解为项目内可用,比如我们写一个某个工具library这个时候里面加入internal的函数就只能在library内使用,我们外部导入这个工具library是无法调用设置internal的函数或者参数的。


资料

Kotlin 里那些「不是那么写的」
Java初始化块(静态代码块和非静态代码块)
Kotlin系列之序列

你可能感兴趣的:(程序日记)