1、类定义
Kotlin类可以包含:构造函数和初始化代码块、函数、属性、内部类、对象声明。
创建类:
class Runoob{ //创建名为Runoob的类
}
定义空类:
class Empty
含有成员函数的类:
fun main(args: Array) {
var s = Student()
s.introduce()
}
class Student{
fun introduce(){ println("I am a student") }
}
类的属性
类的属性可以用关键字var声明为可变的,否则使用只读关键字val声明为不可变。
例子:
class Student{
var name:String = ...
var address:String =...
var phone:String =...
}
kotlin中创建对象没有了new关键字,我们可以像调用普通函数一样调用类的构造方法;
例如:
val student = Student()
想要使用类中的属性,只要用名称引用它即可
例如:
student.name
getter和setter
属性声明的完整语法:
var [:][=]
[]
[]
如果属性类型可以从初始化语句中推断出来,那么类型就可以省略;
在kotlin中,声明一个类的成员变量时,默认实现了getter和setter方法;
用val修饰的属性不允许设置setter函数,因为它本身就是只读的;
例如:
var allByDefault:Int? //错误:需要一个初始化语句
var initialized = 1 //类型为Int,默认实现了getter和setter
val simple:Int? //类型为Int,默认实现了getter,但必须在构造函数中初始化
val inferredType = 1 //类型为Int,默认实现了getter
在kotlin的getter方法中不能使用当前属性的引用,set方法中不能对当前属性进行赋值;
例如:
var no:Int = 100
get() = no //这里如果使用当前属性的引用,会递归调用属性的get方法
set(value){
no = value //同理,如果在这给no赋值,会递归调用属性的set方法
}
为了防止这种情况的发生,kotlin引入了后端变量的概念,后端变量使用field表示;
例如:
class Student{
var number:Int = 1001
get() = getDate()+field
set(value){
field = getDate()+value
}
fun introduce(){ println("I am a student") }
//获取年份
private fun getDate():Int{
var date = Calendar.getInstance().get(Calendar.YEAR)
return date*10000
}
}
非空属性必须在定义的时候初始化,kotlin提供了一种可延迟初始化的方案,使用lateinit关键字描述属性:
public class MyTest{
lateinit var subject:TestSubject
fun setup(){
subject = TestSubject()
}
}
主构造器
主构造器不能包含任何代码,初始化代码可以放在初始化代码段中,初始化代码段使用init关键字作为前缀。
class Person constructor(firstName :String){
init{
println("FirstName is $firstName")
}
}
当然在这里主构造器的参数可在初始化的代码片段中使用,也可以在属性初始化的代码中使用;另
外一种简单的写法就是用主构造器来定义属性并初始化属性值。例如:
class Person(val firstName:String,val lastName:String){
//....
}
如果构造器有注解,或者有可见度修饰符,这时constructor关键字是必须的,注解和修饰符要放在它之前。
次构造函数
类也可以有二级构造函数,需要添加前缀 constructor
class Person{
constructor(parent:Person){
parent.children.add(this)
}
}
如果类有主构造函数,每个次构造函数都要,直接或间接通过另一个次构造函数代理主构造函数。在同一个类中代理另一个构造函数使用关键字this关键字:
class Person(val name:String){
constructor(name:String,age:Int):this(name){
//初始化...
}
}
如果一个非抽象类没有声明构造函数(主构造函数或次构造函数),它会会产生一个没有参数的构造
函数,构造函数时public的,如果你不想你的类有公有的构造函数,你需要声明一个空的主构造函
数:
class Single private constructor(){}
实例练习:
class WebSite constructor(name:String){
var url:String ="http://www.baidu.com"
var country:String = "CN"
var siteName = name
init{
println("初始化网站名:$name")
}
constructor(name:String,alexa:Int):this(name){
println("Alexa 排名 $alexa")
}
}
2、抽象类
抽象类和java一样使用abstract修饰,同样使用abstract修饰的成员方法不存在具体实现。
注意:无需对抽象类或抽象成员标注open注解。
open class Base {
open fun f(){}
}
abstract class Dervied:Base(){
abstract override fun f()
}
嵌套类
kotlin中可以嵌套的声明类,这里和java内部类不同,其他类要使用嵌套类时,只需要外部类的
类名引用来创建嵌套类的对象,如下:
class Outer{ //外部类
private val bar:Int = 1
class Nested{ //嵌套类
var ot:Outer = Outer()
fun foo() {
println(out.bar) //嵌套类想要引用外部类的变量,需要先创建外类的对象
}
}
}
fun main(args:Array){
val demo = Outer.Nested().foo()
println(demo)
}
内部类
内部类使用inner关键字来表示。
内部类会带有一个对外部类的对象的引用,所以内部类可以访问外部类成员属性和成员函数。
class Outer{
private val bar:Int=1
var v = "成员属性"
inner class Inner{
fun foo() = bar
fun innerTest(){
var o = this@Outer
println("内部类可以引用外部类的成员,例如:"+o.v)
}
}
}
fun main(args: Array) {
val demo = Outer().Inner().foo()
println(demo)
val demo2 = Outer().Inner().innerTest()
println(demo2)
}
匿名内部类
class Demo{
fun setInterface(test:TestInterface){
test.test()
}
}
interface TestInterface{
fun test()
}
fun main(args: Array) {
var demo = Demo()
demo.setInterface(object :TestInterface{
override fun test() {
println("匿名内部类的方法,哈哈哈")
}
})
}
这里匿名内部类和java中的有区别,object:TestInterFace中的object是kotlin的关键字;
类的修饰符总结
和java一样,类的修饰符分为两种classModifier和accessModifier:
classModifier:类属性修饰符,用来标识类本身特性。
abstract //抽象类
final //类不可继承,默认属性
enum //枚举类
open //可继承类,类默认是final的
annotation //注解类
accessModifier:访问权限修饰符
private //仅在同一个文件中可见
protected //同一个文件中或子类中可见
public //所有调用的地方都可见
internal //同一个模块中可见