继承
Kotlin的类默认都是封闭的,要让某个类开放继承,必须使用open关键字修饰它。
open class Product(val name: String) {}
class LuxuryProduct(name: String, private val price:Double):Product(name){}
方法重写和重载
父类的函数也要通过open关键字修饰才可以被子类重写。
open class Product(val name: String) {
fun description() = "Product:$name"
//方法重载
open fun load() {
"Nothing..."
}
open fun load(name: String) {
println("$name is very expensive")
}
}
class LuxuryProduct(name: String, private val price: Double) : Product(name) {
//方法重写
override fun load() {
super.load()
println("${super.description()},Price:$price")
}
}
fun main() {
val luxuryProduct: Product = LuxuryProduct("LV", 19800.00)
println(luxuryProduct.description())
luxuryProduct.load()
luxuryProduct.load("LV")
}
类型检测
Kotlin的is运算符是一个不错的工具,可以用来检查某个对象的类型,其实就相当于Java中的instanceof关键字。
println(luxuryProduct is Product)
println(luxuryProduct is LuxuryProduct)
println(luxuryProduct is File)
类型转换
通过as操作符完成类型转换,而且转换一次,后面再使用时无需转换。
open class Product0(val name: String) {
fun special() = "Product0 special function"
}
class LuxuryProduct0 : Product0("Luxury") {}
fun main() {
val lp = LuxuryProduct0()
println((lp as Product0).special())
//只需要转换一次,后面无需转换,也不需要用临时变量去存
println(lp.special())
println(lp.special())
}
Kotlin编译器很聪明,只要能确定any is父类条件检查属实,就会将any当做子类类型对待,因此编译器允许我们不经类型转换直接使用。
open class Product2(val name: String) {
fun load() {
println(name)
}
}
fun sale(p: Product2) {
p.load()
}
class LuxuryProduct2(name: String, private val price: Double) : Product2(name) {}
fun main() {
val lp2 = LuxuryProduct2("LV", 19800.00)
//传入的参数是Product2的子类对象lp2
//sale(lp2 as Product2)
sale(lp2)
}
Any
无须在代码里显示指定,每一个类都会继承一个共同的叫做Any的超类。

Object
使用Object关键字,我们可以定义一个只能产生一个实例的类 ———— 单例。
使用Object有三种方式:对象声明、对象表达式、伴生对象。
对象声明
object ApplicationConfig{
init {
println("ApplicationConfig loading...")
}
fun doSomething(){
println("doSomething")
}
}
fun main() {
//ApplicationConfig既是类名,也是实例名
ApplicationConfig.doSomething()
println(ApplicationConfig)
println(ApplicationConfig)
}
对象表达式
有时候我们不一定非要定义一个新的命名类不可,也许需要某个现有类的一种变体实例,但只需用一次就行了,事实上,对于这种用完就丢的类实例,连命名都可以省了。这个对象表达式是某个类的子类,这个匿名类依然遵循object关键字的一个原则,即一旦实例化,该匿名类只能有唯一一个实例存在。
open class Player {
open fun load() = "loading nothing.."
}
fun main() {
val p = object : Player() {
override fun load() = "anonymous nothing.."
}
println(p.load())
}
伴生对象
如果你想将某个对象的初始化和一个类实例捆绑在一起,可以考虑使用伴生对象,使用companion修饰符,可以在一个类定义里声明一个伴生对象,一个类只能有一个伴生对象。跟Java中的static有一些类似。
open class ConfigMap{
companion object{
private const val PATH= "d://honey.txt"
fun load() = File(PATH).readBytes()
}
}
fun main() {
//static
ConfigMap.load()
}
通过反编译,我们发现这基本就是Java中的static在Kotlin中的实现:
嵌套类
如果一个类只对另一个类有用,那么将其嵌入到该类中并使用这两个类保持在一起是合乎逻辑的 ,可以使用嵌套类。
class Player2 {
class Equipment(var name: String) {
fun show() = println("equipment:$name")
}
}
fun main() {
Player2.Equipment("98k").show()
}
数据类
顾名思义,数据类是专门设计用来存储数据的类。
- 数据类提供了toString的个性化实现
- ==符号默认情况下,比较对象就是比较它们的引用值,数据类提供了equals和hashCode的个性化实现
data class Coordinate(var x: Int, var y: Int) {
val isInBounds = x > 0 && y > 0
}
fun main() {
println(Coordinate(10, 20))
// == 比较的是内容,equals,Any 默认实现===,比较引用
// === 比较的是引用
println(Coordinate(10, 20) == Coordinate(10, 20))
val (x, y) = Coordinate(10, 20)
println("$x, $y")
}