Java与Kotlin在语法上的差异

1、源文件后缀名

Java:.java
Kotlin:.kt

2、继承

Java:
父类:class Base{}
子类:class SubClass extends Base
Kotlin:
父类:open class Base(b:Int)
子类:class SubClass(b:Int) : Base(b)
注:Kotlin的父类必须是open的,否则它默认是final的。final的类不能被继承。

3、变量

Java:

 <PropertyType> <propertyName>[= <property_initializer>];
int param1 = 100;
int param2

Kotlin:

var <propertyName>[: <PropertyType>] [= <property_initializer>]
      [<getter>]
      [<setter>]
**Kotlin:**
var param1 : Int = 100
var param2
var param2 : Int
var param2 : Int
var: Int = 9999

变量默认有set和get两个参数,它们表示设置和获取。即:

var param1
set
get

同时它们还有set(value)和get()和get(value)。可以根据需要实现它们:

var param1 = 5
    set//默认
    get//默认

var param2 = 7
    set(value){
        field = value*2
    }
    get() = field + 4

var param3 = 7
    set(value){
        field = value*2
    }
    get() {
       return field +3
    }


fun main(args: Array<String>){
    println(param1)
    println(param2)
    param2 = 10
    println(param2)
    println(param3)
    param3 = 3
    println(param3)

}

变量在定义时都要被初始化,否则就要将变量声明为可空类型,如:

var str: String?   //可空类型就是在类型后面加个问号

4、常量

Java:

final int param = 100;

Kotlin:

val <propertyName>[: <PropertyType>] [= <property_initializer>]
      [<getter>]
val param = 100
val param : Int = 100
val 我 : Int = 9999 //你没看错,Kotlin的常量名不再局限于英文字母、下画线和数字了。

val是常量,所以只有get方法

val param1 = 5
    get//默认

val param2 = 7
    get() = field + 4
fun main(args: Array<String>){
    println(param1)
    println(param2)
}

5、语法定义

Java:

int getParam(){
	return 8;
}

Kotlin:

fun getParam(): Int{
    return 8
}

6、字符模板

Java:
没有字符模板
Kotlin:

fun templateString(str: String): String{
    return "This is a $str"
}
fun main(args: Array<String>){
    println(templateString("Tom"))
}

7、数据类型

Java:
一、基本数据类型:

类型 位宽度
byte 8
short 16
int 32
long 64
float 32
double 64
char 16
boolean 8

二、引用数据类型:
类,接口,数组

Kotlin:
一、基本数据类型:

类型 位宽度
Byte 8
Short 16
Int 32
Long 64
Float 32
Double 64
Char 16
Boolean 8

二、引用数据类型:
可空类型(Null)、对象类型(Object)、数组类型(Array)
三、其他(Java中没有的):
Tuple元组类型,分为二元组(Pair)和三元组(Triple),可以把不同类型的数据组合在一起。

    val (status,msg) = Pair(404,"Not found")
    println("$status:$msg")

    val (server,language,database) = Triple("Nginx","Kotlin","MySql")
    println("Server:$server,Development Language:$language,DB:$database")

8、数据类型的检查

Java:
instanceof

    Object str = "Hello world";
    boolean flag = a instanceof String;

Kotlin:
is

	var str = "Hello world"
    var flag: Boolean = str is String

9、安全操作符:?.

Java:
没有这一类操作符
Kotlin:

var str: String? = null  // 可空类型,可以同值null
var len = str?.length   // 如果str不为空,就返回str的长度,否则返回null

10、Elvis操作符?:

Java:
没有这一类的操作符
Kotlin:

var str: String? = null  // 可空类型,可以同值null
var len = str?.length?:-1  // 如果str不为空,就返回str的长度,否则返回某个非空值,如这里的-1

11、!!操作符

Java:
没有这一类的操作符
Kotlin:

var str: String? = null  // 可空类型,可以同值null
    val len = str!!.length  // 直接抛出空值异常

抛出异常:

 Exception in thread "main" kotlin.KotlinNullPointerException
	at hello.MyMainKt.main(MyMain.kt:16)

11、数据类型的转换

Java:
基本数据类型转换
1、类型转换主要发生在赋值、方法调用、算术运算 三种情况下发生。
  a、赋值和方法调用转换规则:从低位类型到高位类型自动转换;从高位类型到低位类型需要强制类型转换:
  (1)布尔型和其它基本数据类型之间不能相互转换;
  (2)byte型可以转换为short、int、、long、float和double;
  (3)short可转换为int、long、float和double;
  (4)char可转换为int、long、float和double;
  (5)int可转换为long、float和double;
  (6)long可转换为float和double;
  (7)float可转换为double;
  b、算术运算中的类型转换:先转换为高位数据类型,再参加运算,结果也是最高位的数据类型;byte short char运算会转换为Int;
(1)如操作数之一为double,则另一个操作数先被转化为double,再参与算术运算。
(2)如两操作数均不为double,当操作数之一为float,则另一操作数先被转换为float,再参与运算。
(3)如两操作数均不为double或float,当操作数之一为long,则另一操作数先被转换为long,再参与算术运算。
(4)如两操作数均不为double、float或long,则两操作数先被转换为int,再参与运算。
特殊:
1)如采用+=、*=等缩略形式的运算符,系统会自动强制将运算结果转换为目标变量的类型。
2) 当运算符为自动递增运算符(++)或自动递减运算符(–)时,如果操作数为byte,short或char类型不发生改变;
 引用类型转换原则
 1、基本类型与对应包装类可自动转换,这是自动装箱和折箱的原理;

        Integer c1 = new Integer(1);
        Integer c2 = 2;
        int cc = new Integer(3);

2、两个引用类型间转换:
    (1)子类能直接转换为父类 或 接口类型;
    (2)父类转换为子类要强制类型转换;且在运行时若实际不是对应的对象,会抛出ClassCastException运行时异常;

Kotlin:
智能转换,不需要任何操作符进行操作,编辑器会自动跟踪不可变值的is来进行检查,并且在需要时会自动插入进行安全转换(as?)。

不安全转换,var a: String = b as String,如:

    var str: String = "2"
    var a: Int = str as Int  //直接抛异常
    println(a)

安全转换,var a: String? = b as? String,如:

    var str: String = "2"
    var a: Int? = str as? Int
    println(a)

显式转换,国为不能将较小的数据类型隐式转换为较大的类型,所以每个数字都支持进行类型转换。

    var a: Int = 10
    var aByte = a.toByte()
    var aShort = a.toShort()
    var aInt = a.toInt()
    var aLong = a.toLong()
    println(aByte)
    println(aShort)
    println(aInt)
    println(aLong)

隐式转换,在运算的过程中进行转换,如val a = 2L + 3

12、恒等(===)、非恒等(!==)

kotlin中的===为恒等运算符(===)来检查参数与调用equals的对象是否相同。恒等运算符与Java中的==运算符是完全相同的: 检查两个参数是否是同一个对象的引用(如果是基本数据类型,检查他们是否是相同的值). 注意 === 运算符不能被重载.

13、逻辑运算符

Java Kotlin
&& &&或and
|| ||或 or
!
xor(异或)

14、位运算符

Java:

下表列出了位运算符的基本运算,假设整数变量A的值为60和变量B的值为13:

操作符 描述 例子
如果相对应位都是1,则结果为1,否则为0 (A&B),得到12,即0000 1100
| 如果相对应位都是0,则结果为0,否则为1 (A | B)得到61,即 0011 1101
^ 如果相对应位值相同,则结果为0,否则为1 (A ^ B)得到49,即 0011 0001
按位取反运算符翻转操作数的每一位,即0变成1,1变成0。 (〜A)得到-61,即1100 0011
<< 按位左移运算符。左操作数按位左移右操作数指定的位数。 A << 2得到240,即 1111 0000
>> 按位右移运算符。左操作数按位右移右操作数指定的位数。 A >> 2得到15即 1111
>>> 按位右移补零操作符。左操作数的值按右操作数指定的位数右移,移动得到的空位以零填充。 A>>>2得到15即0000 1111

Kotlin
Kotlin中没有位运算符。它抛弃了类C风格的位运算符,只是定义了几个函数:

Java位运算符 Kotlin中缀 Kotlin函数 描述
a&b a and b a.and(b) 按位与
a|b a or b a.or(b) 按位与
a^b a xor b a.xor(b) 按位异或
~a a.inv() 按位取非
a< a shl b a.shl(b) 左移b位
a>>b a shr b a.shr(b) 右移b位
a>>>b a ushr b a.ushr(b) 无符号右移b位

15、数组生成

Java:

    int data1[] = new int[3];
    int data2[] = new int[]{1,2,3};

Kotlin:
Kotlin要使用函数的方法来创建数组

    val b = Array(3){i -> 2 * i }
    println(b[1])
    var a = arrayOf(1,2,3,4)
    a[3] = 100
    println(a[3])
    println(a[2])
    val c: IntArray = intArrayOf(1,3,4,5)
    println(c[3])

16、条件语句switch、when

Java:
switch语句

        int flag = 1;
        switch (flag) {
            case 1:
                System.out.println("登录成功!");
                break;
            case 2:
                System.out.println("登录失败");
                break;

            default: {
                System.out.println("未知错误400");

            }
        }

Kotlin:
when语句,

 var flag: Int = 1
    when(flag){
        1->{
            println("登录成功")
        }
        2->{
            println("登录失败")
        }
        in 3..10->{
            println("未知错误1")
        }
        else->{
            println("未知错误400")
        }
    }

可以用when语句来取代if语句哦,下面的when语句和if语句是等价的

    var name: String = "Tom"
    if(name == "Tom"){
        println("用户名正确")
    }else{
        println("用户名错误")

    }
    when{
        name == "Tom" ->{
            println("用户名正确")
        }
        else->{
            println("用户名错误")

        }
    }

17、for循环

Java:

	int num[] = {1,2,3,4,5};
    for (int a:num) {
       System.out.println(a);
    }
	for (int a = 0; a<3; a++) {
       System.out.println("重要事情说三遍");
    }

Kotlin:

    var num: IntArray = intArrayOf(1,2,3,4,5)
    for (a in num){
        println(a)
    }
   for (a in 0..2){
        println("重要事情说三遍")
    }

还可以像下面的代码那样哦

    var num: Array<String> = arrayOf("a","b","c","d")
    for ((index,value) in num.withIndex()){
        println("index:$index,value:$value")
    }

与Java不同,Kotlin集合分为可变集合不可变集合两种

18、集合之List,有序且可重复的集合
Java:


        List<String> stringList = new ArrayList<>();
        stringList.add("C");
        stringList.add("D");
        stringList.add("E");
        // 修改操作
        stringList.size();// 统计集合中元素的个数
        stringList.isEmpty();// 判断集合是否为空
        stringList.contains("2"); // 判断集合中是否存在某个函数
        stringList.iterator(); // 返回集合中的迭代器
        // 批量操作
        List<String> tempList = new ArrayList<>();
        tempList.add("A");
        tempList.add("B");
        stringList.containsAll(tempList); // 判断集合中是否包含某个集合
        // 搜索操作
        stringList.indexOf("2");// 返回元素首次出现的位置
        stringList.lastIndexOf("2");// 返回元素最后一次出现的位置
        // 迭代器
        Iterator<String> iterator = stringList.iterator();// 返回集合的迭代器
        Iterator<String> iterator1 = stringList.listIterator(2);// 从指定位置返回集合的迭代器
        List subList =  stringList.subList(0,2); // 返回列表中指定区间的集合

        //修改操作
        stringList.add("Hello world"); // 向集合添加元素
        stringList.set(2,"Good morning"); // 用特定的元素替换指定位置的元素
        stringList.add(1,"Good evening"); // 在指定位置添加元素
        stringList.remove(0); // 移除指定索引的元素
        stringList.remove("Hello world"); //移除指定的元素
        List<String> tmp = new ArrayList<>();
        tmp.add("Hi");
        tmp.add("Bye");
        stringList.addAll(tmp); // 向集合中添加一个集合
        stringList.removeAll(tmp); // 移除集合中一个集合
        stringList.retainAll(tmp); // 判断集合中是否包含某个集合
        stringList.clear(); //清空元素

Kotlin:
Kotlin并没有创建List集合的函数,要调用标准库中的listOf()和mutableListOf()方法来创建。

(1)不可变List:

 var stringList: List<String> = listOf("C","D","E")

    // 修改操作
    var elementsCount: Int = stringList.size// 统计集合中元素的个数
    var emptyOrNot: Boolean = stringList.isEmpty()// 判断集合是否为空
    var existsOrNot:Boolean = stringList.contains("2") // 判断集合中是否存在某个函数
    stringList.iterator(); // 返回集合中的迭代器
    // 批量操作
    var tempList: List<String> = listOf("A","B")
    var containOrNot: Boolean = stringList.containsAll(tempList)// 判断集合中是否包含某个集合
    // 搜索操作
    var index: Int = stringList.indexOf("2")// 返回元素首次出现的位置
    var lastIndex: Int = stringList.lastIndexOf("2")// 返回元素最后一次出现的位置
    // 迭代器
    var iterator: Iterator<String> = stringList.iterator()// 返回集合的迭代器
    var iterator1: Iterator<String> = stringList.listIterator(2)// 从指定位置返回集合的迭代器
    var subList: List<String> =  stringList.subList(0,2) // 返回列表中指定区间的集合

可变List:就是多了修改操作

var mutableStringList: MutableList<String> = mutableListOf("C","D","E")

   // 修改操作
   var elementsCount: Int = mutableStringList.size// 统计集合中元素的个数
   var emptyOrNot: Boolean = mutableStringList.isEmpty()// 判断集合是否为空
   var existsOrNot:Boolean = mutableStringList.contains("2") // 判断集合中是否存在某个函数
   mutableStringList.iterator(); // 返回集合中的迭代器
   // 批量操作
   var tempList: List<String> = listOf("A","B")
   var containOrNot: Boolean = mutableStringList.containsAll(tempList)// 判断集合中是否包含某个集合
   // 搜索操作
   var index: Int = mutableStringList.indexOf("2")// 返回元素首次出现的位置
   var lastIndex: Int = mutableStringList.lastIndexOf("2")// 返回元素最后一次出现的位置
   // 迭代器
   var iterator: Iterator<String> = mutableStringList.iterator()// 返回集合的迭代器
   var iterator1: Iterator<String> = mutableStringList.listIterator(2)// 从指定位置返回集合的迭代器
   var subList: List<String> =  mutableStringList.subList(0,2) // 返回列表中指定区间的集合

   //修改操作
   mutableStringList.add("Hello world") // 向集合添加元素
   mutableStringList[2] = "Good morning" // 用特定的元素替换指定位置的元素
   mutableStringList.set(2,"Good morning") // 用特定的元素替换指定位置的元素

   mutableStringList.add(1,"Good evening") // 在指定位置添加元素
   mutableStringList.removeAt(0) // 移除指定索引的元素
   mutableStringList.remove("Hello world") //移除指定的元素
   var tmp: MutableList<String> = mutableListOf("Hi","Bye")
   mutableStringList.addAll(tmp)// 向集合中添加一个集合
   mutableStringList.removeAll(tmp) // 移除集合中一个集合
   mutableStringList.retainAll(tmp)// 判断集合中是否包含某个集合
   var copyList: List<String> = mutableStringList.toList() // 复制list中的内容,返回一个不可变的List
   mutableStringList.clear() //清空元素

19、集合之Set

不可重复,且无序。
Java:

Set<String> stringSet = new HashSet<>();
        stringSet.add("C");
        stringSet.add("D");
        stringSet.add("E");
        // 修改操作
        stringSet.size();// 统计集合中元素的个数
        boolean emptyOrNot = stringSet.isEmpty();// 判断集合是否为空
        boolean containOrNot = stringSet.contains("2"); // 判断集合中是否存在某个函数
        // 批量操作
        List<String> tempList = new ArrayList<>();
        tempList.add("A");
        tempList.add("B");
        boolean containsAllOrNot = stringSet.containsAll(tempList); // 判断集合中是否包含某个集合
        // 迭代器
        Iterator<String> iterator = stringSet.iterator(); // 返回集合中的迭代器
        //修改操作
        stringSet.add("Hello world"); // 向集合添加元素
        stringSet.remove(0); // 移除指定索引的元素
        stringSet.remove("Hello world"); //移除指定的元素
        Set<String> tmp = new HashSet<>();
        tmp.add("Hi");
        tmp.add("Bye");
        stringSet.addAll(tmp); // 向集合中添加一个集合
        stringSet.removeAll(tmp); // 移除集合中一个集合
        stringSet.retainAll(tmp); // 判断集合中是否包含某个集合
        stringSet.clear(); //清空元素

Kotlin:
Kotlin没有提供专门的语法用来创建Set集合,可以使用标准库中的setOf()和mutableSetOf()方法。
不可变Set:


可变Set:

    var stringSet: Set<String> = setOf("C","D","E")

    // 修改操作
    var elementsCount: Int = stringSet.size// 统计集合中元素的个数
    var emptyOrNot: Boolean = stringSet.isEmpty()// 判断集合是否为空
    var existsOrNot:Boolean = stringSet.contains("2") // 判断集合中是否存在某个函数
    // 批量操作
    var tempSet: Set<String> = setOf("A","B")
    var containOrNot: Boolean = stringSet.containsAll(tempSet)// 判断集合中是否包含某个集合
    // 搜索操作
    var index: Int = stringSet.indexOf("2")// 返回元素首次出现的位置
    var lastIndex: Int = stringSet.lastIndexOf("2")// 返回元素最后一次出现的位置
    // 迭代器
    var iterator: Iterator<String> = stringSet.iterator()// 返回集合的迭代器

可变Set:

    var mutableStringSet: MutableSet<String> = mutableSetOf("C","D","E")

    // 修改操作
    var elementsCount: Int = mutableStringSet.size// 统计集合中元素的个数
    var emptyOrNot: Boolean = mutableStringSet.isEmpty()// 判断集合是否为空
    var existsOrNot:Boolean = mutableStringSet.contains("2") // 判断集合中是否存在某个函数
    // 批量操作
    var tempSet: Set<String> = setOf("A","B")
    var containOrNot: Boolean = mutableStringSet.containsAll(tempSet)// 判断集合中是否包含某个集合
    // 搜索操作
    var index: Int = mutableStringSet.indexOf("2")// 返回元素首次出现的位置
    var lastIndex: Int = mutableStringSet.lastIndexOf("2")// 返回元素最后一次出现的位置
    // 迭代器
    var mutableIterator: MutableIterator<String> = mutableStringSet.iterator()// 返回集合的迭代器
    //修改操作
    mutableStringSet.add("Hello world") // 向集合添加元素
    mutableStringSet.remove("Hello world") //移除指定的元素
    var tmp: MutableSet<String> = mutableSetOf("Hi","Bye")
    mutableStringSet.addAll(tmp) // 向集合中添加一个集合
    mutableStringSet.removeAll(tmp) // 移除集合中一个集合
    mutableStringSet.retainAll(tmp) // 判断集合中是否包含某个集合
    var copySet: Set<String> = mutableStringSet.toSet() // 复制Set中的内容,返回一个不可变的Set
    mutableStringSet.clear() //清空元素

20、集合之Map

Java:

        Map<String, String> map = new HashMap<String, String>();

        // 插入元素
        map.put("key1", "value1");
        // 获取元素
        String value = map.get("key1");
        // 移除元素
        map.remove("key1");
        // 清空map
        map.clear();
        // Map 遍历
        // 初始化数据
        Map<String, String> map1 = new HashMap<String, String>();
        map1.put("key1", "value1");
        map1.put("key2", "value2");
        // 增强for循环遍历
        // 使用keySet()遍历
        for (String key : map1.keySet()) {
            System.out.println(key + " :" + map1.get(key));
        }
        // 其实业界更提倡使用entrySet

        for (Map.Entry<String,String> entry : map1.entrySet()) {
            System.out.println(entry.getKey() + " :" + entry.getValue());
        }

        // 迭代器遍历
        // 使用keySet()遍历
        Iterator<String> iterator = map1.keySet().iterator();
        while (iterator.hasNext()){
            String key = iterator.next();
            System.out.println(key + " :" + map1.get(key));
        }

        // 使用entrySet()遍历
        Iterator<Map.Entry<String,String>> iterator1 = map1.entrySet().iterator();
        while (iterator1.hasNext()) {
            Map.Entry<String, String> entry = iterator1.next();
            System.out.println(entry.getKey() + " :" + entry.getValue());
        }

        // Map 排序:HashMap、Hashtable、LinkedHashMap排序
        Map<String, String> map2 = new HashMap<String, String>();
        map2.put("b", "b");
        map2.put("a", "c");
        map2.put("c", "a");
        // 通过ArrayList构造函数把map.entrySet()转换成list
        List<Map.Entry<String, String>> list = new ArrayList<Map.Entry<String, String>>(map2.entrySet());
        // 通过比较器实现比较排序
        list.sort(new Comparator<Map.Entry<String, String>>() {
            @Override
            public int compare(Map.Entry<String, String> mapping1, Map.Entry<String, String> mapping2) {
                return mapping1.getKey().compareTo(mapping2.getKey());
            }
        });


        for (Map.Entry<String, String> mapping : list) {
            System.out.println(mapping.getKey() + " :" + mapping.getValue());
        }


        // TreeMap排序,TreeMap默认按key进行升序排序,如果想改变默认的顺序,可以使用比较器
        Map<String,String> map3 = new TreeMap<>(new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                // 降序排序
                return o2.compareTo(o1);
            }
        });
        map3.put("2", "b");
        map3.put("1", "c");
        map3.put("3", "a");
        for (Map.Entry<String,String> entry : map3.entrySet()) {
            System.out.println(entry.getKey() + " :" + entry.getValue());
        }
        // 按value排序
        TreeMap<String,String> map4 = new TreeMap<>();
        map4.put("5", "1");
        map4.put("7", "3");
        map4.put("6", "2");
        List<Map.Entry<String,String>> list1 = new ArrayList<>(map4.entrySet());
        list1.sort(new Comparator<Map.Entry<String, String>>() {
            @Override
            public int compare(Map.Entry<String, String> o1, Map.Entry<String, String> o2) {
                return o1.getValue().compareTo(o2.getValue());
            }
        });
        for (Map.Entry<String,String> entry : map4.entrySet()) {
            System.out.println(entry.getKey() + " :" + entry.getValue());
        }

Kotlin:
Kotlin没有提供专门的语法用来创建Map集合,可以使用标准库中的mapOf()和mutableMapOf()方法来创建。

不可变Map:

    var map: Map<String, String> = hashMapOf("key1" to "value1")

    // 插入元素

    // 获取元素
    val value: String? = map.get("key1")

    // Map 遍历
    // 初始化数据
    var map1: Map<String, String> = hashMapOf("key1" to "value1","key2" to "value2")
    // 增强for循环遍历
    // 使用keySet()遍历

    for (key in map1.keys) {
        System.out.println(key + " :" + map1.get(key));
    }
    // 其实业界更提倡使用entrySet

    for ( entry in map1.entries) {
        System.out.println(entry.key + " :" + entry.value);
    }

    // 迭代器遍历
    // 使用keySet()遍历
    var iterator:Iterator<String> = map1.keys.iterator();
    while (iterator.hasNext()){
        var key: String = iterator.next();
        System.out.println(key + " :" + map1.get(key));
    }

    // 使用entrySet()遍历
    var iterator1: Iterator<Map.Entry<String,String>>  = map1.entries.iterator();
    while (iterator1.hasNext()) {
        var entry: Map.Entry<String, String> = iterator1.next();
        System.out.println(entry.key + " :" + entry.value);
    }

    // Map 排序:HashMap、Hashtable、LinkedHashMap排序
    var map2: Map<String, String> = hashMapOf("b" to "b","a" to "c","c" to "a")

    // 通过ArrayList构造函数把map.entrySet()转换成list
    var list: List<Map.Entry<String, String>> = map2.entries.toList();
    // 通过比较器实现比较排序
    list.sortedWith(Comparator { o1, o2 ->  o1.key.compareTo(o2.key)})

    for (mapping in list) {
        System.out.println(mapping.key + " :" + mapping.value);
    }


    // TreeMap排序,TreeMap默认按key进行升序排序,如果想改变默认的顺序,可以使用比较器
    var map3: TreeMap<String,String> = TreeMap<String,String>()

    map3["2"] = "b"
    map3["1"] = "c"
    map3["3"] = "a"

    map3.toSortedMap(Comparator { o1 , o2 -> o2.compareTo(o1) })


    for ( entry in map3.entries) {
        System.out.println(entry.key + " :" + entry.value)
    }
    // 按value排序
    var map4: TreeMap<String,String> = TreeMap<String,String>()
    map4["5"] = "1"
    map4["7"] = "3"
    map4["6"] = "2"
    
    for((key,value) in map4.entries){
        println("key:$key###value:$value")
    }
    var list1: List<Map.Entry<String,String>> = map4.entries.toList()
    list1.sortedWith(Comparator { o1, o2 -> o1.value.compareTo(o2.value) })

    for (entry in map4.entries) {
        System.out.println(entry.key + " :" + entry.value)
    }

可变map:就是比不可变map多了一些删除、清空功能

    var map5: MutableMap<Int,String> = mutableMapOf<Int,String>(1 to "A",3 to "C",2 to "B") 

   // 移除元素
   map5.remove(0)
   // 清空map
   map5.clear()

21、集合操作符

Java8:
Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。
Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。
这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。
元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。

(1)java的总数操作

        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        // any是否有满足条件的元素
        boolean flag = list.stream().anyMatch(a -> a > 5);

        System.out.println(flag);
        boolean flag1 = list.stream().anyMatch(new Predicate<Integer>(){

            @Override
            public boolean test(Integer integer) {
                return integer > 5;
            }
        });

        System.out.println(flag1);


        // all是否所有元素都满足条件
        boolean all = list.stream().allMatch(a -> a >5);
        System.out.println(all);


        // none 是否所有元素都不满足条件
        boolean none = list.stream().noneMatch( a -> a > 5);
        System.out.println(none);

        // count 满足条件的元素的个数
        long count = list.stream().count();  //list.size()
        System.out.println(count);


        // reduce 从第一个元素从到最后一个元素进行累计
       Optional.ofNullable(list.stream().reduce((a, b) -> a + b)).ifPresent(value ->
       {
           if(value.isPresent()){
               System.out.println(value.get());
           }
       });

       Optional<Integer> sum = list.stream().reduce(new BinaryOperator<Integer>() {
           @Override
           public Integer apply(Integer integer, Integer integer2) {
               return integer + integer2;
           }
       });

       if(sum.isPresent()) {
           System.out.println(sum.get());

       }

       Optional<Integer> sum1 = Optional.of(list.stream().reduce(10,(a,b)-> a+b));
       if(sum1.isPresent()){
           System.out.println(sum1.get());
       }

        Optional<Integer> sum2 = Optional.of(list.stream().reduce(10, new BinaryOperator<Integer>() {
            @Override
            public Integer apply(Integer integer, Integer integer2) {
                return integer + integer2;
            }
        }));
        if(sum2.isPresent()){
            System.out.println(sum2.get());
        }

        // fold 以一个初始值开始从第一个元素从到最后一个元素进行累计
        // java 没有

        //forEach 循环遍历元素,对于forEach本身需要使用it关键字对每个元素进行相关操作
        list.stream().forEach(a -> {
            if( a == 5){
            System.out.println("I love You!");

        }
        });
        list.stream().forEach(new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) {
                if( integer == 5){
                    System.out.println("I love You!");

                }
            }
        });


        //主要的区别在并行流的处理上
        //输出的顺序不一定(效率更高)
        Stream.of("AAA", "BBB", "CCC").parallel().forEach(s -> System.out.println("Output:" + s));
        //输出的顺序与元素的顺序严格一致
        Stream.of("AAA", "BBB", "CCC").parallel().forEachOrdered(s -> System.out.println("Output:" + s));




        // max 查询最大的元素

        Optional<Integer> max1 = list.stream().max((a,b) -> a.compareTo(b));
        if(max1.isPresent()){
            System.out.println(max1.get());
        }

        System.out.println(list.stream().max(Integer::compare).get());


        // min 查询最小的元素
        Optional<Integer> min1 = list.stream().min((a,b) -> a.compareTo(b));
        if(min1.isPresent()){
            System.out.println(min1.get());
        }

        System.out.println(list.stream().min(Integer::compare).get());

(2)过滤操作

List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);


        // filter 过滤所有满足条件的元素

        Stream<Integer> listStream = list.stream().filter(a -> a > 5 );
        // 将Stream转化为List
        Collection<Integer> listInteger = listStream.collect(Collectors.toList());
        System.out.println(listInteger);

        Stream<Integer> listStream1 = list.stream().filter(new Predicate<Integer>() {
            @Override
            public boolean test(Integer integer) {
                return integer > 5;
            }
        });

        // 将Stream转化为List
        Collection<Integer> listInteger1 = listStream1.collect(Collectors.toList());
        System.out.println(listInteger1);


        // filterNot 过滤掉所有不满足条件的元素
        // Java 没有特别这个功能,需要通过filter实现

        // filter 过滤所有满足条件的元素

        Stream<Integer> listStream2 = list.stream().filter(a -> a <= 5 );
        // 将Stream转化为List
        Collection<Integer> listInteger2 = listStream2.collect(Collectors.toList());
        System.out.println(listInteger2);

        Stream<Integer> listStream3 = list.stream().filter(new Predicate<Integer>() {
            @Override
            public boolean test(Integer integer) {
                return integer <= 5;
            }
        });
        // 将Stream转化为List
        Collection<Integer> listInteger3 = listStream3.collect(Collectors.toList());
        System.out.println(listInteger3);


        // filterNotNull 过滤掉null
        // Java 没有特别提供这个功能,需要通过filter实现
    
        // take 返回从第一个元素开始的n个元素
        // Java 没有特别提供这个功能,需要通过其他方式实现

        // takeLast 返回从最后一个元素开始的n个元素
        // Java 没有特别提供这个功能,需要通过其他方式实现


        // takeWhile 返回从第一个元素开始符合给定函数条件的元素
        // Java 没有特别提供这个功能,需要通过其他方式实现
        
        // drop 返回去掉前n个元素的列表
        // Java 没有特别提供这个功能,需要通过其他方式实现



        // dropLastWhile 返回从最后一项起,去掉满足条件的元素,直到不满足条件的一项为止
        // Java 没有特别提供这个功能,需要通过其他方式实现

        // slice 过滤掉非指定下标对应的元素,即保留指定下标对应的元素
        // Java 没有特别提供这个功能,需要通过其他方式实现

(3)Java8映射操作

        List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);

        // map对集合中的元素通过 某方法转换后,将结果保存到一个集合中

        // 将Stream转化为List
        Stream<Integer> listStream1 = list.stream().map(a -> a + 1);
        Collection<Integer> listInteger1 = listStream1.collect(Collectors.toList());
        System.out.println(listInteger1);


        Stream<Integer> listStream2 = list.stream().map(new Function<Integer, Integer>() {
            @Override
            public Integer apply(Integer integer) {
                return integer + 1;
            }
        });
        Collection<Integer> listInteger2 = listStream2.collect(Collectors.toList());

        System.out.println(listInteger2);

        // mapIndexed 除了可以得到转换后的集合,还可以得到索引(下标)
        // java没有提供这一个,需要通过其他方式实现

        // Java中的flatMap与Kotlin是不一样的。
        // map只是一维1对1的映射
        // 而flatmap可以将一个2维的集合映射成一个一维,相当于他映射的深度比map深了一层
        // Java 8 中我们可以通过 `::` 关键字来访问类的构造方法,对象方法,静态方法
        String[] words = new String[]{"Hello","World"};
        List<String[]> a = Arrays.stream(words).map(word -> word.split("")).distinct().collect(Collectors.toList());
        a.forEach(System.out::println);

        // 对流扁平化处理
        List<String> aa = Arrays.stream(words).map(word -> word.split("")).flatMap(Arrays::stream).distinct().collect(Collectors.toList());
        aa.forEach(System.out::print);
        
        // groupBy将集合中的元素按照某个条件进行分组,返回map
        // java没有提供这一个,需要通过其他方式实现

(4)顺序操作符

        List<Integer> list = Arrays.asList(1, 5, 9, 7, 26, 74, 32, 47, 41, 42, 6);
        // reversed以相反顺序排列
        Collections.reverse(list); // 倒序排列
        System.out.println(list);


        //sorted自然排序(升序)

        System.out.println(list.stream().sorted().collect(Collectors.toList()));
        System.out.println(list.stream().sorted((o1,o2) -> o1 - o2).collect(Collectors.toList()));
        System.out.println(list.stream().sorted(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o1 - o2;
            }
        }).collect(Collectors.toList()));


        // sortedBy根据方法处理结果进行自然(升序)排列
        // java中没有对应的方法,可通过sorted方法来实现

        // sortedDescending降序排列

        System.out.println(list.stream().sorted((o1,o2) -> o2 - o1).collect(Collectors.toList()));
        System.out.println(list.stream().sorted(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2 - o1;
            }
        }).collect(Collectors.toList()));


        // sortedByDescending根据方法处理结果进行降序排列
        // java中没有对应的方法,可通过sorted方法来实现

(5)生产操作符
在Java中没有对应的,需要通过其他方式来实现。
(6)元素操作符

 List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);

        // contains 判断集合是否包含有指定的元素,如果有则返回true,否则返回false
        System.out.println(list.contains(0));
        System.out.println(list.contains(5));

        // elementAt 查找下标对应的元素,java可以用get来代替
        System.out.println(list.get(0));
        // elementAtOrElse  查找下标对应的元素,如果下标越界,则返回指定的默认值
        // java没有对应的方法

        // elementAtOrNull 查找下标对应的元素,如果下标越界,则返回null
        // java没有对应的方法

        // first 返回符合条件的第一个元素,如果没有则抛出异常
        // java没有对应的方法


        // firstOrNull 返回符合条件的第一个元素,如果没有则返回null
        // java没有对应的方法

        // indexOf 返回指定元素对应的下标,没有则返回-1
        System.out.println(list.indexOf(8));

        // indexOfFirst 返回第一个符合条件的元素的下标,没有则返回-1
        // java没有对应的方法

        // indexOfLast 返回最后一个元素的下标,没有则返回-1
        // java没有对应的方法


        // last 返回符合条件的最后一个元素,没有则抛出异常
        // java没有对应的方法


        // lastIndexOf 返回符合条件的最后一个元素的下标,没有则返回-1
        System.out.println(list.lastIndexOf(5));
        // lastOrNull 返回符合条件的最后一个元素,没有则返回null
        // java没有对应的方法

        // single  返回符合条件的元素,没有或超过一个都会报异常
        // java没有对应的方法

        // singleOrNull 返回符合条件的元素,没有或超过一个则返回null
        // java没有对应的方法       

Kotlin:
(1)总数操作符


fun main(){
   val list = listOf(1,2,3,4,5,6,7,8,9,10)
    // any是否有满足条件的元素
    println(list.any { it > 5}) // it是默认的传入参数
    println(list.any{ i: Int -> i > 5 })
    println(list.any { a -> a > 5 })
    println(list.any(fun(a: Int): Boolean{
        return a > 5
    }))
    println("any#"+list.any()) // 集合是否不为空


    // all是否所有元素都满足条件
    println(list.all { it > 5 })
    println(list.all { a: Int -> a > 5 })
    println(list.all { a -> a > 5 })
    print("####")
    println(list.all(fun(a: Int): Boolean{
        return a > 5
    }))


    // none 是否所有元素都不满足条件
    println(list.none { it > 5 })
    println(list.none { a: Int -> a > 5 })
    println(list.none { a -> a > 5 })
    println(list.none(fun(a: Int): Boolean{
        return a > 5
    }))
    println("none#"+list.none()) // 集合是否为空

    // count 满足条件的元素的个数
    println(list.count { it > 5 })
    println(list.count { a: Int -> a > 5 })
    println(list.count { a -> a > 5 })
    println(list.count(fun(a: Int): Boolean{
        return a > 5
    }))
    println("count##"+list.count()) // 集合元素的个数

    // reduce 从第一个元素从到最后一个元素进行累计
    println(list.reduce { total, next -> total + next  })
    println(list.reduce(Int::plus))
    println("%%%%")
    println(list.reduce(fun(total: Int, next: Int): Int{
        return total + next
    }))


    // reduceRight 从最后一个元素从到第一个元素进行累计
    println(list.reduceRight { total, next -> total + next  })
    println(list.reduceRight(Int::plus))
    println(list.reduceRight(fun(total: Int, next: Int): Int{
        return total + next
    }))

    // fold 以一个初始值开始从第一个元素从到最后一个元素进行累计
    println(list.fold(10){ total,next -> total + next})
    println(list.fold(20,{ tatol,next -> tatol + next })) // 一般都不样写,一般都写成上面那样,把lamda放在括号外面
    println(list.fold(2,fun(total: Int, next: Int): Int{
        return total + next
    }))

    // foldRight 以一个初始值开始从最后一个元素从到第一个元素进行累计
    println(list.foldRight(1){ total, next -> total + next })
    println(list.foldRight(2,fun(total: Int, next: Int): Int{
        return total + next
    }))
    //forEach 循环遍历元素,对于forEach本身需要使用it关键字对每个元素进行相关操作
    list.forEach {
        if( it == 5 ){
            println("I love You!")
        }
    }

    list.forEach(fun(value: Int){
        if(value == 10) {
        println("I am very good!")
        }
    })

    // forEachIndexed 循环遍历元素,同时得到元素索引
    list.forEachIndexed{ i,s ->
        print(i)
        print("#")
        println(s)
    }
    list.forEachIndexed(fun(index: Int, s: Int){
        println("#$index#$s")
    })

    // max 查询最大的元素,如果没有就返回null
    println(list.max())

    // maxBy 获取处理后返回结果最大值 对应的那个元素的初始值,没有则返回null
    println(list.maxBy { it * it })
    println(list.maxBy(fun(i: Int):Int{
        return i*i
    }))

    // min 查询最小的元素,如果没有就返回null
    println(list.min())

    // minBy 获取处理后返回结果最小值对应的那个元素的初始值,没有则返回null
    println(list.minBy { it * it })
    println(list.minBy(fun(i: Int):Int{
        return i*i
    }))

    // sumBy 获取处理后返回结果值的总和
    println(list.sumBy { it * it })
    println(list.sumBy(fun(i: Int):Int{
        return i*i
    }))

    // dropWhile返回从第一项起,去掉满足条件的元素,直到不满足条件的一项为止
    println(list.dropWhile { it < 5 })
    println(list.dropWhile(fun(i :Int):Boolean{
        return i < 5
    }))

}



(2)过滤操作符

   val list = listOf(1,2,3,4,5,6,7,8,9,10)

    // filter 过滤所有满足条件的元素

    println(list.filter { it > 5 })
    println(list.filter { a: Int -> a > 5 })
    println(list.filter{ a -> a > 5 })
    println(list.filter(fun( a: Int): Boolean{
        return a > 5
    }))

    // filterNot 过滤掉所有不满足条件的元素
    println("###")
    println(list.filterNot { it > 5 })
    println(list.filterNot { a: Int -> a > 5 })
    println(list.filterNot { a -> a > 5 })
    println(list.filterNot(fun( a: Int): Boolean{
        return a > 5
    }))

    // filterNotNull 过滤掉null
    println(list.filterNotNull())


    // take 返回从第一个元素开始的n个元素
    println(list.take(5))

    // takeLast 返回从最后一个元素开始的n个元素
    println(list.takeLast(5))

    // takeWhile 返回从第一个元素开始符合给定函数条件的元素
    println("###")
    println(list.takeWhile { it < 5 })
    println(list.takeWhile { a: Int -> a < 5 })
    println(list.takeWhile { a -> a < 5 })
    println(list.takeWhile(fun( a: Int): Boolean{
        return a < 5
    }))

    // drop 返回去掉前n个元素的列表
    println("###")
    println(list.drop(5))


    // dropLastWhile 返回从最后一项起,去掉满足条件的元素,直到不满足条件的一项为止

    println("###")
    println(list.dropLastWhile { it > 5 })
    println(list.dropLastWhile { a: Int -> a > 5 })
    println(list.dropLastWhile { a -> a > 5 })
    println(list.dropLastWhile(fun( a: Int): Boolean{
        return a > 5
    }))
    // slice 过滤掉非指定下标对应的元素,即保留指定下标对应的元素
    println(list.slice(0..9))
    println(list.slice(0..4))
    println(list.slice(listOf(0,2,4,6,8)))

(3)映射操作符

   val list = listOf(1,2,3,4,5,6,7,8,9,10)

    // map对集合中的元素通过 某方法转换后,将结果保存到一个集合中
    println(list.map { it + 1 })
    println(list.map { a: Int -> a + 1 })
    println(list.map { a -> a + 1 })
    println(list.map(fun(a: Int): Int{
        return a + 2
    }))
    // mapIndexed 除了可以得到转换后的集合,还可以得到索引(下标)
    println(list.mapIndexed { index, i ->  index * i  })
    println(list.mapIndexed(fun(index: Int,i: Int): Int{
        return index * i
    }))
    // mapNotNull在执行方法转换前过滤掉值为null的元素
    println(list.mapNotNull { it + 1 })
    println(list.mapNotNull { a: Int -> a + 1 })
    println(list.mapNotNull { a -> a + 1 })
    println(list.mapNotNull(fun(a: Int): Int{
        return a + 2
    }))
    // flatMap合并两个集合,可以在合并时做些其他小操作

    val list2 = listOf(11,12,13,14,15,16,17,18,19,20)
    println(listOf(list,list2).flatten())
    println(listOf(list,list2).flatMap { it.map {  "No.$it" } })
    println(listOf(list,list2).flatMap(fun(a: List<Int>): Iterable<String>{
        return a.map { "NNO.$it" }.asIterable()
    }))

    // groupBy将集合中的元素按照某个条件进行分组,返回map
    println(list.groupBy { if( it > 5) "Big" else "small" })
    println(list.groupBy{ a -> if(a > 5) "Big" else "small"})
    println(list.groupBy{ a: Int -> if(a > 5) "Big" else "small"})
    println(list.groupBy(fun(a: Int): String{
        return if(a > 5) "Bmig" else "small"
    }))

(4)顺序操作符

    var list = listOf(1, 5, 9, 7, 26, 74, 32, 47, 41, 42, 6)
    // reversed以相反顺序排列
    println(list.reversed())
    //sorted自然排序(升序)
    println(list.sorted())
    // sortedBy根据方法处理结果进行自然(升序)排列
    println(list.sortedBy{ it % 2 })
    println(list.sortedBy { a -> a % 2 })
    println(list.sortedBy { a: Int -> a % 2 })
    println(list.sortedBy(fun(a: Int): Int{
        return a % 2
    }))

    // sortedDescending降序排列
    println(list.sortedDescending())


    // sortedByDescending根据方法处理结果进行降序排列
    println(list.sortedByDescending { -it })
    println(list.sortedByDescending { a -> -a })
    println(list.sortedByDescending { a: Int -> -a })
    println(list.sortedByDescending(fun(a: Int): Int{
        return -a
    }))

(5)生产操作符
主要用于把两个集合按照相同的下标合成一个新的集合,这个集合的大小由最小的集合决定。

    // zip 将两个集合按照下标组合成一个个Pair放到集合中返回
    var list1 = listOf(2,3,4,5,6,7)
    var list2 = listOf(8,9,0)
    println(list1.zip(list2))  // [(2, 8), (3, 9), (4, 0)]
    println("$$$")
    println(list1.zip(list2,fun(a: Int,b: Int): Int{
        return a + b
    })) //[10, 12, 4]
    println(list1.zip(list2){ t1,t2 -> t1 + t2   }) // //[10, 12, 4]
    var list3 = listOf(Pair(1,5), Pair(2,7),Pair(4,3))
    println(list3.zip(listOf(3,6))) // [((1, 5), 3), ((2, 7), 6)]

    // partition 根据判断条件是否成立,拆分成两个Pair
    println(list1.partition(fun(a: Int): Boolean{
        return a % 2 == 0
    }))  // ([2, 4, 6], [3, 5, 7])

    println(list2.partition{ it % 2 == 0})  // ([8, 0], [9])


    // plus 合并两个List集合,可以用“+”代替plus
    println(list1.plus(list2))
    println(list1 + list2)

    // unzip 将包含多个Pair4的List集合转换成含List集合的Pair
    println(list3.unzip())

(6)元素操作符

    var list = listOf(1,2,3,4,5,6,7,8,9,10)

    // contains 判断集合是否包含有指定的元素,如果有则返回true,否则返回false
    println(list.contains(0))
    println(list.contains(5))
    // elementAt 查找下标对应的元素,如果下标越界,则抛出异常
    println(list.elementAt(0))
    // elementAtOrElse  查找下标对应的元素,如果下标越界,则返回指定的默认值
    println(list.elementAtOrElse(11,{ 8 }))
    println(list.elementAtOrElse(11){ 8 })
    println(list.elementAtOrElse(11,fun(a: Int): Int{
        println("over boundary index:$a")
        return 8
    }))

    // elementAtOrNull 查找下标对应的元素,如果下标越界,则返回null
    println(list.elementAtOrNull(11))
    println(list.elementAtOrNull(9))

    // first 返回符合条件的第一个元素,如果没有则抛出异常
    println(list.first())

    println(list.first { it % 2 == 0 }) // 返回第一个符合条件的元素
    println(list.first {a -> a % 2 == 0 })
    println(list.first {a: Int -> a % 2 == 0 })
    println(list.first(fun(a: Int): Boolean{
        return a % 2 == 0
    }))

    // firstOrNull 返回符合条件的第一个元素,如果没有则返回null

    println(list.firstOrNull())

    println(list.firstOrNull { it % 4 == 0 }) // 返回第一个符合条件的元素
    println(list.firstOrNull {a -> a % 4 == 0 })
    println(list.firstOrNull {a: Int -> a % 4 == 0 })
    println(list.firstOrNull(fun(a: Int): Boolean{
        return a % 4 == 0
    }))

    // indexOf 返回指定元素对应的下标,没有则返回-1

    println(list.indexOf(8))
    // indexOfFirst 返回第一个符合条件的元素的下标,没有则返回-1
    println(list.indexOfFirst { it % 5 == 0 }) // 返回第一个符合条件的元素
    println(list.indexOfFirst {a -> a % 5 == 0 })
    println(list.indexOfFirst {a: Int -> a % 5 == 0 })
    println(list.indexOfFirst(fun(a: Int): Boolean{
        return a % 5 == 0
    }))

    // indexOfLast 返回最后一个符合条件的元素的下标,没有则返回-1
    println(list.indexOfLast { it % 5 == 0 }) // 返回第一个符合条件的元素
    println(list.indexOfLast {a -> a % 5 == 0 })
    println(list.indexOfLast {a: Int -> a % 5 == 0 })
    println(list.indexOfLast(fun(a: Int): Boolean{
        return a % 5 == 0
    }))


    // last 返回符合条件的最后一个元素,没有则抛出异常
    println(list.last())
    println(list.last { it % 5 == 0 }) // 返回第一个符合条件的元素
    println(list.last {a -> a % 5 == 0 })
    println(list.last {a: Int -> a % 5 == 0 })
    println(list.last(fun(a: Int): Boolean{
        return a % 5 == 0
    }))



    // lastIndexOf 返回符合条件的最后一个元素的下标,没有则返回-1
    println(list.lastIndexOf(7))

    // lastOrNull 返回符合条件的最后一个元素,没有则返回null
    println(list.lastOrNull())
    println(list.lastOrNull { it % 9 == 0 }) // 返回第一个符合条件的元素
    println(list.lastOrNull {a -> a % 9 == 0 })
    println(list.lastOrNull {a: Int -> a % 9 == 0 })
    println(list.lastOrNull(fun(a: Int): Boolean{
        return a % 9 == 0
    }))

    // single  返回符合条件的元素,没有或超过一个都会报异常
    // println(list.single())  //list 只能有一个元素,否则会报异常
    var singleList = listOf(8)
    println(singleList.single())
    println(list.single { it % 9 == 0 }) // 返回第一个符合条件的元素
    println(list.single {a -> a % 9 == 0 })
    println(list.single {a: Int -> a % 9 == 0 })
    println(list.single(fun(a: Int): Boolean{
        return a % 9 == 0
    }))

    // singleOrNull 返回符合条件的元素,没有或超过一个则返回null
    println(list.singleOrNull())
    println(list.singleOrNull { it % 9 == 0 }) // 返回第一个符合条件的元素
    println(list.singleOrNull {a -> a % 9 == 0 })
    println(list.singleOrNull {a: Int -> a % 9 == 0 })
    println(list.singleOrNull(fun(a: Int): Boolean{
        return a % 9 == 0
    }))

21、函数定义

Java:

修饰符 返回值类型 方法名([类型 参数]){
    ...
    方法体
    ...
    return 返回值;
}

java的方法必须写在类里:

class Demo{
    public int add(int a,int b){
        return a+b;
    }
}

Kotlin:


fun 函数名([参数:类型]):返回值类型{
    ...
    函数体
    ...
    [return 返回值]
}

如:

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

在Kotlin中无论有多个函数,其中必须要有一个名为main的函数,它是函数的执行入口:

fun main(args: Array<String>) {

    var sum = add(5,6)
    println(sum)
}

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

表达式作为函数体,返回类型自动推断

fun add(a: Int, b: Int): Int = a + b
// 或,不特别指出返回值类型
fun add(a: Int, b: Int) = a + b

参数带默认值的函数

fun main(args: Array<String>) {
    println(add(100))
    println(add(100,c = 200))
}
fun add(a: Int, b: Int = 100): Int{
    return a + b
}

fun add(a: Int, b: Int = 100, c: Int): Int{
    return a + b + c
}

22、可变长参数函数

Java:
在Java中可变参数必须是函数参数的列表的最后一个参数,如:


public class Main {

    public static void main(String[] args) {

        new Demo().showNum("hello world",1,3,4,5,6,75,6);
    }
}

class Demo{
    public void showNum(String name,int ...ts){
     System.out.println(name);
        for (int temp:ts) {
            System.out.println(temp);
        }
    }
}

Kotlin:
在Kotlin中可变参数不必是函数参数列表中的最后一个参数,使用vararg关键字声明可变参数,如:
注意调用方式。

fun main(args: Array<String>) {

    showNum(1,3,4,5,6,75,6,name = "hello world")
}

fun showNum(vararg ts: Int,name: String){
    println(name)
    ts.forEach { println(it) }
}

23、尾递归函数

函数的递归调用,是指在函数体内直接或间接地调用函数本身。但是在Kotlin中,尾递归函数需要使用tailrec修饰符进行标识,并且只有满足所需要格式才可调用其本身。
Java:

public class Main {

    public static void main(String[] args) {

        System.out.println(new Demo().fac(4));
    }
}

class Demo{
   public double fac(int n){
       double t = 1.0;
       if(n == 0 || n == 1){
           t = 1.0;
       }else {
           t = n * fac(n-1);
       }
       return t;
   }
}

Kotlin:

fun main(args: Array<String>) {

    println(fac(4))
}

tailrec fun fac(n: Int): Double{
    var t: Double = 1.0
    if(n == 0 || n == 1){
        t = 1.0
    }else{
        t = n * fac(n -1)
    }
    return t
}

23、高阶函数

将函数用作参数或返回值的函数称为高阶函数。
Java:
java 8引入了函数式编程。函数式编程重点在函数,函数变成了Java世界里的一等公民,函数和其他值一样,可以到处被定义,可以作为参数传入另一个函数,也可以作为函数的返回值,返回给调用者。

public class Main {

    public static void main(String[] args) {

        Lock lock = new ReentrantLock();
        int temp = new Demo().lock(lock,new Function<Integer, Integer>(){

            @Override
            public Integer apply(Integer integer) {
                return 800;
            }
        },800);
        System.out.println(temp);


    }
}

class Demo{
    public  <T,R> R lock(Lock lock, Function<T,R> body,T t){
        lock.lock(); // 锁上
        try {
            return body.apply(t);
        }
        finally {
            lock.unlock(); // 开锁
        }
    }
}

再看一个java8的高阶函数的例子:


public class Main {

    public static void main(String[] args) {

        MyFunction cube = x -> x * x * x;
        System.out.println(new Demo().sum(cube,3));


    }
}

interface MyFunction {
    int action(int a);
}

class Demo{

    public int sum(MyFunction func,int x){
        return func.action(x);
    }
   
}

@FunctionalInterface是Java 8为函数式接口引入的一个新的注解。表明该接口是函数式接口,它只包含唯一一个抽象方法。任何可以接受一个函数式接口实例的地方,都可以用lambda表达式。
**所以可以使用lambda表达式的前提是接口里只有一个抽象方法,如上例。**所以函数式接口都可以用lamda表达式来代替。加了这个注释,你就不会糊涂写多一个抽象方法。以下这些都是比较常用的函数式接口,JDK8提供的:
java.lang.Runnable,
java.awt.event.ActionListener,
java.util.Comparator,
java.util.concurrent.Callable
java.util.function包下的接口,如Consumer、Predicate、Supplier等

Kotlin:

fun main(args: Array<String>) {

    var lock = ReentrantLock() // 获取进入锁
    var temp = lock(lock,fun(): Int{
        return 800
    })
    println(temp)

}



fun <T> lock(lock: Lock,body: () -> T): T{
    lock.lock() // 锁上
    try {
        return body()
    }
    finally {
        lock.unlock() // 开锁
    }
}

24、Lambda表达式

Lambda表达式源于lambda演算。Lambda演算包括一条变换规则(变量替换)和一条函数定义方式。任何一个可计算函数都能用这种形式来表达和求值。Lambda演算强调的是变换规则的运用,而非实现它们的具体机器。Lambda表达式是定义匿名函数的简单形式,Lambda表达式避免了在抽象类和接口中编写明确的函数声明,进而避免了类的实现部分。Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。

Java:
语法
java8的lambda 表达式的语法格式如下:

(parameters) -> expression

(parameters) ->{ statements; }

示例代码:

public class Main {

    public static void main(String[] args) {

        MyFunction myFunction1 = ((x, y) -> x + y);  // 参数类型可以省略
        System.out.println(myFunction1.sum(5,6));

        MyFunction myFunction2 = (x, y) -> x + y;
        System.out.println(myFunction2.sum(5,7));

        MyFunction myFunction3 = (x, y) -> { return x + y; };  
        System.out.println(myFunction3.sum(5,8));


        MyFunction myFunction4 = (int x, int y) -> x + y;
        System.out.println(myFunction4.sum(5,9));

        MyFunction myFunction5 = ((int x, int y) -> x + y);
        System.out.println(myFunction5.sum(5,10));

        MyFunction myFunction6 = (int x, int y) -> { return x + y; };
        System.out.println(myFunction6.sum(5,11));


        MyFunction2 myFunction21 = () -> System.out.println("Hello");
        myFunction21.hello();

        
        MyFunction3 myFunction31 = (String s) -> System.out.println(s);
        myFunction31.say("Hello world");

        MyFunction3 myFunction33 = s -> System.out.println(s);  //单个参数的,可以不用括号括起来
        myFunction33.say("Hello world 33");

        MyFunction3 myFunction32 = (String s) -> { System.out.println(s); };
        myFunction32.say("Hello world");
    }
}

interface MyFunction {
    int sum(int x, int y);
}
interface MyFunction2{
    void hello();
}
interface MyFunction3{
    void say(String str);
}

Kotlin:
Kotlin中的Lambda表达式总是写在大括号内,在完整的语法形式中,将参数声明放在括号内,并有可选的类型标注,函数体位于“->“符号之后。
在Kotlin中,如果一个函数的最后一个参数是函数,并且传递一个Lambda表达式作为相应的参数,那么可以在括号外指定Lambda表达式中的值:ints.filter { it > 0 }。
如果推断出该Lambda表达式的返回类型不是Unit,那么该Lambda表达式中的最后一个


fun main(args: Array<String>) {
    // 一般常用的定义形式
    var sum = { x: Int, y: Int -> x + y }
    // 把所有的可选标注都留下,如代码如下
    var sum1: (Int, Int) -> Int = { x, y -> x + y }

    println(sum(5,5))
    println(sum1(10,10))
}

可以使用返回语句返回Lambda表达式的显式带有数据类型的值或者不显示数据类型的值,如下代码都是等价的:


fun main(args: Array<String>) {
    var list = listOf(3,5,6,7)
    println(list.filter { var flag: Boolean = it > 0; flag })
    println(list.filter { var flag = it > 0; flag })
    println(list.filter { var flag = it > 0; return@filter flag })
}

25、匿名函数

Java:
就是Java8的Lambda表达式

public class Main {

    public static void main(String[] args) {

        MyFunction myFunction1 = ((x, y) -> x + y);
        System.out.println(myFunction1.sum(5,6));

        MyFunction myFunction2 = (x, y) -> x + y;
        System.out.println(myFunction2.sum(5,7));

        MyFunction myFunction3 = (x, y) -> { return x + y; };  // 如果方法体要加{},且有返回值,则要使用return语句,其实省去更方便。
        System.out.println(myFunction3.sum(5,8));


        MyFunction myFunction4 = (int x, int y) -> x + y;
        System.out.println(myFunction4.sum(5,9));

        MyFunction myFunction5 = ((int x, int y) -> x + y);
        System.out.println(myFunction5.sum(5,10));

        MyFunction myFunction6 = (int x, int y) -> { return x + y; };
        System.out.println(myFunction6.sum(5,11));


        MyFunction2 myFunction21 = () -> System.out.println("Hello");
        myFunction21.hello();


        MyFunction3 myFunction31 = (String s) -> System.out.println(s);
        myFunction31.say("Hello world");

        MyFunction3 myFunction33 = s -> System.out.println(s);
        myFunction33.say("Hello world 33");

        MyFunction3 myFunction32 = (String s) -> { System.out.println(s); };
        myFunction32.say("Hello world");
    }
}

interface MyFunction {
    int sum(int x, int y);
}
interface MyFunction2{
    void hello();
}
interface MyFunction3{
    void say(String str);
}

Kotlin:
匿名函数看起来很象一个常规函数的声音有,除其名称活力

fun main(args: Array<String>) {

    println(sum1(8,5))
    println(sum2(8,5))
    println(sum3(8,5))


}

var sum1 = fun(x: Int, y: Int): Int = x + y // 不要加花括号{}
var sum2 = fun(x: Int, y: Int) = x + y // 不要加花括号{} 
var sum3 = fun(x: Int, y: Int): Int { return x + y }  //在函数体中需要一个return

匿名函数的参数总是在括号内传递的,允许将函数留在括号外传递仅适用于Lambda表达式。不带标签的return语句总是在使用fun关键字声明的函数中返回。意味着Lambda表达式中的return将从包含它的函数返回,而匿名函数中的return将从匿名函数自身返回。

26、内联函数

调用某个函数或方法是将程序执行顺序转移到内存中存放该函数的地址,该函数执行完后,再返回执行该函数前面的代码。这种转移操作要求在转去前要保护现场并记忆执行的地址,转回后要恢复现场,并按原来保存的地址继续执行。这就是所谓的压栈和出栈。因此函数调用会有一定时间和空间的开销,如果频繁地调用的话,这个时间和空间的开销会很大。解决性能消耗问题需要引入内联函数,在编译程序时,编译器将程序中出现的内联函数调用表达式用它的函数体中的代码直接进行替换,提供给主函数运行,因此会增加目标程序的代码量,在时间开销上,没有函数调用时大,它是以目标代码的增加为代价来换取时间的。
Java:
Java中定义内联函数的方法就是使用final修饰。

public final void a(){
    statement
}

注:final关键字只是告诉编译器,在编译的时候考虑性能的提升,可以将final函数视为内联函数。但最后编译器会怎么处理,编译器会分析将final函数处理为内联和不处理为内联的性能,然后再做决定。程序员只有建议权而没有决定权。

Kotlin:
在Kotlin中使用inline修饰符标识内联函数。使用内联函数既会影响函数本身,也会影响传递给它的Lambda表达式,这两者都会被内联到调用处。


fun main(args: Array<String>) {


    var lock = ReentrantLock()
    println(lock<Int>(lock){ 88 })

}

inline fun <T> lock(lock: Lock, body: () -> T): T{
    lock.lock()
    try {
        return body()
    }
    finally {
        lock.unlock()
    }
}

27、类

Java:

class MyClass{} // 简单的类

Kotlin:
Kotlin通过class关键字来声明类,类由构造函数和初始化模块、函数、属性、嵌套类和内部类、对象声明5部分组成。

class MyClass{} // 简单的类
class MyAnotherClass   // 仅有类的骨架,而没有什么功能实现

28、类的成员属性

Java:
java的访问修饰符:public、protected、private,也可以缺省(即不带访问修饰符)。

修饰符 可见性
public 所有可见
protected 在子类可见、同一包中的类可见、本类内可见
private 类内部可见
default(缺省) 同一包中的类可见、本类内可见

java没有存储类型修饰符。
定义成员变量:

关键词  数据类型 成员变量名 = 默认值
private String name = "Tome";

Kotlin:
类的变量称为成员变量,必须在使用前声明,要声明数据类型、访问属性、存储方式。
访问修饰符:public、protected、private、internal,也可以缺省(即不带访问修饰符)
存储类型修饰符:open、override、const。

修饰符 可见性
public(默认) 所有可见
protected 在子类可见
private 类内部可见
internal 模块可见

被open修饰的成员变量,表示该成员变量可以被继承,否则不能被继承。
被const修饰的成员变量称为常成员变量。
在kotlin中,类中的方法也是final类型,是不能被重写的,也需在方法前面加上open关键字后才可以;子类要重写父类中open修饰的方法,需在子类的方法前面加override关键字。

定义成员变量:

关键词  成员变量名[数据类型] = 默认值
private var name: String = "Tome"

访问方法:
对象名.成员变量

29、成员方法

Java:
访问修饰符:public、protected、private、也可以缺省(即不带访问修饰符)
存储类型修饰符:没有

   public int sum(int x, int y){
      return x + y;
     }
    

Kotlin:
函数与成员方法的唯一区别就是函数实现的是某个苳的功能,而成员方法实现的是类的行为,是类的一部分。
访问修饰符:public、protected、private、internal,也可以缺省(即不带访问修饰符)
存储类型修饰符:open、override。

定义成员方法:

fun 方法名 (属性列表) {  方法体  }

如果一个类中的成员方法没有加任何修饰符,那么该方法就是final类型的,这种方法默认不允许被子类继承的。如果允许被子类继承,那么需要在该类的方法前加open修饰符。
demo:


    fun sum(x: Int, y: Int): Int{
        return x + y
    }

注意:所有没有加存储类型修饰符的class、成员变量、成员方法默认都是final的不能被继承的,如果class要被继承,首先应该用open修饰,如:

open class MyClass{}

然后,允许被继承的成员变量、成员方法都要用open修饰。

30、构造函数

Java:

class Student {
    private String username = "";
    private String hobby = "";

    public Student() {
    }

    public Student(String username, String hobby) {
        this.username = username;
        this.hobby = hobby;
    }
}

Kotlin:
当我们定义一个类时,如果没有为其显式提供Primary Constructor,Kotlin编译器会默认为其生成一个无参主构造函数,这点和Java是一样的。
Kotlin的构造函数分为主构造器(primary constructor)和次级构造器(secondary constructor),次级构造器可以有多个:

class 类名 constructor(形参1, 形参2, 形参3){}

class Student constructor(username: String, hobby: String){
     var username: String = ""
     var hobby: String = ""

    init{
        this.username = username
        this.hobby = hobby
    }
}

关键字constructor:在Java中,构造方法名须和类名相同;而在Kotlin中,是通过constructor关键字来标明的,且对于Primary Constructor而言,它的位置是在类的首部(class header)而不是在类体中(class body)。
关键字init:init{}它被称作是初始化代码块(Initializer Block),它是为Primary Constructor服务的,由于Primary Constructor是放置在类的首部,是不能包含任何初始化执行语句的,这是语法规定的,那么这个时候就有了init的用武之地,我们可以把初始化执行语句放置在此处,为属性进行赋值。

当constructor关键字有注解或可见性修饰符作用于它时,constructor关键字是不可以省略,如:

 class Student private constructor(username: String, hobby: String){
     var username: String = ""
     var hobby: String = ""

    init{
        this.username = username
        this.hobby = hobby
    }
     constructor(name: String): this(name,"tennis"){
         println("我是次构造函数")
     }
}

当constructor关键字没有注解和可见性修饰符作用于它时,constructor关键字可以省略,那么上面的代码就变成:

class Student (username: String, hobby: String){
     var username: String = ""
     var hobby: String = ""

    init{
        this.username = username
        this.hobby = hobby
    }
}

初始化执行语句不是必须放置在init块中的,我们可以在定义属性时直接将主构造器中的形参赋值给它。

class Student constructor(username: String, hobby: String){
     var username: String = username
     var hobby: String = hobby
}class Student (username: String, hobby: String){
     var username: String = username
     var hobby: String = hobby
}

这种在主构造器中声明形参,然后在属性定义进行赋值,还可以进一步简化:我们可以直接在Primary Constructor中定义类的属性:

 class Student constructor(public var username: String, public var hobby: String){}class Student (public var username: String, public var hobby: String){}

如果类不包含其他操作函数,那么连花括号也可以省略:

 class Student constructor(public var username: String, public var hobby: String)class Student (public var username: String, public var hobby: String)

和主构造函数相比,很明显的一点,次级构造函数是定义在类体中。次级构造函数可以有多个,而主构造函数只会有一个。
我们可以使用this关键字来调用自己的其他构造函数,它的语法形式,次级构造器: this(参数列表)
可以使用super关键字来调用父类构造器,它的语法形式,次级构造器: super(参数列表)。:

class Student constructor(username: String, hobby: String){
     var username: String = ""
     var hobby: String = ""

    init{
        this.username = username
        this.hobby = hobby
    }
     constructor(name: String): this(name,"tennis"){
         println("我是次构造函数")
     }
}class Student (username: String, hobby: String){
     var username: String = ""
     var hobby: String = ""

    init{
        this.username = username
        this.hobby = hobby
    }
     constructor(name: String): this(name,"tennis"){
         println("我是次构造函数")
     }
}

31、继承

Java:
只支持单继承

// 父类
class Base{
    public Base(){}
    public Base(String name){}
}
// 子类
class SonClass1 extends Base {
    public SonClass1(){
        super();
    }
    public SonClass1(String name){
        super(name);
    }
}

Kotlin:
只支持单继承
在Kotlin中每一个类都有一个共同的父类Any,没有显示声明父类的话Any就是它的默认父类。Any中只有 equals()、hashCode()和toString():

public open class Any {

    public open operator fun equals(other: Any?): Boolean

    public open fun hashCode(): Int

    public open fun toString(): String
}

继承一个父类使用冒号来表示,如果子类有主构造函数,父类则必须使用主构造函数初始化:


// 父类
open class Base(name: String){

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

    ...
}

class SonClass1(name: String): Base(name){...}
class SonClass2(name: String, age: Int, hobby: String): Base(name){...}

如果子类没有主构造函数,子类的次构造函数都必须绑定父类的构造函数(主次都行)。可以绑定同一个,也可以不同:

// 父类
open class Base(name: String) {

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


}
// 子类
class SonClass1 : Base {

    constructor(name: String) : super(name) {}
    constructor(name: String, age: Int) : super(name, age) {}
    constructor(name: String, age: Int, sex: String) : super(name) {}
}

如果父类没有定义构造方法时,我们要初始化它的默认主构造方法:

// 父类
open class Base{}
// 如果子类有定义构造函数,则在构造函数绑定父类的默认构造函数
class SonClass1: Base {

    constructor(name: String) : super() {}
    constructor(name: String, age: Int) : super() {}
    constructor(name: String, age: Int, sex: String) : super() {}
}

// 如果子类没有定义构造函数,则在类头绑定父类的默认构造函数
class SonClass2: Base() {}

32、覆盖方法、属性、规则

Java:
覆盖方法:

// 父类
class Base{
    public void method(){}
}

// 子类
class Example extends Base{
    @Override
    public void method() {
        super.method();
    }
}

覆盖属性:
java只是在子类重新定义属性。

// 父类
class Base{
    public boolean attr = false;
}

// 子类
class Example extends Base{
   public boolean attr = true;
}

覆盖规则

// 接口
interface BaseInterface {
    public void method();

    default public void method1() {
        System.out.println("BaseInterface::method1:hello");
    }

    static public void method2() {
        System.out.println("BaseInterface::method2:hello");
    }

}

// 父类
class Base {
    public void method() {
        System.out.println("Base::Hello");
    }
}

// 子类
class Example extends Base implements BaseInterface {

    @Override
    public void method() {
        this.method1();
        BaseInterface.method2();
        super.method();
    }

}

Kotlin:
Kotlin中,只有被open 标注的成员才可以被覆盖,且覆盖后的成员必须用 override 标注。否则编译将失败。

override标注的成员也可以被覆盖,如果不想再被覆盖的话使用 final 修饰

final  override var a = ..

覆盖方法:

// 父类
open class Base{
    open fun method(){}
}

// 子类
class Example: Base(){
    override fun method() {
        super.method()
    }
}

覆盖属性:

覆盖属性与覆盖方法类似。可以用 val 修饰的属性覆盖 var 修饰的属性,但是不可以用 var 修饰的属性去覆盖 val 。因为一个 val 属性本质上声明了一个 getter 方法,而将其覆盖为 var 只是在子类中额外声明一个 setter 方法。

//父类
open class Base {
   open var attr: Boolean = false
}   

//子类
class Example : Base() {
    override var attr: Boolean = true
}

也可以在主构造函数中去覆盖属性

// 子类
class Example(override var attr: Boolean): Base(){}

覆盖规则:
子类继承父类并实现了接口时,如果有相同的函数时我们可以使用super< ? >指定要调用的父类或接口的函数


// 接口
interface BaseInterface{
    public fun method(){
        println("BaseInterface::method:hello")
    }
    public fun method1()
}
// 父类
open class Base{
    open fun method(){
        println("Base::Hello")
    }
}

// 子类
class Example: Base(),BaseInterface{
    override fun method1() {
        println("BaseInterface::method1:Hello")
    }

    override fun method() {
        super<BaseInterface>.method()
        super<Base>.method()
    }
}

33、内部类与嵌套类

Java:

public class Main {

    public static void main(String[] args) {

        OutterClass.NestedClass nestedclass = new OutterClass.NestedClass();
        nestedclass.method();
        OutterClass outterClass = new OutterClass();
        outterClass.method();

    }
}


class OutterClass {
    static class NestedClass { // 静态内部类,不仅可以在内部使用,还可以在外部使用
        public void method() {
            System.out.println("NestedClass::Method:Hello");
        }
    }

    class InnerClass {  // 内部类只能在内部使用
        public void  method(){
            System.out.println("InnerClass::Method:Hello");
        }

    }

    public void method() {
        InnerClass innerClass = new InnerClass();
        innerClass.method();
    }

}

Kotlin:


fun main(args: Array<String>) {

    var nestedclass = OutterClass.NestedClass()
    var outterClass = OutterClass()
    outterClass.method()
}

class OutterClass{
    class NestedClass{ // 嵌套类,不仅可以在内部使用,还可以在外部使用,类似于Java的静态内部类
        fun method(){
            println("NestedClass::Method:Hello")        }
    }


    inner class InnerClass{  // 内部类只能在内部使用
        fun method() = println("InnerClass::Method:Hello")
    }

    fun method(){
        var innerClass = InnerClass()
        innerClass.method()
    }

}

34、匿名内部类

Java:
所谓的匿名内部类就是一个没有显式的名字的内部类,匿名内部类会隐式的继承一个类或者实现一个接口,或者说,匿名内部类是一个继承了该类或者实现了该接口的子类匿名对象。

public class Main {

    public static void main(String[] args) {

        Example example = new Example();
        example.testInterface(new BaseInterface() { // 利用接口产生匿名类
            @Override
            public void method() {
                System.out.println("Test Test Test Interface");
            }
        });

        example.testInterface(()-> System.out.println("Test Test Test Lambda")); // 使用Lambda表达式产生匿名类

        example.testAbstractClass(new Base() { // 利用抽象类来创建匿名类
            @Override
            public void method() {
                System.out.println("Test Test Test abstract class");

            }
        });


    }
}

interface BaseInterface{
    public void method();
}

abstract class Base{
    abstract public void method();
}

class Example{
    public void testInterface(BaseInterface baseInterface){ // 利用接口产生匿名类
        baseInterface.method();
    }
    public void testAbstractClass(Base base){  // 利用抽象类来创建匿名类
        base.method();
    }
}

Kotlin:


fun main(args: Array<String>) {
    val example = Example()
    example.testInterface(object : BaseInterface { // 利用接口产生匿名类
        override fun method() {
            println("Test Test Test Interface")
        }
    })


    example.testAbstractClass(object : Base(){ // 利用抽象类产生匿名类
        override fun method() {
            println("test test abstract class ")
        }

    })


    example.test { println("I am just fun ") }


}

interface BaseInterface {
    fun method()
}

abstract class Base {
    abstract fun method()
}

class Example {
    fun testInterface(baseInterface: BaseInterface): Unit { // 利用接口产生匿名类
        baseInterface.method()
    }

    fun testAbstractClass(base: Base) {  // 利用抽象类来创建匿名类
        base.method()
    }

    fun test(body: ()->Unit){
        body()
    }
}

35、数据类

Java:
在java中的数据类其实就是一般说的实体类、Bean类:

class MyData{
    private int id;
    private String name;
    private String dec;

    public String getDec() {
        return dec;
    }

    public void setDec(String dec) {
        this.dec = dec;
    }

    public String getName() {
        return name;
    }

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

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }
}

Kotlin:
Kotlin 可以创建一个只包含数据的类,关键字为 data,格式如下:

data class 类名(属性列表)

一般数据类中不应该有方法,所以将变量放在属性列表中,把大括号去掉,如:

data class MyData(var id: Int = 0, var name: String? = null, var dec: String? = null)

运行实例如下:

fun main(args: Array<String>) {

    val myData = MyData(10,"Tom","an engineer")
    println("${myData.name} is ${myData.dec}")

}

36、枚举类

Java:
Java中的枚举类用enum代替class声明,每一个枚举值对应一个类的实例


public class Main {

    public static void main(String[] args) {

        System.out.println(ServerState.BAD_GATEWAY);
        System.out.println(ServerState.BAD_GATEWAY.getCode());
        System.out.println(ServerState.BAD_GATEWAY.getMsg());
        System.out.println(ServerState1.BAD_GATEWAY);
    }
}

enum ServerState{
    ERROR_SERVER(500, "服务器异常"),
    BAD_GATEWAY(502, "服务器异常"),
    NOT_SERVER(404, "页面不存在"),
    TOKEN_INVALID(40101, "登录状态失效"),
    ERROR_PROXY_FIDDLER(502, "fiddler代理失败");   // 必须提供相应的构造函数,才能构造这种类型的枚举

    private int code;
    private String msg;

    ServerState(int code,String msg){  // 构造函数默认是private的
        this.code = code;
        this.msg = msg;
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }
}

enum ServerState1{
    ERROR_SERVER,
    BAD_GATEWAY,
    NOT_SERVER,
    TOKEN_INVALID,
    ERROR_PROXY_FIDDLER;

    // 有默认的构造方法 private ServerState1(){}
}

Kotlin:

枚举类最基本的用法是实现一个类型安全的枚举。
枚举常量用逗号分隔,每个枚举常量都是一个对象。


fun main(args: Array<String>) {


    println(ServerState.BAD_GATEWAY)
    println(ServerState.BAD_GATEWAY.code)
    println(ServerState.BAD_GATEWAY.msg)
    println(ServerState1.BAD_GATEWAY)

    println(ServerState.valueOf("ERROR_SERVER"))
    val serverStates = ServerState.values()
    println("####")
    for (serverState in serverStates) {
        println(serverState)
    }
}

// 必须提供相应的构造函数,才能构造这种类型的枚举
enum class ServerState private constructor(var code: Int, var msg: String?)// 构造函数默认是private的
{
    ERROR_SERVER(500, "服务器异常"),
    BAD_GATEWAY(502, "服务器异常"),
    NOT_SERVER(404, "页面不存在"),
    TOKEN_INVALID(40101, "登录状态失效"),
    ERROR_PROXY_FIDDLER(502, "fiddler代理失败")
}

internal enum class ServerState1 {
    ERROR_SERVER,
    BAD_GATEWAY,
    NOT_SERVER,
    TOKEN_INVALID,
    ERROR_PROXY_FIDDLER

    // 有默认的构造方法 private ServerState1(){}
}

37、密封类

Java:
Java里没有这个概念。
Kotlin:
密封类需要使用sealed关键字修饰,并且被sealed关键字修饰的类,它的子类必须要以嵌套类的形式在父类中全部声明。
sealed 不能修饰 interface ,abstract class(会报 warning,但是不会出现编译错误)

fun main(args: Array<String>) {

    var sonClass1 = SealedClass.SonClass1()
    println(check(sonClass1))
}

sealed class SealedClass {
    class SonClass1 : SealedClass() {}

    class SonClass2 : SealedClass() {}

    class SonClass3 : SealedClass() {}
}


fun check(sealedClass: SealedClass): Int =
    when (sealedClass) {
        is SealedClass.SonClass1 -> 1
        is SealedClass.SonClass2 -> 2
        is SealedClass.SonClass3 -> 3
    }

再来看多一个密封类的实例:

sealed class Expr // 密封类

data class Const(val number: Double) : Expr() // 密封类的子类
data class Sum(val e1: Expr, val e2: Expr) : Expr() // 密封类的子类
object NotANumber : Expr() // 密封类的子类

fun eval(expr: Expr): Double = when(expr){
    is Const -> expr.number
    is Sum -> eval(expr.e1) + eval(expr.e2)
    NotANumber -> Double.NaN
}

fun main(args: Array<String>) {

    val constVar = Const(888.0)
    println(eval(constVar))
    val sumVar = Sum(Const(10.0), Const(10.0))
    println(eval(sumVar))

}

38、对象表达式

Java:
没有
Kotlin:
通过object来声明。

interface BaseInterface {
    public fun method()
}

abstract class Base {
    public abstract fun method()
}

fun invokeMe(inter: BaseInterface) {
    inter.method()
}

fun invokeA(base: Base){
    base.method()
}

fun main(args: Array<String>) {
    // 对象表达式
    invokeMe(object : BaseInterface { // 通过对象表达式实现一个匿名内部类的对象用于方法的参数中
        override fun method() {
            println("BaseInterface::Hello Object")
        }

    })
    // 对象表达式
    invokeA(object :Base(){  // 通过对象表达式实现一个匿名内部类的对象用于方法的参数中
        override fun method() {
            println("Base::Hello Object")

        }

    })

}

如果仅需要一个对象来包住某些东西如变量和一些方法的话,可以这样做:


fun main(args: Array<String>) {

    // 对象表达式
    var myObject = object {
        var name: String = "wongkyunban"
        var height: Int = 180
        fun sayHi(){
            println("Hello,everyone,I am $name")
        }
    }
    println(myObject.name)
    println(myObject.sayHi())
  }

对象可以继承于某个基类,或者实现其他接口:

// 如果对于将要创建的类实例,与类模板有一些细小的差别,又不想继承这个类,在子类里重写有差别的部分,可以通过对象表达式来完成。如

public open class A(x: Int){
    public open var x: Int = x
    public open var name: String = "AAA"
    fun hi(){
        println("hi,$name,$x")
    }

}

interface AA{

    fun speak(str: String){
        println(str)
    }

    fun haha(){
        println("haha")
    }

}
fun main(args: Array<String>) {

    var myA = object: A(10),AA{ // 如果超类有构造函数,几必须传递适当的参数给它,后面只能跟一个类,其他的都是接口
        override var name: String = "Wongkyunban"  // 这就是我将要将创建的对象与类有区别的地方,如果继承重写的话,代码就要写很多,也比较不方便

        override fun speak(str: String) {
            println("I am $str")
        }
    }
    myA.hi()
    myA.speak("Chinese")

}

39、单例类

Java:

// 懒汉式
public class LazySingleton {
    private static LazySingleton singleton = null;

    private LazySingleton() {
    }

    public static LazySingleton getSingleton() {
        if (singleton == null) singleton = new LazySingleton();
        return singleton;
    }
}

// 饿汉式
class HungrySingleton {
    private static HungrySingleton ourInstance = new HungrySingleton();

    private HungrySingleton() {
    }

    public static HungrySingleton getInstance() {
        return ourInstance;
    }


}

Kotlin:
在Kotlin中使用单例模式来声明一个对象会变得更加容易。声明对象和声明变量一样,对象声明并不是一个表达式,所以不能使用赋值语句进行赋值操作。对象声明一般是在object后面加上对象名称

class Student()
object Singleton{
    var all = arrayListOf<Student>()
    fun show(){
        for (student in all){
            println(student.toString())
        }
    }
}

fun main(args: Array<String>) {

    Singleton.all.add(Student())
    Singleton.all.add(Student())
    Singleton.all.add(Student())

    Singleton.show()
}

40、顶层函数

在Kotlin文件里直接定义的函数就是顶层函数,它不是定义在类中的。

41、中缀调用

如下列中的to就是中缀调用。

    var map1: Map<String, String> = hashMapOf("key1" to "value1","key2" to "value2")
    // 与下面是等价
    var map1: Map<String, String> = hashMapOf("key1".to("value1"),"key2".to("value2"))


它的原型是这样的:

public infix fun <A, B> A.to(that: B): Pair<A, B> = Pair(this, that)

42、伴生对象

Java:

Kotlin:
Kotlin中的类不能有静态成员,Java中的static关键字不属于Kotlin的一部分。虽然Kotlin可以通过包 函数和对象声明来实现static功能。 在大多数情况下,使用顶层函数,但是顶层函数不能访问类中的private成员。
Kotlin允许在类中使用 companion object创建伴生对象,用伴生对象的成员来代表Kotlin中的静态成员。伴生对象看起来就像Java中的静态成员。

class A{
    companion object MyFactory{
        fun create(): A = A()
        fun bye(){
            println("Bye Bye")
        }
     const val TAG: String = "A"

    }

    fun show(){
        println("Hello world AAA")
    }
}

fun main(args: Array<String>) {

    var a = A.create()
    a.show()
    A.bye()
    A.MyFactory.bye()
    println(A.tag)
}

在使用companion关键字时,伴生对象的名称可以省略不写,因此上面的代码可以改成:

class A{
    companion object {
        fun create(): A = A()
        fun bye(){
            println("Bye Bye")
        }
        const val TAG: String = "A"

    }

    fun show(){
        println("Hello world AAA")
    }
}

fun main(args: Array) {

    var a = A.create()
    a.show()
    A.bye()
    println(A.TAG)
}

伴生对象还可以实现接口:

interface BaseFactory<T>{
    fun myCreate(): T
}

class A{
    companion object: BaseFactory<A> {
        override fun myCreate(): A = A()
        
        fun bye(){
            println("Bye Bye")
        }
        const val TAG: String = "A"

    }

    fun show(){
        println("Hello world AAA")
    }
}

fun main(args: Array<String>) {

    var a = A.myCreate()
    a.show()
    A.bye()
    println(A.TAG)
}

43、泛型类

泛型,即 “参数化类型”,将类型参数化,可以用在类,接口,方法上。提高代码的重用性和程序安全性。
与 Java 一样,Kotlin 也提供泛型,为类型安全提供保证,消除类型强转的烦恼。
泛型类的声明和非泛型类的声明类似,泛型接口只是多了在类名后面添加了类型参数声明部分
Java:

// 声明一个泛型类
class Box<T> {

    private T t;

    public void add(T t) {
        this.t = t;
    }

    public T get() {
        return t;
    }
}

public class Main {

    public static void main(String[] args) {
        Box<String> stringBox = new Box<>();
        stringBox.add("Hello world");
        System.out.println(stringBox.get());
    }
}

Kotlin:

// 声明一个泛型类
class Box<T> {

    private var t: T? = null

    fun add(t: T) {
        this.t = t
    }

    fun get(): T? {
        return t
    }
}

fun main(args: Array<String>) {
    val stringBox = Box<String>()
    stringBox.add("Hello world")
    println(stringBox.get())
}

44、泛型接口

泛型接口的声明和非泛型接口的声明类似,泛型接口只是多了在接口名后面添加了类型参数声明部分
Java:

// 声明一个泛型接口

interface Base<T>{
    void add(T t);
}
public class Main {

    public static void main(String[] args) {

       Base<String> stringBase = new Base<String>() {
           @Override
           public void add(String s) {
               System.out.println(s);
           }
       };
       stringBase.add("add Hello world");

    }
}

Kotlin:

// 声明一个泛型接口

interface Base<T> {
   fun add(t: T)
}

fun main(args: Array<String>) {
   val stringBase = object : Base<String> {
       override fun add(s: String) {
           println(s)
       }
   }
   stringBase.add("add Hello world")
}

45、泛型方法

泛型方法的声明和非泛型方法的声明类似,泛型方法只是多了在方法名前面添加了类型参数声明部分
Java:

// 声明一个泛型方法

class Base{
    public <T> void show(T t){
        if( t instanceof String){
            System.out.println(t);
        }
    }

    public <T> T get(T t){
        return t;
    }
}

public class Main {

    public static void main(String[] args) {

       Base base = new Base();
       System.out.println(base.get(9999));
       base.show("Hello world 999");

    }
}

Kotlin:

// 声明一个泛型方法

fun <T> show(t: T) {
    if (t is String) {
        println(t)
    }
}

fun <T> get(t: T): T {
    return t
}

fun main(args: Array<String>) {
    show("Hello world 999")
    println(get(8888))
}

46、泛型中的通配符

Java:
当操作的不同容器中的类型都不确定的时候,而且使用的元素都是从Object类中继承的方法,这时泛型就用通配符“?”来表示。泛型的通配符:“?” 相当于 “? extends Object”,如:

        //使用通配符
        ArrayList<?> arr2;
        arr2 = new ArrayList<String>();
        arr2 = new ArrayList<Integer>();

Kotlin:
在Kotlin里是用*号

    //使用通配符
    var arr2: ArrayList<*>
    arr2 = ArrayList<String>()
    arr2 = ArrayList<Int>()

47、泛型限定

Java:
泛型限定就是对操作的数据类型限定在一个范围之内。限定分为上限和下限。
上限:? extends E 接收E类型或E的子类型
下限:? super E 接收E类型或E的父类型
限定用法和泛型方法,泛型类用法一样,在“<>”中表达即可。
一个类型变量或通配符可以有多个限定,多个限定用“&”分隔开,且限定中最多只能有一个类,但可以有多个接口;如果有类限定,类限定必须放在限定列表的最前面。如:T extends MyClass1 & MyInterface1 & MyInterface2

// 声明一个泛型限定  ? super  和 ? extends

class Base{}
class SonClass extends Base{}

class Demo1 {
   public static <T> void copy(List<? super T> dest, List<? extends T> src) {
       int srcSize = src.size();
       if (srcSize > dest.size())
           throw new IndexOutOfBoundsException("Source does not fit in dest");

       for (int i = 0; i < srcSize; i++) {
           dest.add(i,src.get(i));
       }

   }
}

public class Main {

   public static void main(String[] args) {
       List<Base>  list1 = new ArrayList<>();
       list1.add(new Base());
       list1.add(new Base());

       // 或  因为 Object是Base的父类
//        List  list1 = new ArrayList<>();
//        list1.add(new Base());
//        list1.add(new Base());

       List<SonClass>  list2 = new ArrayList<>();
       list2.add(new SonClass());
       list2.add(new SonClass());
       Demo1.copy(list1,list2);
       for (Base son: list1) {
           if(son instanceof SonClass){
               System.out.println("SonClass");
           }
       }
   }
}

 
  

Kotlin:
Kotlin 中使用 : 对泛型的的类型上限进行约束。最常见的约束是上限(upper bound),默认的上界是 Any?,对于多个上限约束条件,可以用 where 子句(在Java中使用&):

fun <T> copyWhenGreater(list: List<T>, threshold: T): List<String>
    where T : CharSequence,
          T : Comparable<T> {
    return list.filter { it > threshold }.map { it.toString() }
}

上面Java代码对应的Kotlin泛型限定如下:


// 声明一个泛型限定  ? super  和 ? extends

open class Base

class SonClass : Base()

object Demo1 {
    fun <T> copy(dest: MutableList<in T>, src: List<T>) {
        val srcSize = src.size
        if (srcSize > dest.size)
            throw IndexOutOfBoundsException("Source does not fit in dest")

        for (i in 0 until srcSize) {
            dest.add(i, src[i])
        }

    }
}
fun main(args: Array<String>) {


    val list1 = ArrayList<Base>()
    list1.add(Base())
    list1.add(Base())


    // 或  因为 Object是Base的父类
//        List  list1 = new ArrayList<>();
//        list1.add(new Base());
//        list1.add(new Base());


    val list2 = ArrayList<SonClass>()

    list2.add(SonClass())
    list2.add(SonClass())

    Demo1.copy(list1, list2)

    for (son in list1) {
        if (son is SonClass) {
            println("SonClass")
        }

    }

}

 
  

Kotlin 中没有通配符类型,它有两个其他的东西:声明处型变(declaration-site variance)与类型投影(type projections)。

声明处型变
声明处的类型变异使用协变注解修饰符:in、out,消费者 in, 生产者 out。
使用 out 使得一个类型参数协变,协变类型参数只能用作输出,可以作为返回值类型但是无法作为入参的类型。

class Boob<out T>(val a: T) {
    fun foo(): T {  // T能作为返回值类型,但不能作为入参类型
        return a
    }

   // T不能作为入参类型,所以以下函数是错误的 
   // fun foo(b: T) {}
    
}

fun main(args: Array<String>) {
    var strBo: Boob<String> = Boob<String>("Hello")
    var anyBo: Boob<Any> = Boob<Any>("world")
    // 如果Boob类不支持型变,就会报如下错:
    // Type mismatch
    // Required:Boob
    // Found:   Boob
    anyBo = strBo  
    println(anyBo.foo())
}

in 使得一个类型参数逆变,逆变类型参数只能用作输入,可以作为入参的类型但是无法作为返回值的类型。它使得一个类型参数逆变。


class Boob<in T>(a: T) {
    // T不能作为返回值类型
//    fun foo(): T { 
//        return a
//    }

   // T能作为入参类型,但不能作为返回值类型
    fun foo(b: T) {}

}

fun main(args: Array<String>) {
    var strBo: Boob<String> = Boob<String>("Hello")
    var anyBo: Boob<Any> = Boob<Any>("world")
    strBo = anyBo
}

48、kotlin 委托

委托模式是软件设计模式中的一项基本技巧。在委托模式中,有两个对象参与处理同一个请求,接受请求的对象将请求委托给另一个对象来处理。

Kotlin 直接支持委托模式,更加优雅,简洁。Kotlin 通过关键字 by 实现委托

类委托
类的委托即一个类中定义的方法实际是调用另一个类的对象的方法来实现的。


// 创建接口
interface Base{
    fun print()
}

// 实现接口
class BaseImpl(val x: Int):Base{
    override fun print() {
        println(x)
    }

}

// 通过by关键字建立委托类
class Entrust(b: Base):Base by b   //by 子句表示,将 b 保存在 Entrust的对象实例内部,而且编译器将会生成继承自 Base 接口的所有方法, 并将调用转发给 b

fun main(args: Array<String>) {
    val b = BaseImpl(100)
    var byClass = Entrust(b)
    byClass.print()
}

属性委托
属性委托指的是一个类的某个属性值不是在类中直接进行定义,而是将其托付给一个代理类,从而实现对该类的属性统一管理。
属性委托语法格式:

// 表达式指的是委托代理类
val/var <属性名>: <类型> by <表达式>

by 关键字之后的表达式就是委托, 属性的 get() 方法(以及set() 方法)将被委托给这个对象的 getValue() 和 setValue() 方法。属性委托不必实现任何接口, 但必须提供 getValue() 函数(对于 var属性,还需要 setValue() 函数)。

// 委托的类
class Entrust{

    // 重载操作符的函数需要用operator关键字标记


    // thisRef参数用于读出p的对象,property参数保存了对p自身的描述,如可取它的名字
    // thisRef参数类型必须与属性的所有者的类型相同或是它的超类型
    // property参数类型必须是KProperty<*>或是它的超类型
    operator fun getValue(thisRef: Any?, property: KProperty<*>): String{
        return "$thisRef, 这里委托了 ${property.name} 属性"
    }

    // thisRef参数用于读出p的对象,property参数保存了对p自身的描述,如可取它的名字,value参数保存了将要被赋予的值
    // thisRef参数类型必须与属性的所有者的类型相同或是它的超类型
    // property参数类型必须是KProperty<*>或是它的超类型
    // value参数类型必须与属性的类型相同或是它的超类型
    operator fun setValue(thisRef: Any?,property: KProperty<*>,value: String){
        println("$thisRef 的 ${property.name} 属性赋值为 $value")
    }
}


// 定义包含属性委托的类
class Example{
    var p: String by Entrust()
}
fun main(args: Array<String>) {
    val e = Example()
    // 当我们从委托到一个Entrust实例的p读取时,将调用Entrust中的getValue()方法
    println(e.p)

    // 当给p赋值时,将调用Entrust中的setValue()方法

    e.p = "Hello world"
    println(e.p)
}

49、标准委托

Kotlin 的标准库中已经内置了很多工厂方法来实现属性的委托。
延迟属性 Lazy
lazy() 函数接受一个 Lambda 表达式作为参数, 返回一个 Lazy 实例,返回的实例可以作为实现延迟属性的委托: 第一次调用 get() 会执行已传递给 lazy() 的 lamda 表达式并记录结果, 后续调用 get() 只是返回记录的结果。


fun main(args: Array<String>) {
    val lazyValue: String by lazy {
        println("computed!")     // 第一次调用输出,第二次调用不执行
        "Hello world"
    }

    println(lazyValue)
    println(lazyValue)
}

可观察属性 Observable
observable 可以用于实现观察者模式。
Delegates.observable() 函数接受两个参数: 第一个是初始化值, 第二个是属性值变化事件的响应器(handler)。
在属性赋值后会执行事件的响应器(handler),它有三个参数:被赋值的属性、旧值和新值:

    var name: String by Delegates.observable("Hello"){
        prop,old,new ->
        println("old value:$old -> new value:$new")
    }

    name = "I Love the world"
    name = "I am coming"

把属性储存在映射中
一个常见的用例是在一个映射(map)里存储属性的值。 这经常出现在像解析 JSON 或者做其他"动态"事情的应用中。 在这种情况下,可以使用映射实例自身作为委托来实现委托属性。

fun main(args: Array<String>) {

    // 构造函数接受一个映射参数
    val site = Site(mapOf(
        "name" to "百度",
        "url"  to "www.baidu.com"
    ))

    println(site.name)
    println(site.url)

}

class Site(val map: Map<String,Any?>){
    val name: String by map
    val url: String by map
}
//  不是每个实例自身都可以作为委托来实现委托属性,如下代码,因为Int类型没有getValue(MySite, 
// KProperty<*>)' method on delegate of type 'Int',所以它不能拿来委托
// class MySite(val a: Int){
//    val b: Int by a
//}


Not Null
notNull 适用于那些无法在初始化阶段就确定属性值的场合。

class Demo{
    var notNullValue: String by Delegates.notNull<String>()
}

fun main(args: Array<String>) {

      var demo = Demo()

    // println(demo.notNullValue)  如果属性在赋值前就被访问的话则会抛出异常

    demo.notNullValue = "Hello world"

    println(demo.notNullValue)


}

50、局部委托属性

可以将局部变量声明为委托属性


class Foo {
    fun doAction() {
        println("hello world")
    }
}

fun foo(add: () -> Foo) {
    //memoizedFoo 变量只会在第一次访问时计算
    val memoizedAddFunc by lazy(add)
    memoizedAddFunc.doAction()
}

fun main(args: Array<String>) {


    foo { Foo() }

}

51、翻译规则

在每个委托属性的实现的背后,Kotlin 编译器都会生成辅助属性并委托给它。 例如,对于属性 prop,生成隐藏属性 prop$delegate,而访问器的代码只是简单地委托给这个附加属性:

class Example{
    var prop: String by Entrust()
}

// 这段是由编译器生成的相应代码:
class Example {
    private val prop$delegate = Entrust()
    var prop: String
        get() = prop$delegate.getValue(this, this::prop)
        set(value: String) = prop$delegate.setValue(this, this::prop, value)
}

52、提供委托

暂缺

53、扩展函数

与定义一般的函数很像,区别在于需要在添加的函数名字之前放置想要扩展的类或者接口的类型。这个类或接口叫做接收器类型(receiver type)。

// 给String类扩展一个函数,名叫mylastChar()
fun String.mylastChar(): Char = this.get(this.length - 1 )


fun main(args: Array<String>) {
    var str: String = "Hello World"
    // 调用我们扩展出来的函数mylastChar()
    println(str.mylastChar())
    println("bye bye".mylastChar()) 
}

54、with的用法

class MyData{
    var name: String? = null
    var age: Int? = null
}


fun main(args: Array<String>) {
    var data = MyData()
    with(data){
        name = "Tom"
        age = 28
    }
    println(data.name)
    println(data.age)
}

谢谢阅读。如果错误,请给我留言。

你可能感兴趣的:(Kotlin)