类的属性可以使用 var 声明变量,可以使用 val 声明常量。
属性的引用可以用 (.)符号来实现。
属性取值和赋值的 getter 和 setter 都是可选的 。
val 不允许设置 setter 函数,它是只读的。
class Person{
var lastName :String = "zhang"
get() = field.toUpperCase() //转换为大写
set
var no: Int = 100
get
set(value) {
if (value < 10) {
field = value
}else{
field = -1
}
}
var height:Float = 145.4f
private set
fun addOne(x: Float) {
height += x
}
}
这个 Person 类的 height 把 setter 设置为私有的,外部不能直接修改,需要通过 Person 类提供的方法来修改。这里提供了 addOne 方法。
var person :Person = Person()
person.lastName = "wang"
println("lastName is ${person.lastName}")
person.no = 9
println("no is ${person.no}")
person.no = 20
println("no is ${person.no}")
println("height is ${person.height}")
person.addOne(1f)
println("height is ${person.height}")
在 main 里实现这些代码,对 Person 类做相应的访问。
运行结果
lastName is WANG
no is 9
no is -1
height is 145.4
height is 146.4
类的构造器
Kotlin 的类是通过 constructor 来实现构造器的。构造器有主构造器和次构造器之分。
主构造器中不能包含任何代码,初始化代码可以放在 init 初始化代码段中。
class Pp constructor(firstName: String){
init {
System.out.println("First name is $firstName.")
}
}
这样在实例化的时候,会打印出一句话来
var p = Pp("Joel")
First name is Joel.
类的 constructor 关键字一般是可以省略的。如果主构造函数有注解或可见性修饰符,则 constructor 关键字不可省略,并且这些修饰符要放在 constructor 前面。
类也可以声明前缀有 constructor 的次构造函数。
当类有一个主构造函数,每个次构造函数需要委托给主构造函数,可以直接委托或通过别的次构造函数间接委托。委托到同一个类的另一个构造函数用 this 关键字。
class Person constructor(firstName: String){
constructor(name: String, parent: Person): this(name){
}
}
抽象类没有声明任何构造函数的,会有一个生成的不带参数的主构造函数。构造函数的默认可见性是 public 。如果不希望类有这个公有构造函数,则需要声明一个带有非默认可见性的空的主构造函数。
class DontCreateme private constructor(){
}
再看一个类的示例
package main
fun main(args: Array<String>) {
val cofox = Cofox("金龙翼移动办公", 1000)
println(cofox.Sitename)
println(cofox.Url)
println(cofox.Country)
cofox.PrintTest()
}
class Cofox constructor(name: String){
// 大括号内是类体构成
var Url: String = "http://www.cofox.com"
var Country: String = "CN"
var Sitename = name
init {
println("初始化网站名称:$name")
}
// 次构造函数
constructor(name: String, alexa: Int): this(name){
println("Alexa 排名 $alexa")
}
fun PrintTest(): Unit {
println("我是类的函数")
}
}
运行结果
初始化网站名称:金龙翼移动办公
Alexa 排名 1000
金龙翼移动办公
http://www.cofox.com
CN
我是类的函数
继承类
Kotlin 默认类都是 final 的。如果类需要被其他类继承,那么要让这个类 open 才行。
当 fun 是 open 的时候,那么也是可以被 override 的。
open class Base{
open fun f(){}
}
abstract class Derived :Base(){
override abstract fun f()
}
由于 Base 类是 open 的,所以 Derived 可以继承 Base 。
由于 f() 是 open 的,所以可以被 override
嵌套类
类可以嵌套其他类
当要引用类内的函数时,类后需要跟括号
class Outer{
private val bar : Int = 1
class Nested{
fun foo() = 2
class Thrd{
fun mee() = "meyaya"
}
}
}
在 main 函数中这样调用 Outer 里的类和函数
val demo = Outer.Nested().foo()
val demo2 = Outer.Nested.Thrd().mee()
println(demo.toString() + ":" + demo2)
执行结果如下
2:meyaya
内部类
当把嵌套在内部的类标记为 inner 内部类时,每层的引用都需要加括号。
内部类可以访问外部类成员,也可以通过 this@外部类 ,从而达到能获取外部类实例的使用模式。
class Outer{
private val bar : Int = 1
inner class Nested{
fun foo() = bar //访问外部类成员
inner class Thrd{
fun mee() = "meyaya"
fun innerTest(){
var o = this@Outer
println("这是获取外部类成员" + o.bar.toString())
// bar
}
}
}
}
在 main 中可以这样调用
val demo = Outer().Nested().foo()
val demo2 = Outer().Nested().Thrd().mee()
println(demo.toString() + ":" + demo2)
Outer().Nested().Thrd().innerTest()
运行结果
1:meyaya
这是获取外部类成员1
不仅如此,class 中的 o 可以像在 main 中一样调用 class 里的函数。
匿名内部类
使用对象表达式来创建匿名内部类
首先定义一个接口,接口内是一个 test() 函数
/*
* 定义接口
* */
interface TestInterFace{
fun test()
}
创建一个 Test 类,类内有一个 成员 v 和一个函数,函数的参数为 TestInterFace 接口。
class Test{
var v = "成员属性"
fun setInterFace(test: TestInterFace){
test.test()
}
}
在主函数中,先声明实例化这个Test类。
试着打印一下这个类的成员 v,看是否能成功。
var test = Test()
println(test.v)
类实例 test 的 setInterFace 函数的参数是接口,这里用对象表达式来创建接口对象,即匿名内部类的实现。
test.setInterFace(object: TestInterFace{
override fun test() {
println("对象表达式创建匿名内部类的实例")
}
})
类的修饰符
类的修饰符包括:类属性修饰符(classModifier)和 访问权限修饰符(accessModifier)
- classModifier: 类属性修饰符,标示类本身特性。
abstract | 抽象类 |
final | 类不可继承,默认属性 |
enum | 枚举类 |
open | 类可继承,非默认属性,需要注意 |
annotation | 注解类 |
- accessModifier: 访问权限修饰符
private | 定义的内部可见 |
protected | 同一个文件中或子类可见 |
public | 所有调用的地方都可见 |
internal | 同一个模块中可见 |