kotlin数据类的构造器,我碰到一个无法解决的麻烦

caibirdcnb 2021-04-26 12:22:54




我打算将Java转成Kotlin实现同样功能。如下面代码所示,Java代码创建了2个构造器初始化不同属性。
但是,Kotlin使用数据类的时候,无法实现同样的功能。

初始化只能是2种,不能有第3种:
Table(date,time,price)或Table(date,priceBBB)
现在Kotlin代码多出了1种:Table(date)

主要问题:现在Kotlin代码多了一个构造器,麻烦就出现在这个多出来的主构造器,该构造器是不允许存在的。
但我看了资料,似乎data类必须有带参数的构造器。虽然我可以使用普通类实现和Java一样的代码,但这个类确实是个data类。
请问如何解决?难道这是Kotlin语言的逻辑缺少吗?


Java:

class Table {
private String mDate;
private String mTime;
private double mPrice;
private double mPriceBBBBBB;

Table(String date, String time, double price) {
mDate = date;
mTime = time;
mPrice = price;
}

Table(String date, double priceBBBBBB) {
mDate = date;
mPriceBBBBBB = priceBBBBBB;
}
}


Kotlin:

data class Table(var date: String) {
private var time: String? = null
private var price = 0.0
private var priceBBBBBB = 0.0

constructor(date: String, time: String?, price: Double):this(date) {
this.time = time
this.price = price
}

constructor(date: String, priceBBBBBB: Double) :this(date){
this.priceBBBBBB = priceBBBBBB
}
}
...全文
1187 19 打赏 收藏 转发到动态 举报
写回复
用AI写文章
19 条回复
切换为时间正序
请发表友善的回复…
发表回复
caibirdcnb 2021-05-26
  • 打赏
  • 举报
回复
引用 15 楼 雪下的回忆 的回复:
[quote=引用 14 楼 caibirdcnb 的回复:] 你多写了一个构造器肯定会多出来一个的,在我回答你之前请问一下为什么你不允许有一个拥有所有信息的源创建对象
目前我有no,name,weight和no,height这2个数据源,还有第3个数据源包含no,name,height,weight。 如果存在【拥有所有信息】的构造器,就可能误用第3个数据源的数据。
caibirdcnb 2021-05-26
  • 打赏
  • 举报
回复
引用 17 楼 立青_ 的回复:
就是瞎讲究。首先 data类是把主构造方法内的属性纳入考虑,所以你不把参数放主构造,就没必要使用data类。 然后,就算你用构造方法限制了,但有的是其它办法实例化对象。 你这个需求本身就是有问题的,你要么就别使用data类要么就放弃你这个有问题的需求吧
你说的对,如果不用data类实现还更好实现。 但这不能说是我的需求有问题啊,应该说是语言适用性不够。 你看我的需求,都有合理性啊。 例如,类本身确实是个数据类,想用data class实现不合理吗? 又例如,确实有2个数据源要求有2种初始化方式,也很合理啊。 第三,不能拥有第3个构造器的要求也有合理性。(假设我有第3个数据源刚好和第3个构造器匹配,那不熟悉的程序员维护的时候,就可能搞混导入错误数据)
caibirdcnb 2021-05-26
  • 打赏
  • 举报
回复
引用 16 楼 雪下的回忆 的回复:
[quote=引用 14 楼 caibirdcnb 的回复:] 可以看到写到最后已经和直接用java写差不多繁琐了,因此不是特殊需求不要这样写,另外遇到问题多思考一下,这些东西按我之前说的内容完全可以推理出来的
非常感谢!经过你的仔细指导,终于弄出来了。
data class Student(val no: Int, val name: String, val weight: Int) {
    var height = 0

    constructor(no: Int, height: Int) : this(no, "", 0) {
        this.height = height
    }
    // 其它重写
}

fun test() {
    Student(21, "Zhang San", 65)
    Student(21, 158)
}
立青_ 中级 2021-05-25
  • 打赏
  • 举报
回复
就是瞎讲究。首先 data类是把主构造方法内的属性纳入考虑,所以你不把参数放主构造,就没必要使用data类。 然后,就算你用构造方法限制了,但有的是其它办法实例化对象。 你这个需求本身就是有问题的,你要么就别使用data类要么就放弃你这个有问题的需求吧
雪下的回忆 2021-05-25
  • 打赏
  • 举报
回复
引用 14 楼 caibirdcnb 的回复:
你给的代码: data class Student(val no: Int, val name: String, val height: Int, val weight: Int) { constructor(no: Int) : this(no, "", 0, 0) } 我自己改的: data class Student(val no: Int, val name: String, val height: Int, val weight: Int) { constructor(no: Int, height: Int) : this(no, "", 0, 0) constructor(no: Int, name: String, weight: Int) : this(no, "", 0, 0) }
虽然这是一个非常蠢而且没什么用的要求,但是你照着我的思路仔细思考一下是可以得出结论的。 首先我们需要一个data类而且它只能有两个构造器,所以我们就一定只能写一个从构造器和一个主构造器 主构造器我们可以定义为
data class Student(val no: Int, val name: String, val weight: Int)
应该很容易理解。 从构造器我们需要的是一个包含了no和height的值,并且从构造器我们需要去给主构造器赋值,因此我们可以把从构造器写成这样
constructor(no: Int, height: Int) : this(no, "", 0)
再然后我们在使用主构造器赋值之后仍然可能有赋值height的需求,并且我们从构造器中传入的height值也需要一个存放的位置,因此我们需要在方法内部放一个变量
var height = 0
再往你的从构造器里添加对应的赋值方法
this.height = height
最后,因为我们新添加的属性不会直接被data识别,因此我们需要单独重写tostring、hashcode等方法

override fun toString(): String {
    return "Student(no=$no, name='$name', weight=$weight, height=$height)"
}
//下略
可以看到写到最后已经和直接用java写差不多繁琐了,因此不是特殊需求不要这样写,另外遇到问题多思考一下,这些东西按我之前说的内容完全可以推理出来的
雪下的回忆 2021-05-25
  • 打赏
  • 举报
回复
引用 14 楼 caibirdcnb 的回复:
确实是必须存在第三个构造器。 我明白你的代码没有第三个构造器,只是按照你的意思,必须有第三个构造器的存在。请看下面解释: 一个数据源包含no、name、weight。(3个变量)另一个数据源包含no和height。(2个变量) 按照你给的代码,主构造器包含了4个变量,不符合要求。所以必须去掉1个, 我结合你给的代码和我的需求,写了发现需要3个构造器的。 你给的代码: data class Student(val no: Int, val name: String, val height: Int, val weight: Int) { constructor(no: Int) : this(no, "", 0, 0) } 我自己改的: data class Student(val no: Int, val name: String, val height: Int, val weight: Int) { constructor(no: Int, height: Int) : this(no, "", 0, 0) constructor(no: Int, name: String, weight: Int) : this(no, "", 0, 0) }
你多写了一个构造器肯定会多出来一个的,在我回答你之前请问一下为什么你不允许有一个拥有所有信息的源创建对象
caibirdcnb 2021-05-24
  • 打赏
  • 举报
回复
引用 13 楼 雪下的回忆 的回复:
[quote=引用 12 楼 caibirdcnb 的回复:] 我觉得我应该明白你的意思,但是,确实不满足我的需求。我的需求之一就是必须只有两个构造器,上次回复我特意用红色字体说明了。 但是你的方法明显有3个构造器,这样的话,有人调用第3个构造器就可能破坏程序。 (而如果我不使用数据类,我确实能实现我的需求,就是只有2个构造器。但遗憾的是,我这个类确实是个数据类,然而却只能用非数据类的方式实现需求。你明白我为难的地方了吗?就是那种不完美的遗憾)
哪来的第三个构造器,kotlin默认不支持无参构造,一个主构造一个从构造还有一个哪来的,你跑过我的代码没有[/quote] 确实是必须存在第三个构造器。 我明白你的代码没有第三个构造器,只是按照你的意思,必须有第三个构造器的存在。请看下面解释: 一个数据源包含no、name、weight。(3个变量)另一个数据源包含no和height。(2个变量) 按照你给的代码,主构造器包含了4个变量,不符合要求。所以必须去掉1个,
引用 13 楼 雪下的回忆 的回复:
[quote=引用 12 楼 caibirdcnb 的回复:] 我觉得我应该明白你的意思,但是,确实不满足我的需求。我的需求之一就是必须只有两个构造器,上次回复我特意用红色字体说明了。 但是你的方法明显有3个构造器,这样的话,有人调用第3个构造器就可能破坏程序。 (而如果我不使用数据类,我确实能实现我的需求,就是只有2个构造器。但遗憾的是,我这个类确实是个数据类,然而却只能用非数据类的方式实现需求。你明白我为难的地方了吗?就是那种不完美的遗憾)
哪来的第三个构造器,kotlin默认不支持无参构造,一个主构造一个从构造还有一个哪来的,你跑过我的代码没有[/quote] 我结合你给的代码和我的需求,写了发现需要3个构造器的。 你给的代码: data class Student(val no: Int, val name: String, val height: Int, val weight: Int) { constructor(no: Int) : this(no, "", 0, 0) } 我自己改的: data class Student(val no: Int, val name: String, val height: Int, val weight: Int) { constructor(no: Int, height: Int) : this(no, "", 0, 0) constructor(no: Int, name: String, weight: Int) : this(no, "", 0, 0) }
雪下的回忆 2021-05-23
  • 打赏
  • 举报
回复
引用 12 楼 caibirdcnb 的回复:
我觉得我应该明白你的意思,但是,确实不满足我的需求。我的需求之一就是必须只有两个构造器,上次回复我特意用红色字体说明了。 但是你的方法明显有3个构造器,这样的话,有人调用第3个构造器就可能破坏程序。 (而如果我不使用数据类,我确实能实现我的需求,就是只有2个构造器。但遗憾的是,我这个类确实是个数据类,然而却只能用非数据类的方式实现需求。你明白我为难的地方了吗?就是那种不完美的遗憾)
哪来的第三个构造器,kotlin默认不支持无参构造,一个主构造一个从构造还有一个哪来的,你跑过我的代码没有
caibirdcnb 2021-05-22
  • 打赏
  • 举报
回复
引用 11 楼 雪下的回忆 的回复:
[quote=引用 10 楼 caibirdcnb 的回复:] 非常感谢! 但我看不懂您的代码如何满足我的要求。 我的要求是: 需要获取学生的no、name、height、weight。 一个数据源包含no、name、weight。另一个数据源包含no和height。 需求的两种初始化方式如下面所示,而且必须只有这两种方式
val wt = Student(21, "Zhang San", 65)
val ht = Student(21,170)
这样都看不懂吗,不加 constructor的时候默认有一个初始的全部赋值的构造方法,加一个constructor的附属构造方法,仅传入部分值,剩余的值在方法内调用初始构造方法初始化就好,这样一个初始构造方法一个附属构造方法刚好只有两个。 这样都看不懂的话你以后没办法用kotlin的哦,我不会直接给你最终的版本的,这个内容很简单你尝试改一下。[/quote] 我觉得我应该明白你的意思,但是,确实不满足我的需求。我的需求之一就是必须只有两个构造器,上次回复我特意用红色字体说明了。 但是你的方法明显有3个构造器,这样的话,有人调用第3个构造器就可能破坏程序。 (而如果我不使用数据类,我确实能实现我的需求,就是只有2个构造器。但遗憾的是,我这个类确实是个数据类,然而却只能用非数据类的方式实现需求。你明白我为难的地方了吗?就是那种不完美的遗憾)
雪下的回忆 2021-05-20
  • 打赏
  • 举报
回复
引用 10 楼 caibirdcnb 的回复:
非常感谢! 但我看不懂您的代码如何满足我的要求。 我的要求是: 需要获取学生的no、name、height、weight。 一个数据源包含no、name、weight。另一个数据源包含no和height。 需求的两种初始化方式如下面所示,而且必须只有这两种方式
val wt = Student(21, "Zhang San", 65)
val ht = Student(21,170)
这样都看不懂吗,不加 constructor的时候默认有一个初始的全部赋值的构造方法,加一个constructor的附属构造方法,仅传入部分值,剩余的值在方法内调用初始构造方法初始化就好,这样一个初始构造方法一个附属构造方法刚好只有两个。 这样都看不懂的话你以后没办法用kotlin的哦,我不会直接给你最终的版本的,这个内容很简单你尝试改一下。
caibirdcnb 2021-05-19
  • 打赏
  • 举报
回复
引用 8 楼 雪下的回忆 的回复:
[quote=引用 7 楼 雪下的回忆 的回复:] kotlin的数据类会自动生成一个构造方法,而且在使用constructor关键字重新方法之后并不会像java一样去掉默认的无参构造,所以你写了两个constructor肯定会有三个构造方法的,如果想要修改默认的构造方法请使用init代码块,网上有资料自己查。 然后是kotlin里你不需要去手动地给关键字赋值,构造方法自己会生成对应的属性并且赋值的,this.xxx=xxx可以直接删了不影响。 最后给了默认参数是不需要再输入的,它会自动给你生成一个构造函数。 以下是我的代码,你可以自己看看编译后的java源码,kotlin还是要深入理解一下的

data class Student(val no: Int, val name: String,val height: Int, val weight: Int) {
    constructor(no: Int) : this(no, "", 0, 0)
}
这个是我的代码运行截图,应该是可以满足你的要求的 [/quote] 非常感谢! 但我看不懂您的代码如何满足我的要求。 我的要求是: 需要获取学生的no、name、height、weight。 一个数据源包含no、name、weight。另一个数据源包含no和height。 需求的两种初始化方式如下面所示,而且必须只有这两种方式
val wt = Student(21, "Zhang San", 65)
val ht = Student(21,170)
caibirdcnb 2021-05-19
  • 打赏
  • 举报
回复
引用 6 楼 孤独的冥王星 的回复:
1. 首先说一下你所谓的多出一个构造器的问题 数据类主构造函数需要至少有一个参数 2. 再说一下你创建的次级构造函数的问题 不是kotlin语言的逻辑缺少,是你的逻辑有问题,不同数据源非要用一个class,用一个class就算了还要限制构造函数的个数
可是,如果不使用数据类,使用普通类,我确实能实现我的需求:也就是一个类,只有2个构造函数。 但问题是,我这个类确实是个数据类,然而我不能用数据类实现。
雪下的回忆 2021-05-07
  • 打赏
  • 举报
回复
引用 7 楼 雪下的回忆 的回复:
kotlin的数据类会自动生成一个构造方法,而且在使用constructor关键字重新方法之后并不会像java一样去掉默认的无参构造,所以你写了两个constructor肯定会有三个构造方法的,如果想要修改默认的构造方法请使用init代码块,网上有资料自己查。 然后是kotlin里你不需要去手动地给关键字赋值,构造方法自己会生成对应的属性并且赋值的,this.xxx=xxx可以直接删了不影响。 最后给了默认参数是不需要再输入的,它会自动给你生成一个构造函数。 以下是我的代码,你可以自己看看编译后的java源码,kotlin还是要深入理解一下的

data class Student(val no: Int, val name: String,val height: Int, val weight: Int) {
    constructor(no: Int) : this(no, "", 0, 0)
}
这个是我的代码运行截图,应该是可以满足你的要求的
雪下的回忆 2021-05-07
  • 打赏
  • 举报
回复
引用 4 楼 caibirdcnb 的回复:
这么设计数据类,是因为需求就是这样啊,请看下面详细描述。 需要获取学生的no、name、height、weight。 一个数据源包含no、name、weight。另一个数据源包含no和height。 假设建立下面所示的类:

data class Student(val no: Int, val name: String = "", val height: Int = 0, val weight: Int = 0) {
}
这样初始化:

val wt = Student(21, "Zhang San", 0, 65)
val ht = Student(21,"",170)
问题有两个: 第一,已经给name、height、weight默认值了,但初始化的时候还需要再输入一次。 第二,wt的height必须是默认值0,但上面的初始化无法保证,例如wt = Student(21, "Zhang San", -999, 65)。ht同理。 需求的两种初始化方式如下面所示,而且必须只有这两种方式。但似乎无法实现:

val wt = Student(21, "Zhang San", 65)
val ht = Student(21,170)
比如,我建立下面所示的类,会有3个构造器,多出1个构造器。

data class Student(val no: Int) {
    var name = ""
    var height = 0
    var weight = 0

    constructor(no: Int, name: String, weight: Int) : this(no) {
        this.name = name
        this.weight = weight
    }

    constructor(no: Int, height: Int) : this(no) {
        this.height = height
    }
}
kotlin的数据类会自动生成一个构造方法,而且在使用constructor关键字重新方法之后并不会像java一样去掉默认的无参构造,所以你写了两个constructor肯定会有三个构造方法的,如果想要修改默认的构造方法请使用init代码块,网上有资料自己查。 然后是kotlin里你不需要去手动地给关键字赋值,构造方法自己会生成对应的属性并且赋值的,this.xxx=xxx可以直接删了不影响。 最后给了默认参数是不需要再输入的,它会自动给你生成一个构造函数。 以下是我的代码,你可以自己看看编译后的java源码,kotlin还是要深入理解一下的

data class Student(val no: Int, val name: String,val height: Int, val weight: Int) {
    constructor(no: Int) : this(no, "", 0, 0)
}
孤独的冥王星 2021-05-07
  • 打赏
  • 举报
回复
1. 首先说一下你所谓的多出一个构造器的问题 数据类主构造函数需要至少有一个参数 2. 再说一下你创建的次级构造函数的问题 不是kotlin语言的逻辑缺少,是你的逻辑有问题,不同数据源非要用一个class,用一个class就算了还要限制构造函数的个数
caibirdcnb 2021-04-27
  • 打赏
  • 举报
回复
这么设计数据类,是因为需求就是这样啊,请看下面详细描述。 需要获取学生的no、name、height、weight。 一个数据源包含no、name、weight。另一个数据源包含no和height。 假设建立下面所示的类:

data class Student(val no: Int, val name: String = "", val height: Int = 0, val weight: Int = 0) {
}
这样初始化:

val wt = Student(21, "Zhang San", 0, 65)
val ht = Student(21,"",170)
问题有两个: 第一,已经给name、height、weight默认值了,但初始化的时候还需要再输入一次。 第二,wt的height必须是默认值0,但上面的初始化无法保证,例如wt = Student(21, "Zhang San", -999, 65)。ht同理。 需求的两种初始化方式如下面所示,而且必须只有这两种方式。但似乎无法实现:

val wt = Student(21, "Zhang San", 65)
val ht = Student(21,170)
比如,我建立下面所示的类,会有3个构造器,多出1个构造器。

data class Student(val no: Int) {
    var name = ""
    var height = 0
    var weight = 0

    constructor(no: Int, name: String, weight: Int) : this(no) {
        this.name = name
        this.weight = weight
    }

    constructor(no: Int, height: Int) : this(no) {
        this.height = height
    }
}
caibirdcnb 2021-04-27
  • 打赏
  • 举报
回复
引用 3 楼 立青_ 的回复:
而且属性不写在主构造,就不是数据字段,所以最好一个构造就够了 而且不明白你么这么设计数据类的意义
请参见我的上一个回帖,谢谢!
立青_ 中级 2021-04-26
  • 打赏
  • 举报
回复
而且属性不写在主构造,就不是数据字段,所以最好一个构造就够了 而且不明白你么这么设计数据类的意义
立青_ 中级 2021-04-26
  • 打赏
  • 举报
回复
kotlin可以有默认参数,没必要重载构造方法

80,351

社区成员

发帖
与我相关
我的任务
社区描述
移动平台 Android
androidandroid-studioandroidx 技术论坛(原bbs)
社区管理员
  • Android
  • yechaoa
  • 失落夏天
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧