Java快速转Kotlin

1,347 阅读15分钟

一:变量的声明跟赋值

Java:

public View mTvName;
public String name="chencm";
public final int age = 1;

Kotlin:

var mTvName:View?=null
var name:String = "chencm" //var修饰参数可读可写,如果要修改值 直接name="cc"
var name = "chencm" // 像这种在声明变量的时候直接赋值,可以不写变量类型,这个是Kotlin的类型推断
val age = 1 
lateinit var mHeadView:View //如果不想马上初始化,就可以使用lateinit

几点不同讲解:

  • kotlin默认是public的,可以省略
  • kotlin里声明变量使用var,val关键字
  • kotlin变量名在前,变量类型在后,java则相反
  • kotlin里变量名跟类型之间用“:”冒号隔开
  • kotlin里变量必须要有初始化的值,java有默认
  • kotlin末尾不需要写“;”分号

var修饰的变量是可读可写变量,比如上面的代码修改name的值,name="cc"
val修饰的变量是只能赋值一次,类似java的final
kotlin中如果声明变量直接赋值:比如var name = "ccm" 这种就是kotlin的类型判断,它会自动把name判断成字符串类型
kotlin里变量必须初始化,当我们想要使用的时候在初始化,那么可以使用lateinit,但在使用的时候,必须保证是初始化过的,例子:

lateinit var mHeadView:View //如果不想马上初始化,就可以使用lateinit
private fun initUI(){
    // 举个例子:可以判断是否没初始化过
    if(!::mHeadView.isInitialized){
        mHeadView = new View()
    }
    // 必须保证mHeadView是初始化过的
    mHeadView.bindData()
}

二:Kotlin空安全设计

Java:

//声明可空的变量
@Nullable
public View view = null; 
// 使用可空的变量,判断非空
If(view!=null){
    view.setBackgroundColor(Color.RED)
} 

Kotlin:

//声明可空的变量
var view:View?=null
// 使用可空的变量,判断非空
view?.setBackgroundColor(Color.RED)

这种类型之后加"?"的写法,在 Kotlin 里叫可空类型 ?表示可空,!!表示非空,如果使用!!那么该变量一定不能为空,否则会报空指针,举例:

var student:Student?=null
student?.name = "ccm"//当student没有初始化过时,不会报空指针
student!!.name = "ccm"//当student没有初始化过时,报空指针
var myName = student?.name!!

一起讲下Kotlin的?:
Kotlin中的?:表示如果空则使用?:后面的值 继续上面的代码举例

var myName = student?.name?:"cc" //表示如果student为空,或者student.name为空的时候,就默认给myName赋值为cc

三:函数的声明

Java:

// 没有入参,没有返回参数
public void log(){
    Log.e("xxx","xxx");
}
// 有入参,有返回参数的
public int sum(int x,int y){
    return x+y;
}

Kotlin:

// 没有入参,没有返回参数
fun log():Unit{
    Log.e("xx","xx")
}
fun log(){
    Log.e("xxx","xxx")
}
// 有入参,有返回参数的
fun sum(x:Int,y:Int):Int{
    return x+y
}
// 函数简化
fun sum(x:Int,y:Int) = return x+y

fun getStudent(teacher:Teacher?):Stuent?{
    return null
}

几点不同讲解:

  • kotlin默认是public的,可以省略
  • kotlin是fun关键在声明函数
  • kotlin里无返回值的函数,默认类型是Unit,Unit可以省略,Java是Void
  • kotlin参数在前,参数类型在后,并且用":"冒号隔开,Java是相反
  • kotlin返回值类型是在函数的右边并且用":"冒号隔开,Java是在前面
  • kotlin返回类型,跟入参都可以是可空类型
  • kotlin中函数可以简化return跟{} 直接用”=“号来代替

四:函数的重载

Java:

public int sum(int x){
    return sum(x,0)
}
public int sum(int x,int y){
    return x+y;
}
//调用
sum(1);
sum(1,1)

Kotlin:

fun sum(x:Int=0,y:Int=0):Int{
    return x+y
}
//调用
sum()
sum(x=1)
sum(y=1)
sum(1)
sum(1,1)

Kotlin中可以通过对入参添加默认值,从而来实现函数的重载

五:类型

Java:

public int num = 1;//还有long,double,float,short,byte
// 当然Java还要装箱的
public Integer num = 1;//还有Long,Double,Float,Short,Byte

// java里float转int还得使用强转
public float x = 1.55f;
int y = (int)x;

public char c = 'c';
public Boolean flag = true;
public String name = "ccm";
// Java数组
public int[] array = new int[]{1,2} //还有long的数组,double数组,float数组,short数组,byte数组等类似
public String[] strArray = new String[]{"xx","cc"};
publci Student[] stuArray = new Student[10];
// Java常用集合
public List<Student> list = new ArrayList<Student>();
public Map<Student> map = new HashMap<Student>();

Kotlin:

// Kotlin是不管拆箱跟装箱统一用Int
var num:Int = 1 //还有Long,Double,Float,Short,Byte

// Kotlin里Int跟Float等的转化直接是有方法调用,比如:
var x = 1.55f
var y = x.toInt() //类似方法还有toFloat(),toDouble(),toLong(),toShort(),toByte()

var c:Char = 'c' // 当然这种直接赋值,由于kotlin类型推断都是可以省略变量类型的
var flag:Boolean = false
var name:String = "ccm"

// kotlin的数组,还有DoubleArrayOf,FloatArrayOf,LongArrayOf,ShortArrayOf,ByteArrayOf等
var array:IntArrayOf=intArrayOf(1,2) 
var strArray:Array<String> = arrayOf("xxx","ccc")//也可以写成var strArray = arrayOf("xx","cc")
var studentArray:Array<Student> = arrayOf(Student("xx"),Student("xx1"))

// kotlin的集合
var list= ArrayList<Student>()
var map = HashMap<String,String>()

// kotlin的只读list,只读map,可变list,可变map
val list = listOf("a","b","c") //只读的list
val map = mapOf("a" to 1, "b" to 2, "c" to 3) //只读的map
// 可变集合 mutableMapOf修饰可变的map, mutableListOf是修饰可变的list, mutableSetOf是修饰可变的Set 
val maps = mutableMapOf("name" to "ccm", "age" to "1")
maps.put("xxx","000") 
// 不过不可变的集合是可以通过toMutable*()方法来变成可变集合的
// 比如上面的listof
list.toMutableList()//转化成了可变的集合
map.toMutableMap()//转化成可变的map,set同理

Java中的Object相当于Kotlin中的Any

六:类的继承跟实现

Java:

public class MainActivity extents Activity implements View.OnClickListener{
    @Override
    public void onClick(View v){
    }
}

Kotlin:

class MainActivity:Activity(),View.OnClickListener{
    override
    fun onClick(v:View){
        
    }
}
// 举例自定义个Apple类继承自定义水果类
open class Fruit{}
class Apple:Fruit(){}

Kotlin当中继承跟实现都是使用":"冒号,如果有多个的话,用","逗号隔开,Java继承用extends,实现用implements
Java中方法使用@Override注解,Kotlin是override关键字
Kotlin里类默认是final的,如果想要继承,那么可以用open修饰

七:类型判断跟强转

Java:

// 举个例子,判断水果如果是苹果的话,调用苹果的吃方法
public void test(Fruit fruit){
    if(fruit instanceof Apple){
        ((Apple)fruit).eat();
    }
}

Kotlin:

fun test(fruit:Fruit){
    if(fruit is Apple){
        (fruit as Apple).eat()
        // 或者是
        fruit.eat(); //因为类型判断原因,所以可以省略强转
    }
    // 或者上面的代码可以如下写法
    (fruit as? Apple).eat()
    // !is 表示不是某个类型
    if(student !is Fruit){
        xxx
    }
}

Kotlin 中的is关键字相当于Java的instanceof
Kotlin 中的as关键字相当于Java的强转
Kotlin 中as? 表示如果强转成功就执行之后的调用,如果强转不成功就不执行 Kotlin 中!is表示不是某个类型

八:类的构造器

Java:

// Java中写一个类
public class HeadOverlayView extends LinearLayout{
    public String name = "";
    public HeadOverlayView(Context context){
        this(context,null);
    }
    public HeadOverlayView(Context context, AttributeSet attrs){
        this(context,attrs,0);
    }
     public HeadOverlayView(Context context, AttributeSet attrs,int defStyleAttr){
        super(context,attrs,defStyleAttr);
        name = "ccm";
    }
}

Kotlin:

// Kotlin中写一个类
class HeadOverlayView : LinearLayout{
    var name = ""
    constructor(context: Context) : this(context, null)
    constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr){
        name = "ccm"
    }
}
// 也可以这么写
class HeadOverlayView(context:Context):LinearLayout(context){}

Java中构造器的写法是:类名的形式 Kotlin构造器的写法有两种
次级构造器:使用关键字constructor声明的构造器是次级构造器
主构造器:直接在HeadOverlayView(context:Context) 后面写这种方式是主构造器方式
Kotlin中this的用法跟Java中一样,super也是,只是Kotlin次级构造参数后面是用:接着调用super或者this,而Java是写在{}中

九:init

Java:

public class Student{
    {
        //做点事情
    }
    public Student(){}
}

Kotlin:

class CustomView(context:Context):LinearLayout{
    init{
       LayoutInflater.from(context).inflate(R.layout.layout_customview, this)
    }
}

Kotlin中经常在init{}里去写一些初始化的代码,等价于Java的{} 都是在实例化时执行,并且都在构造器之前调用

十:object

object是Kotlin的关键字,并非Java的Object,Java的Object是表示所有类的基类,Kotlin中表示所有类的基类用的是Any
object关键在,在Kotlin中的意思是,创建一个类,并且创建一个这个类的对象,他是生成一个单例对象

Java:

public class Test {
    private static Test sInstance;
    public static Test getInstance() {
        if (sInstance == null) {
            sInstance = new Test();
        }
        return sInstance;
    }
    public void add(){
    }
} 
// 调用代码
Test.getInstance().add()
// 饿汉式
public class Test{
    private Test(){}
    private static final Test test = new Test();
    public static Test getInstance(){
        return test;
    }
}

Kotlin:

object Test {
    var name = "ccc"
    fun add(){}
} 
// 调用
Test.add()
Test.name

通过object 实现的单例是个线程安全的,饿汉似的单例。 当我们想要使用单例,或者想要通过类名.的方式去调用某个类里面的变量跟方法的时候,可以用object

十一:伴生对象companion object

在Java里我们在类里面写一些静态常量,静态方法,让类直接就可以调用,而在Kotlin中我们就可以用伴生对象了
Java:

public class VideoDetailActivity extends Activity{
    public static final String EXTRA_ID = "id";
    public static final int MAX_COUNT = 700;
    public static void enter(Context context,String id){
        Intent intent = new Intent(context,VideoDetailActivity.class);
        intent.putExtra(EXRTA_ID,id);
        context.startActivity(intent);
    }
    // 静态代码块
    static{
    }
}
// 调用
VideoDetailActivity.enter(context,"1");

Kotlin:

class VideoDetailActivity:Activity(){
    companion object {
        const val EXTRA_ID = "id"
        const val MAX_COUNT = 700
        fun enter(context:Context,id:String){
            val intent = Intent(context,VideoDetailActivity::class.java).apply{
                putExtra(EXRTA_ID,id)
            }
            context.startActivity(intent)
        }
        // 类似java的静态代码块
        init{
            
        }
    }
}
// 调用
VideoDetailActivity.enter(context,"1")

当我们只想让类中的一部分函数和变量是静态的,我们就可以用companion object

这里顺便讲几个点:

  • Java中声明常量用static final ,而Kotlin中用const val
  • Java中创建一个对象是用new关键字,而Kotlin不需要new,比如Java:new Intent(),Kotlin是Intent()
  • Kotlin中拿到java的class对象是使用 类名::class.java的形式,例如VideoDetailActivity::class.java,
  • Kotlin中新建一个对象之后,要对对象里面的属性赋值,可以通过apply{} 并在{}里对属性进行初始化 举例:
    Java:
    Student stu = new Student();
    stu.name = "ccm";
    
    Kotlin:
    Student().apply{
        this.name = "ccm"
    }
    

十二:匿名内部类

Java:

button.setOnClickListener(new View.OnClickListener() {
     @Override
     public void onClick(View v) {
       
     }
});

Kotlin:

button.setOnClickListener(object:View.OnClickListener{
     override fun onClick(v: View?) {
    
    }
})
// 通过lambda改写
button.setOnClickListener({v:View->
})
// 如果lambda是函数的最后一个参数,那么可以把Lambda写在()小括号外面
button.setOnClickListener(){v:View->
    
}
// 如果Lambda的函数是唯一的参数,可以把()小括号去掉
button.setOnClickListener{v:View->
}

// 如果这个Lambda是单个参数的,那么参数也可以省略,表达式可以简写成
button.setOnClickListener{
}

Kotlin写匿名内部类的时候,是通过object: 写的

十三:可见性修饰符

Java:

// java中有public ,表示都可见
public class User{
    public String name;
    public void method(){}
}
// java中没有写修饰符表示包内可见default
class User{} //同包名下才可见
// protected 在java中表示包内可见+子类可见
public class User{
    protected void walk(){
    }
}
// private 在java中表示类中可见,作为内部类是对外部类可见
public class Test{
    private int type =1;
    public void test(){
        Inner inner = new Inner();
        inner.name = "xxx";//访问的到
    }
    private class Inner{
        private String name = "cc";
    }
}

Kotlin:

// Kotlin不写默认就是public ,表示都可见
class User{
    var name:String;
    fun method(){}
}
// kotlin中internal修饰付表示对module内可见,Kotlin里没有Java那样的包内可见的修饰符了
internal class User{} //表示这个类只能被同module下的可见
// protected在kotlin中就表示private+子类可见

// private表示类中或所在文件内可见,作为内部类时,对外部类不可见
class Test{
    // 这个是只在Test这个类里可见
    private val type = 1
    public void test(){
        val inner = Inner()
        inner.name //这个代码访问不到
    }
    private class Inner{
        private var name = "xx"
    }
}
// 这个是表示只在Test这个文件里可见(这个也是顶层变量)
private val name = "xx"

Kotlin中的public表示对可见
internal表示包内可见
protected表示private+子类可见
private表示类中可见或文件里可见,作为内部类时,外部类不可访问到

十四:when,if,if else

Java:

// java中使用switch
public int test(int type){
    int result = 0;
    switch (type){
        case 1:
            result = 1;
            break;
        case 2:
        case 4:
            result = 6;
            break;
        case 8:
            result = 10;
            break;
        default:
            result = 20;
            break;
    }
    return result;
}
// java中使用if else
public int test(int type){
    int result = 0;
    if(type == 1){
        result = 1;
    }else if(type == 2 || type == 4){
        result = 6;
    }else if(type == 8){
        result = 10;
    }else{
        result = 20
    }
    return result;
}

Kotlin:

fun test(type:Int):Int{
    val result = when(type){
        1->1
        2,4->6
        8->10
        else->20
    }
    return result
}
// 当然kotlin也可以使用if else的形式,跟java没有太大区别,
fun test(type:Int):Int{
    val result = if(type==1) 1 
    else if(type ==2 || type == 4) 6 
    else if(type == 8) 10
    else 20
    reutrn reuslt
}

Kotlin中if else使用跟java没有太大区别,唯一区别是kotlin中的if else可以有返回值,因为在Kotlin中函数其实中可以作为一个对象
Kotlin中的when基本替代了Java的switch的用法 Kotlin中没有了switch这种用法

十五:字符串拼接

Java:

// java字符串的拼接
public String name = "xxx"
public String text = "昵称"+name
// 使用String.format拼接
System.out.print(String.format("昵称 %s", name));

Kotlin:

// kotlin字符串的拼接
val name = "xxx"
var text = "昵称"+name
// 使用$拼接
println("昵称$name");

十六:== 和 ===

Java:

// java中== 如果是用在基本数据类型,那么是判断值是否相等,如果是放在字符串Stirng是表示引用地址是否相等,Java中判断字符串值是否相等用equals
public int num = 1;
if(num==1) //true
public String s1 = "xx";
public String s2 = "xx";
if(s1 == s2) // false
if(s1.equals(s2)) //true

Kotlin:

Kotlin中==是判断值是否相等,如果是===则判断引用地址是否相等,当然Kotlin也可以用equals
val num = 1
if(num==1)
val s1 = "xx"
val s2 = "xx"
if(s1==s2) //等价于 if(s1.equals(s2))
if(s1===s2) //这个是判断引用地址是否相等

十七:数组,集合的遍历

Java:

// 数组遍历
String[] strs = new String[]{"xx","xxx","xxxxx"};
for(String str:strs){
    ...
}
// 集合遍历
List<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
for(int i=0;i<list.size;i++){
    list.get(i);
    .....
}
for(int index:list){
    .....
}
Map<Stirng,String> map = new HashMap<String,String>();
map.put("xx","xxxx");
map.put("xx1","xxxxx");
for (Map.Entry<String, String> entry : map.entrySet()) { 
  System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue()); 
}

Kotlin

// 数组遍历
val strs = arrayOf("xx","xxx","xxx")
for(str in strs){
    ...
}
// 集合遍历
val list = listOf(1,2,3)
for(i in 0 until list.size){
    .....
}
for(item in list){
    ....
}
// 甚至Kotlin中遍历可以跳指定step  
// 下面意思是0,接着是2...
for(i in 0 until list.size step 2){
    ...
}
// 更经常用的是
list.forEach{
    // it就是指集合里面的值
    println(it)
}
list.forEachIndex{index,i->
   // index是位置索引,i是list里index索引下具体的值
}
// Map的话
var map = mapOf<String,String>("name" to "ccm","b" to "cjh")
for ((k, v) in map) {
    println("$k -> $v")
}
val value = map.get("a")//这个是访问map
map.forEach { 
    // 这里的it值Map.Entry<String,String>
    it.key
    it.value
}
// 一起讲一下kotlin中的while,continue,break用法跟java的没有什么区别
var x = 6
while (x > 0) {
    x--
    if (x == 4) {
        continue
    }
    if (x == 2) {
        break
    }
    Log.e("ccm", "x=$x")
}
输出结果是 53

十八:Kotlin不需要findViewById

Java:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:id="@+id/iv_back"
        android:layout_width="48dp"
        android:layout_height="48dp"
        android:layout_marginLeft="10dp"
        android:scaleType="centerInside"
        android:src="@drawable/nav_btn_back"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>

public class TestActivity extends Activity{
    private ImageView mBackIv;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_test);
        mBackIv = (ImageView) findViewById(R.id.iv_back);
        mBackIv.setImageResource(R.drawable.xxx);
    }
}

Kotlin:

// 需要在app的build.gradle里加入 插件 apply plugin: 'kotlin-android-extensions'
// 然后在使用的地方导入对应的布局的包,就不需要findViewById
import kotlinx.android.synthetic.main.activity_test.*
class TestActivity : Activity(){
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_test)
        iv_back.setImageResource(R.drawable.xxx)
    }
}

十九:顶层声明

Kotlin的顶层声明的函数跟变量是属于package的。在同一包名内,都可以直接调用,不是同一包名需要引入包。举例:比如我们在package com.menstrual.video包名下建一个video.kt文件

package com.menstrual.video

const val HOST = "http://www.baidu.com"

// 比如我们可以写个router跳转
fun router(path: String): Any? {
    return ARouter.getInstance().build(path).navigation()
}
// 写个字符串空判断
fun isEmpty(source: String?): Boolean {
    return !TextUtils.isEmpty(source)
}
// 这样在同包名下的任何地方都可以直接调用上面两个方法,跟获取到HOST
class TestActivty:Activity(){
    override fun onCreate(savedInstanceState: Bundle?) {
      super.onCreate(savedInstanceState)
      // 输出顶层变量HOST
      Log.d("info","==host==${HOST}")
      // 判断是不是等于空
      if(isEmpty("")){
        // 调用router跳转页面
         router("/circle/video")
      }
    }
}
// 如果在不同包名下的话,那么也是可以使用的只不过要导入相应的包引用
package com.menstrual.test
import com.menstrual.video.router
import com.menstrual.video.isEmpty
class TestActivty2:Activity(){
    override fun onCreate(savedInstanceState: Bundle?) {
      super.onCreate(savedInstanceState)
      // 判断是不是等于空
      if(isEmpty("")){
        // 调用router跳转页面
         router("/circle/video")
      }
    }
}

二十:扩展函数

Kotlin中的扩展函数是可以给具体的类,添加扩展的函数。举例: com.menstrual.video包名下建一个video.kt文件,在这个video.kt里添加扩展函数

package com.menstrual.video
// 给字符串String添加扩展函数
fun String.cut():String= this?.substring(0,1)
// 在同包名下的任何类都可以调用
val name = "cxk"
// 就可以让字符串调用我们自己写的cut方法,这个cut方法就是扩展函数
val str = name.cut()

// 给View添加扩展函数
fun ImageView.loadImage(url:String,placeResId:Int){
    Glide.with(context).load(url).placeholder(placeResId).into(this)
}
// 调用 比如mHeadView是个ImageView 
mHeadView.loadImage("http://xxx",R.drawable.xxx)

// 如果在不同包名下要调用的话,也是导入对应的包就行了,举例
package com.menstrual.test
import com.menstrual.video.loadImage
class TestActivty:Activity(){
    override fun onCreate(savedInstanceState: Bundle?) {
      super.onCreate(savedInstanceState)
      ivHead.loadImage("http://xxx",R.drawable.xxx)
    }
}

二十一:内联函数

Kotlin中声明内联函数关键字是inline

// 这个是kotlin源码里 String.kt 判断字符串是否为空的代码
public inline fun CharSequence.isEmpty(): Boolean = length == 0
// 调用
val text = "xxx"
if(text.isEmpty())

为何要写内联函数?

  1. 我们每调用一个方法的时候,都会创建出一个栈帧,并且把这个栈帧压入到方法栈,当方法调用完成之后又需要把该栈帧出栈,这整个调用方法的过程是会消耗资源的。
  2. 我们在开发过程当中,我们会把我们经常使用到的代码抽成方法,而这些方法是我们经常调用的,比如判断字符串是否为空类似的方法,那么这时候是比较耗资源的。
  3. 我们使用内联函数之后,编译之后,我们方法调用的地方,都会被替换成方法的内容,这样就不用去创建栈帧了,因为在编译时候自动做的事情,所以不影响我们开发时候使用。从而减少了资源的消耗,同时不影响使用。
    // 我们方法调用的地方,内联函数在编译后被替换成方法内容,什么意思呢?举例:
    比如上面的 text.isEmpty() 因为是内联函数编译后代码text.length == 0, 这个方法isEmpty() 直接被替换成了方法内容length==0,所以这样就少了栈帧的资源消耗
    

所以这就是我们使用内联函数的原因。如果很多函数经常被使用到,那么我们可以把这个方法定义为内联函数。

二十二:高阶函数

Kotlin中的高阶函数,是如果方法的参数是函数类型,或者方法的返回值是函数类型,那么我们就把这个函数成为高阶函数,举例:

fun getName(name:String):String = "my name is ${name}"
// 参数是函数类型的例子 method:(name:String)->String 这个是表示参数是String,并且返回类型是String的函数
fun join(s1:String,method:(name:String)->String):String{
    return method(s1)
}
// 调用
fun test(){
    // 调用结果输出是  my name is ccm
    println(join("ccm",::getName))
}
// 返回类型是函数类型的例子 (Int)->Unit 这个表示参数是int无返回类型的函数
fun test2(num: Int): (Int) -> String {
   ...
}

Kotlin中的双冒号“::”表示函数引用,对于一个声明好的函数,当我们要把它作为参数传递给函数,还是要把它赋值给变量,都得在函数名的左边加上双冒号,来进行调用,举例

fun getName(name:String):String = "my name is ${name}"
// 把声明好的函数getName,赋值给变量
val b = ::getName
// 把声明好的函数,作为参数调用
join("cc",::getName)

二十三:嵌套函数

Kotlin中可以在函数里面写函数,这种就是嵌套函数

// 比如
fun main(){
    fun test(){
        xxx
    }
    //调用,test方法只属于main方法
    test()
}