1、类的构造,构造函数
Java中的Activity类写法如下:
public class MainActivity extends BaseActivity {
......
}
Kotlin中的Activity类写法如下:
class MainActivity : BaseActivity() {
……
}
做个简单的对比发现,Kotlin对类的写法与Java之间有以下几点区别:
- Kotlin省略了关键字public,源于Kotlin默认就是开放的。
- Kotlin用冒号“:”代替了extends,也就是通过冒号表示继承关系。
- Kotlin进行继承时,父类后面多了一个小括号“()”。其他方面区别不大,
再来,我们继续寻找二者不一致的地方:
class Category {
init {
println("Category的初始化")
}
}
var mCategory = Category()
运行上面的代码,可以看到控制台输出了如下信息:Category的初始化。哈哈,看到这里是不是有点感想了?是不,不错,这里也表现出了Kotlin与Java的的几点不同:
- Java里面对一个类的初始化,是通过构造方法实现的,分有参构造和无参构造。而Kotlin里面类的初始化则是通过关键字init实现的。
- Kotlin在创建类的实例对象时没有用到关键字new,因为他压根儿就没有“new”这个关键字。
- Kotlin的初始化函数init只是其构造函数的一部分,相当于Java的无参构造。要定义接收输入参数的构造方法还需要别的方法实现,这个我们接下来讨论。
关于有参构造的重载,我们先直接上代码:
class Category {
// 默认的init构造函数不是必须的,而且无论是调用init默认构造函数还是二级构造函数,init方法都会
// 被默认执行,这样就太不友好了。因此当我们不需要的时候,就完全可以注释掉该函数
//init {
//println("Category的初始化")
//}
constructor(mContext: Activity){
println(mContext.localClassName)
}
constructor(mContext: Activity, name:String, age:Int) {
println("Activity的名字:${mContext.localClassName},用户名字:$name,年龄大小:$age")
}
constructor(name:String, age:Int) {
println("用户名字:$name,年龄大小:$age")
}
}
// 下面的代码,我们创建了三个Category的对象,按我们预计的,Category.kt里面的init默认构造不会
// 执行才对,但实际上是每当我们创建一个Category对象的时候,init默认构造就会被执行一次。
// 因此若不是必须,init默认构造最好不让他存在
var mCategory1 = Category(this)
var mCategory2 = Category("我的晓晓宝贝", 9999)
var mCategory3 = Category(this, "晓晓",999)
Kotlin的构造方法也可以像前面我们学习的普通方法那样设置默认参数——带默认参数的构造函数:
class Category {
constructor(mContext: Activity, age:Int, name:String="baby晓晓") {
println("Activity的名字:${mContext.localClassName},用户名字:$name,年龄大小:$age")
}
constructor(age:Int, name:String="晓晓,老婆") {
println("用户名字:$name,年龄大小:$age")
}
}
var mCategory2 = Category(9999)
var mCategory3 = Category(this, 999)
观察上面的代码,我们发现两个构造方法都用到了前面我能学到方法设置默认参数,另外,这里我们都对那么这个参数设置了默认数据,这样,我们在使用的时候如果不是特别需要,可以不用再设置参数。同样的,我们还可以对age年龄这个参数也这么设置,这样就只剩下一个mContext参数了。
到了这里,估计你会觉得有点怪怪的,一个方法明明大部分参数都一样,就一个不一样,但还得写两个方法,怎么看怎么别扭。是不是可以优化一下?嗯,老铁,你太优秀了,估计快赶上爱因斯坦了,是的,我们还可以优化,优化后如下:
class Category {
constructor(mContext: Activity, age:Int=16, name:String="baby晓晓") {
println("Activity的名字:${mContext.localClassName},用户名字:$name,年龄大小:$age")
}
}
var mCategory1 = Category(this)
var mCategory2 = Category(this,9999)
var mCategory3 = Category(this, 999, "宝贝老婆晓晓")
这样,原本多个参数多个构造方法的结构被改造为只有一个方法包含多个参数的结构,这样代码逻辑更加简洁明了,便于阅读。调用的时候也很方便,只针对一个方法,赋予不同的值即可。
但上面的实现方式都不是kotlin构造方法的最优实现方式。最优最简洁的实现方式是这样的:
kotlin最大众化的流行构造方法实现方式,我们还可以给构造方法设置默认参数。
毕竟在Java里面,当我们需要传不同类型和数量的参数给一个类时,通常是通过该类的构造方法的重载来实现的;
现在我们可以通过给构造方法设置默认参数的形式来实现,避免更多的样板代码。
在写法上,下面的方式还不是最简单的,更简单的见ConstructorClass.kt
class ConstructorClass(var x: Int = 0, var y: Int = 5, var z: String = "ClassAndInterface") {
fun logging(obj:Any){
println("输入的数据是:${obj.toString()}")
}
fun screenInputParams(){
println("构造方法输入的数据是:XX === $x,YY === $y, ZZ === $z")
}
}
因为在构造方法里面参数的前面我们添加了创建成员变量的关键字“var”,因此构造方法里面的变量我们是可以直接拿来用的,他跟我们在class类里面创建的成员变量没有区别。
然后我们再来看看在main(args: Array)方法里面的调用执行情况:
fun main(args: Array<String>) {
//ClassAndInterfaceThird的构造方法传入参数。
var classAndInterOne = ConstructorClass(1,9, "秋水浮萍任缥缈")
classAndInterOne.screenInputParams()
//ClassAndInterfaceThird的构造方法不传参数,使用默认参数
var classAndInterTwo = ConstructorClass()
classAndInterTwo.logging(123)
classAndInterTwo.logging(classAndInterTwo.z)
}
这样在Kotlin里面到时完美了,但是还存在一个问题,我要和Java进行交互怎么办?毕竟Java和kotlin的混合开发现在还是很普遍的,尤其是老项目里面。Java里面可是多个方法进行重载,他可不认识什么默认数据的设置这些花招。客官别急,既然Kotlin想出了这个完美的结构,那么就肯定有办法实现与Java的交互,这不kotlin给我提供了一个新的关键字:JvmOverloads,通过他就可以实现Javahekotlin在构造方法上的交互,使用方式如下:
class Category {
@JvmOverloads
constructor(mContext: Activity, age:Int=16, name:String="baby晓晓") {
println("Activity的名字:${mContext.localClassName},用户名字:$name,年龄大小:$age")
}
}
public class Constructor {
Activity activity;
Category mCategory1 = new Category(activity);
Category mCategory2 = new Category(activity,999);
Category mCategory3 = new Category(activity,999, "老婆,我想你");
}
注意看上面代码里面的标不同颜色,不同加粗形式的代码:@JvmOverloads就是告诉Java这个是给你提供重载用的。
总结:Kotlin给类的构造函数引入了新的关键字constructor并且区分了柱构造函数和二级构造函数,柱构造函数的入参在类名后面声明,函数体则位于init方法块里面;耳机构造函数从属于柱构造函数,他不但有柱构造函数派生而来,还必须先调用柱构造函数的具体实现。另外Kotlin也支持默认参数的设置,从而避免荣誉的构造函数的定义。
2、类的成员:属性、方法、对象
a、成员属性:
Kotlin舍弃了Java那套的get/set方法,而是把构造函数的输入参数保存到类的属性中,无论输入参数有几个,该类都依葫芦画瓢地声明同样数量的属性字段并加以赋值。
class Animal(var name:String, val sex:String="male") {
......
}
var mAnimal = Animal("tiger", "male")
logging("this ${mAnimal.name} is ${mAnimal.sex}, and very Strong")
注意上面标红加粗的关键字var和val,这里是为了专门示例定义成员属性的时候的注意事项,特意用到了两个关键字,实际开发中根据需要确定用哪一个关键字。
这样确实省去了很多的麻烦,但是又引发了另一个问题,我要使用构造函数的时候怎么办?很明显二者的最优结构是无法同时满足的。使用的使用要权衡利弊,合理选择。也可以这样:
class Category {
var mAge:Int = 0;
var mName:String? = null;
@JvmOverloads constructor(mContext: Activity, age:Int=16, name:String="baby晓晓") {
mAge = age;
mName = name;
}
fun impFunction(){
println("作者年龄大约$mAge,作者名字是$mName")
}
}
var mCategory3 = Category(this, 999, "宝贝老婆晓晓")
mCategory3.impFunction()
println("在主方法里面通过对象调属性:年龄${mCategory3.mAge}, 名字${mCategory3.mName}")
b、成员方法:
一个类里面,除了成员变量,还有成员方法,比如上面例子中的impFunction()方法就是成员方法。要在类的外部调用该类的成员方法,其实Java很相似的,都是先创该类的对象,然后通过对象来调用。
c、伴生对象
其作用就相当于Java的static关键字。Kotlin没有static功能的关键字,取而代之的是companion关键字,但他要和object关键字组合使用,用法如下:
class Animal(var name:String, var sex:String="male") {
companion object CatAnimal{
fun describeTiger(type:String, sexType:String):String{
return "this $type is $sexType, and it is very very very Strong"
}
}
}
logging(Animal.describeTiger(mAnimal.name, mAnimal.sex))
上面红色加粗的部分即起到static静态功能的作用,二者要组合使用,缺一不可。蓝色加粗的部分即是伴生对象,通过他来访问里面的方法。单纯的加粗部分即为调用方式。
d、静态属性
其实从名字就可以知道他对标的就是Java的static修饰的属性变量,其调用方法如下:
class Animal(var name:String, var sex:String="male") {
companion object CatAnimal{
var TIGER = 1
var CHEETAH = 2
fun describeTiger(code:Int, sexType:String):String{
var type = if(code == 1) "老虎" else "猎豹"
return "this ${type} is $sexType, and it is very very fast when it running"
}
}
}
logging(Animal.describeTiger(Animal.CHEETAH, "female"))
上面蓝色加粗的代码就是Kotlin的静态属性的调用方法,可以看到静态属性变量也是要写在半生对象里面的。这一点要注意。
3、类的继承
a、开放新修饰符
在Java里面,每个默认的class类都是可以被继承的,除非是被关键字final修饰的class类。但是在Kotlin里面,他默认每个类都是不可以被继承的,也就是morning每隔类都是被final修饰的。那么我们要让指定的类被继承该怎么办呢?嗯,要用到一个全新的关键字——“open”。是的,确定那个类允许被继承,就在那个类的class关键字前面加上open关键字,就表示这个类是开放的,可以被继承。
Kotlin里面除了open这个开放性修饰符外,还有以下几个开放性修饰符。
open class Animal() {
fun getDescribe(){ }//默认是public开放的,因此public可以省略
internal fun getDescribe(name:String){
......
}
protected fun getDescribe(age:Int){
......
}
private fun getDescribe(des:Double){
......
}
}
class Tiger : Animal() {
......
}
另外,在同一个.kt文件中,open和private是不允许共存的,否则编译报错:“Modifier ‘open’ is incompatible with ‘private’”
b、普通类继承
这一点,除了遵循前面a中提到的那些规则外,其他的逻辑基本上跟Java是一样的。不再累述。
c、抽象类
关于这一点其实跟Java相差不大,抽象类也是以abstract关键字来定义的,而且其抽象方法也是这样,同样的抽象方法里面可以定义属性变量,也可以有自己的具体方法实现,但是至少要保留一个关键字abstract修饰的抽象方法,否则这个类就不再是抽象类了。
abstract class Mammal : Animal("哺乳动物","Unknown"){
var characteristic:String = "草食动物相对温顺,肉食动物则凶猛霸道"
abstract fun foodType(describe:String)
fun printCharacteristic(){
println(characteristic)
}
}
class Cow :Mammal() {
override fun foodType(describe:String) {
println(describe)
}
}
var mCow = Cow();
mCow.printCharacteristic()
mCow.foodType("以植物为食物来源的动物是草食性动物。以其他动物为食物来源的动物是肉 食性动物。不过还有一些动物的食物来源很杂,既吃肉,也吃食物,他们是 杂食性动物。但他们都是${mCow.name},然后也分雌雄的")
上面创建了一个名为Mammal的抽象类,继承于Animal这个类。然后在里面定义了一个字符串变量characteristic、一个名为foodType()的抽象方法、还有一个名为printCharacteristic()的有具体实现的方法。
d、接口
Kotlin也是单继承的,其定义接口的目的跟Java一样是为了解决无法实现多继承这一问题,定义的关键字也是interface。Kotlin的接口 也有其以下几个特点:
-
接口内部不定定义构造函数,否则编译会报错。
-
接口内部方法默认都是抽象方法,默认不用加abstract关键字,也默认是开放的,所以不用加open关键字
-
接口内部可以定义未经赋值,仅仅声明了类型的变量;实现接口的类必须重载该属性。
-
与Java不同的是Kotlin允许接口内部有具体的方法实现,而不是像Java那样严格要求所有的方法都必须是抽象方法。但一旦是经具体实现的方法,就不能在其前面加上abstractt关键字。
-
Java里面的继承和实现分别是通过extends和implement两个关键字实现的,Kotlin里这两个关键字都被符号“:”替代了。
interface InterAnimal { //定义未经赋值,仅仅声明了类型的变量 var animalName: String fun animal() //Kotlin允许接口内部有具体的方法实现 fun classifyAnimal(){ println("动物分类") } } //":"即具有继承“Extends”的功能,也有implement实现的功能 class XiaoXiao :InterAnimal { // 接口内部可以定义未经赋值,仅仅声明了类型的变量;实现接口的类必须重载该属性 override var animalName: String = "Garfield" override fun animal(type:String) { println("type") } }
2020年9月6日补充一:
kotlin的继承与Java不同有三点:
一、Java里面的实现继承用的是关键字“extends”,kotlin里面实现继承用的还是冒号“:”,与接口的实现是一致的;
二、Java里面的继承是关键字“extends”后面直接跟抽象类的类名,而kotlin里面则是冒号“:”后面跟抽象类的类名加(),即:“抽象类类名:()”。表示调用抽象类的构造方法,但是这个构造方法我们通常是没有写出来的,因此调用的是他的默认的无参构造。就类似Java的默认的无参构造一样。
三、在kotlin里面,普通类如果想要能够被别的类继承的话,那么就必须在class前面加关键字“open”来进行标识。
open class ConstructorClass(var x: Int = 0, var y: Int = 5, var z: String = "ClassAndInterface")
:KotlinInterface, KotlinAbstract() {
var encryptionMsg = ""
fun logging(obj:Any){
println("输入的数据是:${obj.toString()}")
}
fun screenInputParams(){
println("构造方法输入的数据是:XX === $x,YY === $y, ZZ === $z")
}
//加密
override fun encryption(oldParams: String, format: String) {
//md5String(md5String:String):抽象类父类KotlinAbstract有具体的实现。
encryptionMsg = "${md5String(oldParams.reversed())}${format.reversed()}${defaultFormat}"
println("加密之后的信息:$encryptionMsg")
}
//解密
override fun decryption(oldParams: String, format: String) {
//调用接口的方法实现打印
print("解密之后的结果:${oldParams.reversed()}${format.reversed()}")
}
//重写父类的开放性方法:voerrideDecode()
override fun overrideDecode() {
super.overrideDecode()
print("在kotlin里面,如果一个方法允许继承他的类重写的话,那么就必须在该方法的前面加“open”关键字。\n" +
"否则,没有“open”关键字修饰的具体实现的方法一律不允许被重写。")
println("直接调用接口Interface定义的常量:$defaultTime")
}
//我们还可以在这里重新给接口定义的常量赋值。注意写法
override val defaultTime:Long get(){
return System.nanoTime()
}
}
无论是在Java里面还是在kotlin里面,接口的所有方法都是可以被实现它的类复写的。
不同的是,在kotlin的接口里面,并不是所有的方法都是抽象方法,它是可以有自己的具体实现类的。也可以定义常量值,注意写法。
interface KotlinInterface{
val defaultTime: Long
get() = System.currentTimeMillis()
fun encryption(oldParams:String, format:String)
fun print(msg:String){
println("TAGTAG------>>>$msg")
}
}
在kotlin的抽象类里面,我们可以像Java抽象类那样定义变量,定义抽象方法,定义具体实现的方法;
但是有一点需要注意的是:在kotlin里面,如果一个方法允许继承他的类重写的话,那么就必须在该方法的前面加“open”关键字。否则,没有“open”关键字修饰的具体实现的方法一律不允许被重写。
abstract class KotlinAbstract{
var defaultFormat = "yyyy--mm--dd HH:mm:ss"
abstract fun decryption(oldParams:String, format:String)
fun md5String(md5String:String): String {
return "$defaultFormat${md5String.reversed()}"
}
open fun overrideDecode(){
}
}
在main(args: Array)里面的运行:
println("==============================================================================================")
var classAndInterThree = ConstructorClass()
//调用加密
classAndInterThree.encryption("宫本总司:无极剑法--还珠楼主:缥缈剑法--西经无缺:摩柯剑法",
"无常无定---无形无相---空无之境:摩柯无量")
//调用解密
classAndInterThree.decryption(classAndInterThree.encryptionMsg, "")
//调用复写自父类的open方法
classAndInterThree.overrideDecode()
运行结果如下:
2020年9月6日补充二:
注意:我们创建的ClassAndInterfaceFour类,继承了ClassAndInterfaceFive类,但是我们的ClassAndInterfaceFive类在创建的时候,设置了默有参的构造方法,因此这里我们继承自ClassAndInterfaceFive类的ClassAndInterfaceFour类,也要设置构造方法,并传参数给他的父类。
这里我们还可以继续重写overrideDecode()方法。
但是我想这个方法到我这里就截止了,后面的继承我的子类就不在允许重写这个方法了,怎么办?
我们可以在前面加一个关键字“final”
open class ClassAndInterfaceFour(xx: Int, yy: Int, msg: String) : ClassAndInterfaceFive(xx, yy, msg) {
final override fun overrideDecode() {
super.overrideDecode()
println("继承的子类ClassAndInterfaceFive.kt的子类ClassAndInterfaceFour.kt里面我们还可以继续重写overrideDecode()方法。")
}
}
作为被继承的父类ClassAndInterfaceFive.kt如下:
open class ClassAndInterfaceFive(x: Int , y: Int, z: String) :KotlinAbstract() {
override fun decryption(oldParams: String, format: String) {
//TODO("Not yet implemented")
}
override fun overrideDecode() {
super.overrideDecode()
}
}
更进一步的继承关系及技术点ClassAndInterfaceSix.kt:
我们可以发现,继承ClassAndInterfaceFour.kt之后,我们就只能重写decryption(oldParams: String, format: String)这个方法了,不能够在重写overrideDecode()这个方法,因为在他的父类ClassAndInterfaceFour.kt里面做了final限制。因此,我们也可以发现,在kotlin里面也是有“final”关键字的,不同于Java的是
kotlin里面的“final”关键字只是用于更改被“open”关键字修饰的方法的重写权限这一方面。
class ClassAndInterfaceSix(xxx: Int, yyy: Int, msg: String) :ClassAndInterfaceFour(xxx, yyy, msg) {
override fun decryption(oldParams: String, format: String) {
super.decryption(oldParams, format)
println("在这里,我们就发现,继承自ClassAndInterfaceFour.kt之后,我们就只能重写decryption(oldParams: String, format: String)" +
"这个方法了,不能够在重写overrideDecode()这个方法,因为在他的父类ClassAndInterfaceFour.kt里面做了final限制。" +
"因此,我们也可以发现,在kotlin里面也是有“final”关键字的,不同于Java的是,kotlin里面的“final”关键字只是用于更改" +
"被“open”关键字修饰的方法的重写权限这一方面。")
}
}
在main(args: Array)函数里面调用运行结果如下:
2020年9月6日补充三:
类似数据解析的一个bean文件
在kotlin里面这样的写法相当于同时实现了Java的bean文件里面的get/set方法。
就比如下面变量那么的get/set方法。等价于Java里面的get/set方法。
通常,kotlin里面已经默认帮我们实现了get/set方法,我们不用再写这样的模板代码
class ClassAndInterfaceSeven(age: Int, name: String) {
var mAge = age
//这里我们也可以对变量name做类似Java的get/set方法,如果只是使用默认的get/set,那我们完全可以省略。
//需要自定义的时候再写:
var mName = name
get() {
return field
}
set(value) {
field = value
}
}
在main(args: Array)函数里面的调用
var seven = ClassAndInterfaceSeven(18,"美女妹妹")
var age01 = seven.mAge
var name01 = seven.mName
我们还可以这样来获取:
var age02: KMutableProperty0<Int> = seven::mAge
var name02: KMutableProperty0<String> = seven::mName
age02.set(20)
上面获取ClassAndInterfaceSeven的age和name属性的方式还可以这样来写:
var age03 = ClassAndInterfaceSeven::mAge
var name03 = ClassAndInterfaceSeven::mName
f、总结:
- Kotlin的类默认不可被继承,若需要被继承,需要在class前面加“open”关键字;而Java是默认允许被继承的,只有被final关键字修饰的类才不能被继承。
- Kotlin除了常规的三个开放性修饰符public、protected、private外,新增了internal修饰符,便是只对本模块开放。
- Java类中表示继承的extends和实现implement关键字在Kotlin中都被“:”冒号所取代。
- Kotlin允许在接口内部定义有具体实现的方法,而Java接口内部则只允许抽象类的存在。
- Kotlin引入了接口代理的概念,Java不存在这个。但是接口代理跟Java的代理模式差不多。
4、几种特殊类
a、嵌套类:
其实本质上就是内部类,但与Java的内部类相比,Kotlin的嵌套类(内部类)有一些差别:嵌套类不能访问外部类的成员变量,强行访问,会报错“Unresolved reference:******”,意思是找不到这个类。
class InnerClass {
var strName:String = "这是外部类定义的一个成员变量"
class ChildClass{
var childName = "这是嵌套类定义的一个成员变量"
fun printlnVar(){
println("在嵌套类里面打印几个变量的值:首先是嵌套类的成员变量:$childName")
}
}
}
var childClass = InnerClass.ChildClass()
childClass.printlnVar()
嵌套类的使用要注意黑体加粗部分代码。
b、内部类
其实本质上就是对嵌套类做了一个华丽的转型,转型的方式就是在嵌套类的class前面加上关键字“inner”,表示这是一个内部类,不再是嵌套类了:
class InnerClass {
var strName:String = "这是外部类定义的一个成员变量"
private fun outClassFunctioin(content:String){
println("$content, 在外部类里面的打印日志:$strName")
}
inner class InnerChildClass(var content:String){
var childName = "这是内部类定义的一个成员变量"
fun printlnVar(){
outClassFunctioin("在内部类里面也是可以调用外部了的成员方法的,哪怕是被private修饰的 方法")
println("在内部类里面是可以访问外部类的成员变量和信息的:首先是内部类的成员变量: $childName,然后是外部类的成员变量:$strName,最后是内部类构造方法的入参:$content")
}
}
}
var mInnerChildClass = InnerClass().InnerChildClass("正在的内部类")
mInnerChildClass.printlnVar()
内部类的调用与嵌套类的调用要注意以下几点:
1、在嵌套类的关键字class前面加上关键字inner,这样嵌套类就华丽的变为内部类。
2、嵌套类不能访问外部类的任何成员变量和任何成员方法。
3、声明嵌套类的对象格式是:外部类.嵌套类();声明内部类的对象的格式是:外部类().内部类();
4、内部类可以访问外部类的所有成员变量和成员方法,哪怕是被privte修饰的变量和方法。
c、枚举类
ava中的枚举类是通过关键字enum定义的。但是创建方式不一样。Java的枚举类型是这么创建的:
enum Season { SPING, SUMMER, AUTUMN, WINTER}
Kotlin中的枚举类是这样创建的:
enum class SeasonType(var seasonName:String){
SPING(“春天”), SUMMER(“夏天”), AUTUMN(“秋天”), WINTER(“冬天”)
}
使用实例如下:
enum class EnumClass (var seasonName:String) {
SPING("春天"),SUMMER("夏天"),AUTUMN("秋天"),WINTER("冬天")
}
var enumStr = ""
var mod:Int = (System.currentTimeMillis() %3).toInt()
when(mod){
0->enumStr = EnumClass.SPING.seasonName
1->enumStr = EnumClass.SUMMER.seasonName
2->enumStr = EnumClass.AUTUMN.seasonName
else->enumStr = EnumClass.WINTER.seasonName
}
println("mod模值是:$mod,对应地获取到的是$enumStr 这个季节")
d、密封类
密封类就像是一种更加严格的枚举类,他的内部有且仅有自身的实例对象,是一个有限的自身实例集合。具体使用的时候再来详勘
e、数据类
这里的数据类型,可以理解为Java里面的对象实体类,比如我们网络请求回来后数据解析时用到的解析类就属于数据类型。Java中我们 要事先定义好各个属性,然后再是各种get/set方法,再是toString()方法 ,方便打印。最后是序列化。使用起来相对比较麻烦。
Kotlin为了省去这些麻烦,提出了自己的一套解决方案:在数据类的class关键字前面增添关键字“data”,并声明拥有完整输入参数的构造函数,即可无缝实现以下功能:
1、自动声明与构造函数入参同名的属性字段。
2、自动实现每隔属性字段的get/set方法。
3、自动提供equals方法,用于比较两个数据对象是否相等。
4、自动提供copy方法,用于允许完整赋值某个数据对象,也可以在赋值后单独的修改某几个字段的值。
5、自动提供toString方法,用于打印数据对象中保存的所有字段值。
data class ParseDataBean(
//数据类型必须有柱构造函数并且至少有一个入参
//并且要声明与输入参数同名的属性,即输入参数前面添加关键字var或者val
//数据类不能是基类也不能是子类,也不能是抽象类、内部类,更不能是嵌套类
var developCount: String, var developCountValue: String,
var inputResource: String, var inputResourceValue: String,
var inputCountValue: String, var inputCount: String) {
}
var parseData = ParseDataBean("开发数量", "500", "投入资源数量", "1000", "计划投入总量", "1200")
logging("toString()方法:${parseData.toString()}")
var parseDataCopy = parseData.copy(inputCountValue="已完成投入量", inputCount="999")
var same = if (parseData.equals(parseDataCopy)) "相同" else "不相同"
logging("parseData和parseDataCopy一样吗:$same")
logging("二者的某个属性值${parseData.inputCountValue}和${parseDataCopy.inputCountValue}一样吗: ${parseData.inputCountValue.equals(parseDataCopy.inputCountValue)}")
f、模板类
可以理解为泛型或者泛型的升级版,用法上和Java区别不大。前面也讲过了。