有时候我们需要以字符串的形式提交信息,例如在调试时输出到控制台。那么,如何将非文本对象表示为可读字符串呢?这就需要用到 toString() 函数。
引言
假设我们有三个盒子,分别装有不同种类的浆果:覆盆子(raspberry)、草莓(strawberry) 和 蓝莓(blueberry)。我们需要这些盒子的重量信息,并打印出来:
val raspberryWeight = 10
val strawberryWeight = 15
val blueberryWeight = 20
println(raspberryWeight) // 10
println(strawberryWeight) // 15
println(blueberryWeight) // 20
解释代码:
这看起来没问题。我们定义了三个变量,存储每种浆果的重量,并通过 println() 输出了它们。
现在我们定义一个 BerryHolder 类,用来存储这些盒子的重量,并再次尝试打印这些值:
class BerryHolder(val weight: Int)
val raspberryWeight = BerryHolder(10)
val strawberryWeight = BerryHolder(15)
val blueberryWeight = BerryHolder(20)
println(raspberryWeight) // BerryHolder@6f496d9f
println(strawberryWeight) // BerryHolder@723279cf
println(blueberryWeight) // BerryHolder@10f87f48
解释代码:
这次的结果看起来就不太理想了,输出的并不是我们期望看到的重量,而是类名和内存地址。
为什么会这样?
要理解这一点,我们需要知道 println(message: Any?) 是怎么工作的。它的参数类型是 Any?,这意味着 Kotlin 中的所有类(标准类或自定义类)都可以传递进去。
由于 println() 要处理任意类型的对象并将其输出为字符串,所以它会隐式地调用对象的 toString() 函数。
默认行为
toString() 函数定义在 Any 类中,这是所有类的父类。因此,任何类都继承了 toString() 方法。
但默认的 toString() 实现,返回的是类名 + 内存地址的字符串。
对于一些内置类型,比如 Int 或 Double,toString() 方法已被重写以提供更有意义的输出:
val nonString = 1.0
println(nonString.toString()) // 1.0
println(nonString) // 1.0
解释代码:
上面两种写法效果相同,println() 隐式调用了 Double 类型的 toString()。
但对于大多数类,如果没有特别重写 toString(),仍然会输出类名+内存地址。
重写 toString()
为了让我们的类输出有意义的字符串内容,我们需要重写 toString() 方法。比如:
class BerryHolder(val weight: Int) {
override fun toString(): String {
return weight.toString()
}
}
println(BerryHolder(10)) // 10
解释代码:
现在,我们创建的 BerryHolder 对象在被打印时会输出它的重量,而不是内存地址。
更复杂的例子
现在我们要开发一个电子图书馆系统,其中有一个 User 类,包含用户的 ID、登录名和邮箱。
我们希望输出格式类似于:
User{id=id_value, login=login_value, email=email_value}
class User(val id: Int, val login: String, val email: String) {
override fun toString(): String {
return "User{id=$id, login=$login, email=$email}"
}
}
val user = User(1, "uncle_bob", "rmartin@objectmentor.com")
println(user) // User{id=1, login=uncle_bob, email=rmartin@objectmentor.com}
解释代码:
通过重写 toString(),我们成功将 User 对象转换为清晰的字符串形式,输出包含所有关键信息。
重写 toString():继承情况
当子类继承父类时,如果父类已经重写了 toString(),子类也会继承这个行为。
比如,我们添加一个 Author 类继承 User,并添加图书信息:
open class User(val id: Int, val login: String, val email: String) {
override fun toString(): String {
return "User{id=$id, login=$login, email=$email}"
}
}
class Author(id: Int, login: String, email: String, val books: String): User(id, login, email)
val user = User(1, "marys01", "mary0101@gmail.com")
val author = Author(2, "srafael", "rsabatini@gmail.com", "Captain Blood: His Odyssey")
println(user) // User{id=1, login=marys01, email=mary0101@gmail.com}
println(author) // User{id=2, login=srafael, email=rsabatini@gmail.com}
解释代码:
由于 Author 没有重写 toString(),所以调用的是 User 中的重写版本。
为子类单独重写 toString()
现在我们在 Author 中也重写 toString(),并输出书籍信息:
class Author(id: Int, login: String, email: String, val books: String): User(id, login, email) {
override fun toString(): String {
return "Author{id=$id, login=$login, email=$email}, books: $books"
}
}
解释代码:
这样我们就能看到更多信息了:
val user = User(1, "marys01", "mary0101@gmail.com")
val author = Author(2, "ohwilde", "wilde1854@mail.ie", "Someone’s portrait")
println(user) // User{id=1, login=marys01, email=mary0101@gmail.com}
println(author) // Author{id=2, login=ohwilde, email=wilde1854@mail.ie}, books: Someone’s portrait
在子类中调用父类的 toString()
有时候我们希望在子类的 toString() 方法中复用父类的逻辑,这时候可以使用 super:
class Author(id: Int, login: String, email: String, val books: String): User(id, login, email) {
override fun toString(): String {
return "Author: ${super.toString()};\nBooks: $books"
}
}
测试一下:
val author1 = Author(1, "uncle_bob",
"rmartin@objectmentor.com",
"\n1.\"Clean Code: A Handbook of Agile Software Craftsmanship\" \n2.\"Agile Software Development: Principles, Patterns and Practices\"")
val author2 = Author(2, "ltlst",
"leotolstoy@mail.com",
"\n1.\"Anna Karenina\" \n2.\"The Death of Ivan Ilyich\" \n3.\"War and Peace\"")
println(author1)
println()
println(author2)
输出结果为:
Author: User{id=1, login=uncle_bob, email=rmartin@objectmentor.com};
Books:
1."Clean Code: A Handbook of Agile Software Craftsmanship"
2."Agile Software Development: Principles, Patterns and Practices"
Author: User{id=2, login=ltlst, email=leotolstoy@mail.com};
Books:
1."Anna Karenina"
2."The Death of Ivan Ilyich"
3."War and Peace"
总结
-
toString()函数可以将非字符串对象转换为字符串。 -
Kotlin 中的所有类都继承了
Any,因此默认拥有toString()方法。 -
默认情况下,
toString()返回的是类名和内存地址。 -
你可以通过重写
toString()自定义对象的打印方式。 -
对于继承结构,子类可以重用或扩展父类的
toString()方法。
现在你已经掌握了如何使用和重写 toString() 方法,能够更好地进行调试和信息展示了!
Kotlin和Java中toString()方法的使用与重写
1376

被折叠的 条评论
为什么被折叠?



