适合有java基础的,获取kotlin基础知识/语法等,Kotlin精讲-黑马程序员(原创)的学习笔记。
类
- Kotlin实现了默认的setter/getter方法,我们也可以对它们进行自定义,以及修改访问控制符。
- 主构函数
// Kotlin在类定义的时候,在类名后面加上小括号,变成了函数形式。
// 我们在小括号内就可以直接定义类创建的时候可以接收的值,并可以把接收的值赋值给变量,
// 达到Java里面构造函数的作用,我们称这样的函数为主构函数
class Person(name: String, age: Int) {
var name: String = name
var age: Int = age
}
// 在主构函数上,我们还可以为每一个变量加上一个val或者var修饰符
// 这样就表示,为该类定义了一个对应的成员属性
// 还可以给参数设置默认值
class Person2(var name: String="default_name", var age: Int=18) {
fun printInfo() {
println("name is $name, age is $age")
}
}
fun main() {
// Kotlin创建类对象的时候不需要使用new关键字
val person = Person()
// 主构函数,默认值的初始化
val person21 = Person2()
val person22 = Person2("Jerry")
val person23 = Person2("Jerry", 4)
val person24 = Person2(age = 4)
}
- 次构函数
Kotlin的主构函数确实给我们带来了很多的方便,在编程开发过程中,能用主构函数,我们优先去用主构函数。其实Kotlin同样允许你像Java一样在类的内部定义构造函数,我们称这样的构造函数为次构函数。
使用次构函数的时候,分两种情况,一种是类不存在主构函数,一种是类存在主构函数。
3.1 不存在主构函数
class Person {
var name: String = ""
var age: Int = 18
constructor(name: String, age: Int) {
this.name = name
this.age = age
}
}
3.2 存在主构函数
class Person(var name: String) {
var age: Int = 18
// 因为存在主构函数,所以我们通过“:this(name)”对主构函数成员变量进行赋值
constructor(name: String, age: Int): this(name) {
this.age = age
}
}
注意: 次构函数不能像主构函数那样,通过加上var或者val修饰符,让方法参数变成类的成员属性,次构函数只能接收值
- 初始化方法
第一,调用了主构函数或者次构函数,都会触发初始化方法。
第二,初始化方法在次构函数之前被执行。
class Person {
var name: String = ""
var age: Int = 18
init {
println("初始化方法。。。")
}
constructor(name: String, age: Int) {
this.name = name
this.age = age
println("次构函数。。。")
}
}
- 嵌套类
嵌套类分成两种类型,一种是不通过Inner关键字修饰的嵌套类,一种是通过Inner关键字修饰的嵌套类。
两者的区别主要体现在类的创建以及对外部内属性的访问上。
5.1 不通过Inner关键字修饰的嵌套类
class Outer {
val outerValue = 12
class Inner {
fun innerFun() {
// 不能访问外部类的成员属性, outerValue
}
}
}
fun main(args: Array<String>) {
// 在创建的时候,不需要先创建外部类对象
var inner = Outer.Inner()
inner.innerFun()
}
5.2 Inner关键字修饰的嵌套类
class Outer {
val outerValue = 12
inner class Inner {
fun innerFun() {
// 能访问外部类的成员属性
println("访问外部类的成员属性 $outerValue")
}
}
}
fun main(args: Array<String>) {
// 在创建的时候,需要先创建外部类对象
var inner = Outer().Inner()
inner.innerFun()
}
- 数据类
在类定义的时候,通过在最前面加上data关键字,就可以标明这个类是一个数据类。如果一个类被标明为数据类,编译器在编译的时候会自动帮我们覆写常用的一些方法。
toString方法,方便做日志输出
hashCode、equals方法,方便对象比较
copy方法,方便做对象复制
componentX方法,可以很方面的解析对象包含的属性变量(X是1,2,3 对应属性)
// 没有类体
data class Person(var name: String, var age: Int)
fun main(args: Array<String>) {
var person = Person()
// componentX,全部解析
val(name, age) = person
// 第一个属性
var name2 = person.component1()
}
- 枚举类
枚举类通过enum关键字完成,enum关键字添加在class关键字的前面
enum class Gender {
MALE, FEMALE, OTHER
}
enum class Week(val date: String, val doSth: String) {
MON("周一", "work"),
TUE("周二", "work"),
WED("周三", "work"),
THU("周四", "work"),
FRI("周五", "work"),
SAT("周六", "offline"),
SUN("周七", "offline")
}
fun test() {
val sat = Week.SAT
// sat.name, sat.ordinal,
// sat.date, sat.doSth
}
- 印章类
通过enum关键字可以定义一个枚举类,枚举类让一个类拥有了有限多个常量。通过sealed关键字,则可以定义一个印章类,印章类让一个类拥有了有限多个子类。印章类甚至可以理解为一个特殊的枚举类。印章类本身不能被实例化。
sealed class Operation {
class Add(val num1: Int, val num2: Int): Operation()
class Subtract(val num1: Int, val num2: Int): Operation()
class Multiply(val num1: Int, val num2: Int): Operation()
class Divide(val num1: Int, val num2: Int): Operation()
}
fun operation(op: Operation) {
when (op) {
is Operation.Add -> println("add ${op.num1 + op.num2}")
is Operation.Subtract -> println("subtract ${op.num1 - op.num2}")
is Operation.Multiply -> println("multiply ${op.num1 * op.num2}")
is Operation.Divide -> println("divide ${op.num1 / op.num2}")
}
}
fun main(args: Array<String>) {
var add = Operation.Add(1, 2)
operation(add)
}
- 类的继承
// 父类需要通过open关键字表示,才可以被继承
open class Person(val name: String) {
// 父类允许子类重写属性,需要通过open关键字标记。
open var hairStyle = "有头发"
// 父类允许子类重写方法,需要通过open关键字标记
open fun wash(): String {
return "wash"
}
}
// Kotlin中的继承关系,通过冒号去表示
// 通过主构给基类赋值
class Man(name: String) : Person(name) {
// 子类如果重写了父类的属性,需要通过 override标记
override var hairStyle = "短头发"
// 子类如果重写了父类的方法,需要通过 override标记
override fun wash(): String {
return "man wash"
}
}
class Woman: Person {
override var hairStyle = "长头发"
// 通过次构给基类赋值
constructor(name: String) : super(name)
override fun wash(): String {
return "woman wash"
}
}
- 抽象类
// abstract修饰(不需要open)
abstract class Person(val name: String) {
// 抽象属性 不能实例化
// 子类需要将抽象属性初始化,除非子类也是abstract
abstract var hairStyle: String
// 抽象方法必须public/protected(默认)
abstract fun wash(): String
}
class Man(name: String) : Person(name) {
// 必须override修饰
override var hairStyle = "短头发"
// 必须override修饰
override fun wash(): String {
return "man wash"
}
}
- 接口
interface Clickable {
// 抽象属性 不能实例化
var name: String
fun click()
// Java中的接口中的方法,不能有方法体(JDK1.8之后可以有),
// Kotlin中的接口方法,可以带有方法体(学习了jdk1.8的做法)
fun printInfo() {
println("fun from interface...")
}
}
class Button: Clickable {
override var name: String = "button"
override fun click() {
println("button click...")
}
override fun printInfo() {
println("fun from Button...")
}
}
实现的多个接口中方法同名的调用:
interface Clickable {
fun show() {
println("Clickable#show...")
}
}
interface Touchable {
fun show() {
println("Touchable#show...")
}
}
class Button: Clickable, Touchable {
override fun show() {
// 指定接口,调用方法
super<Clickable>.show()
super<Touchable>.show()
println("button show...")
}
}
- 接口/抽象类的异同
异
1、 接口是定义一些独立的功能、模块、能力,定义为一个一个的接口。比如“可点击的”、“可触摸的”、“可滑动的”、“可吃的”。接口是抽象功能,抽象类是抽象类别。
2、 接口可以看做是抽象类的延申,接口的抽象级别更高
3、 抽象类只能被单继承,接口可以多实现。
4、 抽象类被子类继承,接口被类实现。
5、 方法被abstract修饰,一定是抽象类。(接口也可以用abstract修饰,只是没必要)
同
1、 抽象类和接口都不能被实例化。
2、 抽象类和接口中都可以有方法声明和方法实现。
3、 抽象类和接口中的变量都不能初始化。
4、 子类没有实现完抽象类中的抽象方法,接口实现类没有实现完接口没有方法体的接口方法,都将变为抽象类。
5、 接口中、抽象类中的方法,都不能是私有(private)的。
网友评论