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

构造方法

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

Java中类的构造方法:

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

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

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

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

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

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

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

open class Button

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

一、主构造方法

特点:

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

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

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

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

声明一个简单类:

class User(val nickname:String)

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

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

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

//代码片段1  表示方式更为明确的代码,nickname是属性
class User constructor(_nickname:String){
    val nickname:String
    init{//初始化语句块
        nickname = _nickname
    }
}

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

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

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

错误写法:

class User constructor(_nickname:String){
    val nickname = _nickname
    println("init") //!!!语法错误,因为主构造方法中不能包含类的初始化代码
}

正确写法:

class User constructor(_nickname:String){
    val nickname = _nickname
    init{
        println("init")
    }
}

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

//代码片段2 功能和代码片段1相同
class User(_nickname:String){
    val nickname = _nickname  //用参数来初始化属性
}

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

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

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

//代码片段3 功能和代码片段1和2相同 最简洁
class User(val nickname:String)

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

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

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

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

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

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

User()   //name="zhangsan",age=9  注意:这个不是默认构造方法,默认构造方法不包含任何参数,且方法体为空。
User(String name)  //age=9
User(Int age)   //name="zhangsan",调用该方法时,需命名参数age
User(String name, Int age)  
//Kotlin
fun main(args:Array<String>){
    val user = User()
     //name::zhangsan::age::9
    println("name::" + user.name + "::age::" + user.age) 
    
    val user2 = User("lisi")
    //name::lisi::age::9
    println("name::" + user2.name + "::age::" + user2.age)
    
    val user3 = User(age=18)
    //name::zhangsan::age::18
    println("name::" + user3.name + "::age::" + user3.age)
    
    val user4 = User(name="wangwu", age=18)
    //name::wangwu::age::18
    println("name::" + user4.name + "::age::" + user4.age)
}

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

//Kotlin

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

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

User()  //name="zhangsan",age=9  注意:这个不是默认构造方法,默认构造方法不包含任何参数,且方法体为空
User(String name, Int age)  //name="zhangsan",age=9
//Java
class Test11{
    public static void main(String args[]){
        User user = new User();
        //name::zhangsan::age::9
        System.out.println("name::" + user.getName() + "::age::" + user.getAge());
        
        User user2 = new User("lisi", 11);  
        //name::lisi::age::11
        System.out.println("name::" + user2.getName() + "::age::" + user2.getAge());
    }
}

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

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

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

User()  //name="zhangsan",age=9  注意:这个不是默认构造方法,默认构造方法不包含任何参数,且方法体为空
User(String name)  //age=9
User(String name, Int age)  //name="zhangsan",age=9
//Java
class Test11{
    public static void main(String args[]){
        User user = new User();
        //name::zhangsan::age::9
        System.out.println("name::" + user.getName() + "::age::" + user.getAge());
        
        User user2 = new User("lisi", 11);
        //name::lisi::age::11
        System.out.println("name::" + user2.getName() + "::age::" + user2.getAge());
        //Test33Kt.User类中增加了 @JvmOverloads 注解后,增加了重载的构造函数 User(String name)
        User user3 = new User("lisi");
        //name::lisi::age::9
        System.out.println("name::" + user3.getName() + "::age::" + user3.getAge());
    }
}

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

特点:

声明在类的内部

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

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

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

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

class User{
private val username: String
private var age: Int
constructor(_username: String, _age: Int){
    this.username = _username.toUpperCase()
    this.age = _age
}
}

注意:

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

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

2、委托

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

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

例1:

open class B(){
    init{
        println("--B主构造--")
    }
}
class A(): B() {
    init{
        println("--A主构造--")
    }
    constructor(name: String):this() {
        println("--A次构造--")
    }
}
fun main(args:Array<String>){
    val a2 = A("zhangsan")
}

执行结果:

--B主构造--

--A主构造--

--A次构造--

例2:

class User(val name: String = "Bob") {
    init{
        println("--User主构造--")
    }
    constructor(id: Long) : this(){
        println("--User次构造11111--")
    }
    constructor(id: Long, email: String):this() {
        println("--User次构造22222--")
    }
}
fun main(args:Array<String>){
    val user = User(1,"aoeiuv")
    println(user.name)
}

执行结果:

--User主构造--

--User次构造22222--

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

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

// open 标识该类可以被继承
open class Mouse {
    var _name:String = ""
    var _price:Int = 0
    constructor(name: String) : this(name, 0){
        this._name = name;
        println("--Mouse次构造(含1个参数)--")
    }
    constructor(name: String, price: Int) {
        this._name = name
        this._price = price
        println("--Mouse次构造(含2个参数)--")
    }
    fun printInfo() {
        println("name = $_name , price  = $_price")
    }
}
class AppleMouse: Mouse {
    constructor(name:String, price:Int):super(name, price){
        println("--AppleMouse次构造(含2个参数)--")
    }
}
fun main(args:Array<String>){
    val mouse = AppleMouse("luoji",190)
    mouse.printInfo()
}

执行结果:

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

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

name = luoji , price = 190

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

// open 标识该类可以被继承
open class Mouse{
    init {
        println("--Mouse无参主构造--")
    }
}
class LuoMouse: Mouse{
    constructor(name:String){      //无需使用super关键字
        println("--LuoMouse无参次构造--")
    }
}
fun main(args:Array<String>){
    LuoMouse("hh")
}

执行结果:

--Mouse无参主构造--

--LuoMouse无参次构造--

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

// open 标识该类可以被继承
open class Mouse{
    constructor(name:String)
}
class LuoMouse(): Mouse("bob"){
    constructor(name:String){
        println("--LuoMouse无参次构造--")
    }
}
// open 标识该类可以被继承
open class Mouse{
    constructor()
}
class LuoMouse(): Mouse(){
    constructor(name:String){
        println("--LuoMouse无参次构造--")
    }
}

3、使用场景

1)构造函数的相互调用

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

class MyButton : AppCompatButton {
    constructor(context: Context) : this(context, null)
    constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, R.attr.buttonStyle)
    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
}

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

三、默认构造方法

1、写法

open class Button

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

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

class RadioButton:Button()

————————————————

版权声明:本文为CSDN博主「浅唱整个春天」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/qq_32677531/article/details/126075375

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Kotlin中有两种类型的构造方法:主构造方法和次构造方法。 1. 主构造方法: 主构造方法是类头的一部分,它跟在类名后面,可以带有参数。主构造方法可以直接初始化类的属性和执行其他初始化操作。 示例代码如下: ``` class Person(firstName: String, lastName: String) { init { println("Person initialized with firstName = $firstName, lastName = $lastName") } } ``` 在上面的例子中,我们定义了一个Person类,并在类头中定义了一个主构造方法,该方法带有两个参数:firstName和lastName。在构造方法体中,我们使用了init块来执行初始化操作。 2. 次构造方法: 次构造方法是类中定义的额外构造方法。它们需要使用constructor关键字来定义。一个类可以拥有多个次构造方法,但每个次构造方法都必须调用主构造方法或者其他次构造方法。 示例代码如下: ``` class Person(firstName: String, lastName: String) { init { println("Person initialized with firstName = $firstName, lastName = $lastName") } constructor(firstName: String) : this(firstName, "Smith") { println("Person initialized with firstName = $firstName") } } ``` 在上面的例子中,我们定义了一个Person类,并在类头中定义了一个主构造方法,该方法带有两个参数:firstName和lastName。在类体中,我们定义了一个次构造方法,该方法只有一个参数:firstName。该次构造方法调用了主构造方法,并给lastName参数传递了默认值“Smith”。在次构造方法体中,我们使用println函数输出了初始化信息。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值