Kotlin基础学习(五)—— 构造方法

构造方法

构造方法:类的一种特殊方法,负责新创建对象的初始化工作,为实例变量赋初值。

Java中类的构造方法:

类的构造方法不是要求必须定义的。

① 如果在类中没有定义任何一个构造方法,则 Java 会自动为该类生成一个默认的构造方法(默认构造方法不包含任何参数,且方法体为空);

② 如果在类中显式地定义了一个或多个构造方法,则 Java 不再提供默认构造方法。

★ Kotlin 和 Java 一样,一个类可以声明一个或多个构造方法,但Kotlin的不同点为,区分了主构造方法和从构造方法:

主构造方法:主要而简洁的初始化类的方法,并且在类体外部声明

从构造方法:在类体内部声明

★ 如果没有给类声明任何构造方法,将会生成一个不做任何事情的默认构造方法:

open class Button

★ 大多数情况下,Kotlin 中类的构造方法的声明方式非常简明,要么类名后没有参数(默认构造方法),要么直接把参数与对应属性相关联(主构造方法)。当需要为类定义足够多的构造方法时,使用从构造方法。

一、主构造方法

特点:

声明在类的外部,且一般主构造方法在类头部的类名后面有括号(含参构造方法)

一个类只有一个主构造方法,该主构造方法可以有多个重载参数的构造方法

主构造方法不包含初始化执行语句(因为其放在类首部,所以不能包含初始化执行语句),但是可以将初始化执行语句放在 init 中,为属性赋值

1、写法(在类中声明主构造方法的方式)

声明一个简单类:

class User(val nickname:String)

其中,被括号围起来的语句块就叫作 主构造方法。

括号的目的:表明构造方法的参数,以及定义使用这些参数初始化的属性。

1) 主构造方法写法1:表示方式更为明确的构造方法

 
 
  1. //代码片段1 表示方式更为明确的代码,nickname是属性

  2. class User constructor(_nickname:String){

  3. val nickname:String

  4. init{//初始化语句块

  5. nickname = _nickname

  6. }

  7. }

constructor关键字 用来开始一个主构造方法或从构造方法的声明;

init关键字 用来引入一个初始化语句块。

初始化语句块:在Kotlin中,主构造方法有语法限制,不能包含初始化代码。 可以在一个类中声明多个初始化语句块。

错误写法:

 
 
  1. class User constructor(_nickname:String){

  2. val nickname = _nickname

  3. println("init") //!!!语法错误,因为主构造方法中不能包含类的初始化代码

  4. }

正确写法:

 
 
  1. class User constructor(_nickname:String){

  2. val nickname = _nickname

  3. init{

  4. println("init")

  5. }

  6. }

2) 主构造方法写法2:去掉constructor关键字

 
 
  1. //代码片段2 功能和代码片段1相同

  2. class User(_nickname:String){

  3. val nickname = _nickname //用参数来初始化属性

  4. }

初始化执行语句块中的代码可以与nickname属性的声明相结合

主构造方法没有注解或可见性修饰符,可去掉constructor关键字;当有修饰符时,constructor关键字位于修饰符后面

3) 主构造方法写法3:将val关键字加在方法的参数前

 
 
  1. //代码片段3 功能和代码片段1和2相同 最简洁

  2. class User(val nickname:String)

将val关键字加在参数前:属性使用构造方法参数来初始化,这种方式可以替换类中的属性定义

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

2 、为构造方法声明默认值(构造方法的重载

1) 在 Kotlin 中调用构造方法(使用 Kotlin 声明类)

 
 
  1. //Kotlin

  2. class User(val name:String = "zhangsan", val age:Int = 9)

该类的参数设置了默认值,在Kotlin中默认生成了四个构造方法:

 
 
  1. User() //name="zhangsan",age=9 注意:这个不是默认构造方法,默认构造方法不包含任何参数,且方法体为空。

  2. User(String name) //age=9

  3. User(Int age) //name="zhangsan",调用该方法时,需命名参数age

  4. User(String name, Int age)

 
 
  1. //Kotlin

  2. fun main(args:Array<String>){

  3. val user = User()

  4. //name::zhangsan::age::9

  5. println("name::" + user.name + "::age::" + user.age)

  6. val user2 = User("lisi")

  7. //name::lisi::age::9

  8. println("name::" + user2.name + "::age::" + user2.age)

  9. val user3 = User(age=18)

  10. //name::zhangsan::age::18

  11. println("name::" + user3.name + "::age::" + user3.age)

  12. val user4 = User(name="wangwu", age=18)

  13. //name::wangwu::age::18

  14. println("name::" + user4.name + "::age::" + user4.age)

  15. }

2) 在Java中调用构造方法(使用 Kotlin 声明类):

//Kotlin

class User(val name:String = "zhangsan", val age:Int = 9)

该类的声明方式,在Java中默认生成了两个构造方法:

 
 
  1. User() //name="zhangsan",age=9 注意:这个不是默认构造方法,默认构造方法不包含任何参数,且方法体为空

  2. User(String name, Int age) //name="zhangsan",age=9

 
 
  1. //Java

  2. class Test11{

  3. public static void main(String args[]){

  4. User user = new User();

  5. //name::zhangsan::age::9

  6. System.out.println("name::" + user.getName() + "::age::" + user.getAge());

  7. User user2 = new User("lisi", 11);

  8. //name::lisi::age::11

  9. System.out.println("name::" + user2.getName() + "::age::" + user2.getAge());

  10. }

  11. }

Java中没有函数参数默认值的概念,当从 Java 代码中调用 Kotlin 代码中的函数时,需要显式地指定所有的参数值。当对 Kotlin 中的函数使用 @JvmOverloads 注解 时,编译器会生成 Java 重载函数(从最后一个开始 省略有默认值的参数,构成重载函数的参数)。

 
 
  1. //Kotlin

  2. class User @JvmOverloads constructor(val name:String = "zhangsan", val age:Int=9)

这种类的声明方式,在Java中默认生成了三个构造函数:

 
 
  1. User() //name="zhangsan",age=9 注意:这个不是默认构造方法,默认构造方法不包含任何参数,且方法体为空

  2. User(String name) //age=9

  3. User(String name, Int age) //name="zhangsan",age=9

 
 
  1. //Java

  2. class Test11{

  3. public static void main(String args[]){

  4. User user = new User();

  5. //name::zhangsan::age::9

  6. System.out.println("name::" + user.getName() + "::age::" + user.getAge());

  7. User user2 = new User("lisi", 11);

  8. //name::lisi::age::11

  9. System.out.println("name::" + user2.getName() + "::age::" + user2.getAge());

  10. //Test33Kt.User类中增加了 @JvmOverloads 注解后,增加了重载的构造函数 User(String name)

  11. User user3 = new User("lisi");

  12. //name::lisi::age::9

  13. System.out.println("name::" + user3.getName() + "::age::" + user3.getAge());

  14. }

  15. }

二、从构造方法(次构造方法)

特点:

声明在类的内部

一个类可声明任意多个从构造方法,通过定义多个从构造函数来配置不同的参数组合

从构造方法可以包含初始化代码块

从构造方法需委托给主构造方法(主从同时存在)

1、写法(声明从构造方法)

 
 
  1. class User{

  2. private val username: String

  3. private var age: Int

  4. constructor(_username: String, _age: Int){

  5. this.username = _username.toUpperCase()

  6. this.age = _age

  7. }

  8. }

注意:

声明从构造方法类似于在 Java 中声明构造方法的方式,区别在于这里使用 constructor 关键字取代了类名

在从构造方法中,不能在 constructor 参数中通过 val 或 var 来为类添加相应的属性

2、委托

1) 主从构造方法同时存在时,从构造方法会直接或者间接调用/委托主构造方法。

在从构造方法存在委托情况时,会先执行委托的方法,然后执行自身。

例1:

 
 
  1. open class B(){

  2. init{

  3. println("--B主构造--")

  4. }

  5. }

  6. class A(): B() {

  7. init{

  8. println("--A主构造--")

  9. }

  10. constructor(name: String):this() {

  11. println("--A次构造--")

  12. }

  13. }

  14. fun main(args:Array<String>){

  15. val a2 = A("zhangsan")

  16. }

执行结果:

--B主构造--

--A主构造--

--A次构造--

例2:

 
 
  1. class User(val name: String = "Bob") {

  2. init{

  3. println("--User主构造--")

  4. }

  5. constructor(id: Long) : this(){

  6. println("--User次构造11111--")

  7. }

  8. constructor(id: Long, email: String):this() {

  9. println("--User次构造22222--")

  10. }

  11. }

  12. fun main(args:Array<String>){

  13. val user = User(1,"aoeiuv")

  14. println(user.name)

  15. }

执行结果:

--User主构造--

--User次构造22222--

以下考虑存在继承关系的时候:

2) 如果子类中没有主构造方法,有从构造方法,且父类没有无参构造方法,那么必须要在子类的从构造方法中调用 super 关键字 委托给父类,来初始化父类,初始化父类时,可调用父类的不同的构造函数

 
 
  1. // open 标识该类可以被继承

  2. open class Mouse {

  3. var _name:String = ""

  4. var _price:Int = 0

  5. constructor(name: String) : this(name, 0){

  6. this._name = name;

  7. println("--Mouse次构造(含1个参数)--")

  8. }

  9. constructor(name: String, price: Int) {

  10. this._name = name

  11. this._price = price

  12. println("--Mouse次构造(含2个参数)--")

  13. }

  14. fun printInfo() {

  15. println("name = $_name , price = $_price")

  16. }

  17. }

  18. class AppleMouse: Mouse {

  19. constructor(name:String, price:Int):super(name, price){

  20. println("--AppleMouse次构造(含2个参数)--")

  21. }

  22. }

  23. fun main(args:Array<String>){

  24. val mouse = AppleMouse("luoji",190)

  25. mouse.printInfo()

  26. }

执行结果:

--Mouse次构造(含2个参数)--

--AppleMouse次构造(含2个参数)--

name = luoji , price = 190

3) 如果子类中没有主构造方法,有从构造方法,但父类有无参构造方法,子类在继承该基类时,无需在从构造方法中使用super关键字,执行时会实现该基类的无参构造器

 
 
  1. // open 标识该类可以被继承

  2. open class Mouse{

  3. init {

  4. println("--Mouse无参主构造--")

  5. }

  6. }

  7. class LuoMouse: Mouse{

  8. constructor(name:String){ //无需使用super关键字

  9. println("--LuoMouse无参次构造--")

  10. }

  11. }

  12. fun main(args:Array<String>){

  13. LuoMouse("hh")

  14. }

执行结果:

--Mouse无参主构造--

--LuoMouse无参次构造--

4) 如果子类中有主构造方法,无论父类什么情况,子类的主构造方法需调用父类的构造方法

 
 
  1. // open 标识该类可以被继承

  2. open class Mouse{

  3. constructor(name:String)

  4. }

  5. class LuoMouse(): Mouse("bob"){

  6. constructor(name:String){

  7. println("--LuoMouse无参次构造--")

  8. }

  9. }

 
 
  1. // open 标识该类可以被继承

  2. open class Mouse{

  3. constructor()

  4. }

  5. class LuoMouse(): Mouse(){

  6. constructor(name:String){

  7. println("--LuoMouse无参次构造--")

  8. }

  9. }

3、使用场景

1)构造函数的相互调用

比如,需要重写 AppCompatButton 类中的多个构造器,那么就需要用到从构造方法:

 
 
  1. class MyButton : AppCompatButton {

  2. constructor(context: Context) : this(context, null)

  3. constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, R.attr.buttonStyle)

  4. constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)

  5. }

2)使用不同的参数列表创建类的实例

三、默认构造方法

1、写法

open class Button

2、继承只有一个默认构造方法的类

如果继承了Button类(只有一个默认构造方法),并且子类没有提供任何构造方法,必须显式地调用父类的构造方法(父类名称后面加上一个空括号):

class RadioButton:Button()

猜你喜欢

转载自blog.csdn.net/liujun3512159/article/details/129193378
今日推荐