开发者中心 > 专栏 > 内容详情
分享
  • 打开微信扫码分享

  • 点击前往QQ分享

  • 点击前往微博分享

  • 点击复制链接

强烈推荐!Java开发者入手Kotlin的几大原因(一)构造方法篇

  • 京麦研发团队
  • 2021-07-14
  • 1721浏览

 

原因:更加简洁的构造方法

你还在为 Java 中重载多个构造方法去初始化一个类而困扰吗?在 Kotlin 中完全不用担心这个问题,Kotin 用合理的设计为我们规避了这些问题。通过 Java 和 kotlin 对比来看看 Kotlin 是如何处理构造函数的。

 

Java 的构造方法

Java 是如何实现多个构造方法的,答案是显而易见的,是通过重载。Student 的实例中就展示了两个区分参数的构造方法。

public class Student {
    private String name;
    private int age;
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public Student(String name) {
        this.name = name;
    } 
}

这样的实现方式,造成的问题有两个:

  • 如果要支持任意参数组合来创建对象的话,需要实现的构造方法会很多。

  • 每个构造方法代码其实存在冗余

 

那么针对以上问题,Kotlin 是如何设计来解决的,是否能够减少构造方法的数量的同时最大程度的复用代码,如果能又该怎么使用呢?

 

Kotlin 的构造方法

首先第一点 kotlin 破天荒的支持了参数设置默认值,通过对参数设置默认值,可以有效的减少构造方法的数量,Java 中通过重载机制实现的构造方法在 Kotlin 中都可以通过设置参数默认值的方法替代。

 

StudentKotlin 实例中就 对于 参数 name 进行了默认值的设置,有了默认值的参数在对象实例化时可以不赋值,当然在使用时如果想要重新赋值也是可以的,Kotlin 构造方法还有什么其他特点呢?

 

Kotlin 主构造方法特点

  • 由于参数具有默认值的存在,所以在创建对象的时候,最好是可以直接指定名称,否则需要和 java 一样,必须按照参数顺序进行赋值。是的你没听错,只要参数指定名称就可以不按照参数顺序进行赋值,当然前提是指定名称。

  • 如果某些参数不需要设置默认值,可以通过设置 val 或是 var 修饰符,但在实例化对象时该参数将会被强制要求赋值否则会报错。

  • init 方法中也可以对构造方法中的参数进行赋值,例如 StudentKotlin 实例化时将 age 赋值为 5,init 方法又将 age 赋值为 2,最后结果却是 2 ,这其实和构造方法和 init 的初始化顺序有关,博主以前有写过一篇关于初始化顺序的文章,感兴趣的同学可以翻翻看。

 

class StudentKotlin(name: String = "xiaoming", var age: Int
) {  
   init{
      age = 2
      println("姓名 $name 年龄 $age)
   }                                                 
}


//实例化 studentKotlin1
val studentKotlin1:StudentKotlin = StudentKotlin(name = "xiaohong",age = 1)


//实例化 studentKotlin2
val studentKotlin2:StudentKotlin = StudentKotlin(age = 2,name = "xiaohong")


fun main(args: Array<String>) {
    //实例化 studentKotlin3 age 参数必传
    val studentKotlin3: StudentKotlin = StudentKotlin(age = 5)

 


原因:主从构造方法的引入

其实 Kotlin 也是支持多个构造方法的,Kotlin 将这种构造方法体系叫做主从构造方法,我们上文提到的构造方法就是主构造方法,在实际开发中,虽然 Kotlin 支持构造参数设置默认值在主构造参数中,但在特殊场景中,其实还是需要子构造方法的参与的,单一的主构造方法还是无法满足我们的需求。

 

例如有时候我们需要从一个特殊的数据提供者获取构造类的参数值,这时候就凸显出多构造方法的重要性,我们可以通过定义一个额外的构造方法,用来接收这个自定义的参数,这样会方便不少也让程序结构更清晰。

 

在 Student 例子中,我们有以下需求

我们有已知参数<生日>,我们希望通过已知<生日>直接获取到<年龄>。

 

Java 如何实现?

Java 完全可以通过新增一个构造方法的方式来解决这个问题,添加一个需要参数是 birthday 的构造方法,通过<getAgeByBirth>方法获取到年龄并赋值给成员变量 <age>

 

public class Student {
    private String name;
    private int age;
    private int birthday;
    
    public Student(String name) {
        this.name = name;
    }
    
    public Student(int birthday) {
        this.age = getAgeByBirth(birthday);
    }
    
    //获取年龄
    public int getAgeByBirth(int age) {
        ...
    } 
}

 

通过 Kotlin 主从构造实现

其实 Kotlin 也支持多构造方法,和 Java 的区别是,在多个构造方法之间建立了"主从"的关系。通过实例代码我们学习一下主从构造方法的使用

 

class Student(name: String = "xiaoming", age: Int = 0){
    val age:Int = age
    
    //从构造方法
    constructor(birth:int):this(getAgeByBirth(birth))
    
    //获取年龄
    private fun getAgeByBirth(birth: Int): Int {
       ...
    }
}

 

主从构造方法的特点

  • 通过 constructor 方法定义的构造方法,被称为从构造方法,相应的在类外部定义的构造方法被称为主构造方法。当然如果主构造方法存在注解或可见性修饰符,也必须像从构造方法一样加上 constructor 关键字。

internal class StudentKotlin @inject constructor (name: String = "xiaoming", private var age: Int, private val birth: Int) {
   init{
       age = 2
       println("姓名 $name 年龄 $age)
   } 
}
  • 从构造方法由两部分组成,一部分是其他构造方法的委托另一部分是由花括号包裹的代码块。执行顺序上会先执行委托的方法,然后再执行自身代码块的逻辑;通过 this 关键字来调用委托的构造方法。如果一类存在主构造方法,那么每个从构造方法都要直接或间接地委托给它

 

通过 Java 版的 Android View 实现和 Kotlin 版的 View 实现对比,就可以明白 Kotlin 的构造方法直接和间接委托的概念

 

Java 版 Android View
public class MyView extends View {
    
    public MyView(Context context) {
        super(context);
    }


    public MyView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }


    public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }


    public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

Kotlin 版 Android View
class MyKotlinView : View {
    //构造方法 A
    constructor(context: Context?):this(context,null)
    //构造方法 B
    constructor(context: Context?, attrs: AttributeSet?) : this(context, null,0)
    //构造方法 C
    constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(
        context,
        attrs,
        defStyleAttr
    ) {
    
    }
}

 

Kotlin 版内一共三个构造方法,可以看出 构造方法 A 委托于 构造方法 B,构造方法 B 委托于构造方法 A。

 

为了表现出拥有主构造方法的情况是怎样的,我们还 可以这样改造。所有的构造方法都是直接或是间接的委托于主构造方法

 

class MyKotlinView(context: Context?, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) :
    View(context, attrs, defStyleAttr, defStyleRes) {
    constructor(context: Context?) : this(context, null)
    constructor(context: Context?, attrs: AttributeSet?) : this(context, null, 0)
    constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : this(
        context,
        null,
        0,
        0
    )
}

 

以上就是本章对于 Java 和 Kotlin 在构造方法上的改进和区别,如果觉得还不错请多多点赞和转发,后续本系列也会分享更多的 Kotlin 和 Java 的干货内容,感谢您的纠错和反馈。