constructor,有private等修饰时,需要
/**
* 主构造函数
* 一个类对象中,属性如果时val修饰,只生成
*/
class Person constructor(firstName: String) { /*……*/ }
/**
* 简化写法,如果没有private或者注解修饰则可以省略constructor关键字
*/
class Person2(firstName: String) {}
class Person3 private constructor(firstName: String) {
var firstName: String = firstName
}
所谓的主构造函数,就是头上的Person4
注意,init一定会执行
/**
* 主构造函数不能包含任何的代码。初始化的代码可以放到以 init 关键字作为前缀的初始化块(initializer
* 在实例初始化期间,初始化块按照它们出现在类体中的顺序执行,与属性初始化器交织在一起:
*/
class Person4(firstName: String, age: Int) {
var firstName: String
var age: Int
init {
this.firstName = firstName
this.age = age
}
}
简化写法
/**
* 请注意,主构造的参数可以在初始化块中使用。它们也可以在类体内声明的属性初始化器中使用
*/
class Person5 private constructor(firstName: String) {
var firstName: String = firstName
}
更简洁写法
/**
* 更简洁的写法
*/
class Person6 private constructor(val firstName: String, var age: Int) {}
/**
* 如果类中有主构造函数和次构造函数,则次构造函数一定要实现主构造函数
*/
class School2(val firstName: String, var age: Int) {
var studentNum: Int = 0
constructor(firstName: String, age: Int, studentNum: Int) : this(firstName, age) {
this.studentNum = studentNum
}
}
/**
* 多个次构造函数时,也可以实现同类中其他次构造函数,间接地实现主构造函数
*/
class School3(val firstName: String, var age: Int) {
var studentNum: Int = 0
var name: String? = null
constructor(firstName: String, age: Int, studentNum: Int) : this(firstName, age) {
this.studentNum = studentNum
}
constructor(firstName: String, age: Int, studentNum: Int, name: String) : this(firstName, age, studentNum) {
this.name = name;
}
}
kotlin中,如果表达一个类或者函数可以被继承,需要open关键字
如果向禁止继承的超类,在被继承函数,可以用final
open class Base(p: Int)
/**
* 继承
* 需声明一个显式的超类型,请在类头中把超类型放到冒号之后
*/
class Derived(p: Int) : Base(p)
/**
* 默认情况下,Kotlin 类是最终(final)的:它们不能被继承。 要使一个类可继承,请用 open 关键字标记它。
* 函数也一样,默认也是final标记地
*/
open class BaseTeacher(name: String) {
open fun teach(lesson: String) {
}
fun eat(thing: String) {
}
}
/**
* 继承 二者必须实现一个
* 1.没有构造方法时,继承需要class()形式
* 2当父类有成员时,子类可以通过constructor来实现,但必须super去实现父类地构造函数
*/
class MathTeacher : BaseTeacher {//类似接口,但不是接口
var name: String? = null
constructor(name: String) : super(name) {
this.name = name
}
override fun teach(lesson: String) {
super.teach(lesson)
}
}
/**
* 如果想禁止二次被覆盖,可以在前面加上final关键字
*/
class Circle() : Shape() {
final override fun draw() { /*……*/
}
}
kotlin中,属性覆盖也需要用open
open class Shape2 {
open val vertexCount: Int = 0
open val height: Int = 2
open val width: Int = 3
open var length: Int = 5;
}
/**
* 可以用一个 var 属性覆盖一个 val 属性,但反之则不行。
* 这是允许的,因为一个 val 属性本质上声明了一个 get 方法,
* 而将其覆盖为 var 只是在子类中额外声明一个 set 方法。
* java中没有属性继承的方式,但实际,也是覆盖了
*/
class Rectangle : Shape2() {
override val vertexCount = 4
override val height: Int
get() = super.height
// override val height:Int = 4 // 可以覆盖
override var width: Int = 10
// override val length:Int = 2 // 不能将var变成val
}
/**
* 派生类中的代码可以使用 super 关键字调用其超类的函数与属性访问器的实现:
*/
open class Rectangle2 {
open fun draw() {
println("Drawing a rectangle")
}
val borderColor: String get() = "black"
}
class FilledRectangle : Rectangle2() {
override fun draw() {
super.draw()
println("Filling the rectangle")
}
val fillColor: String get() = super.borderColor
}
package day2Class
/**
* 内部类与java本质时一样的,public final class Filler,非静态类
* 一个内部类中访问外部类的超类,可以通过由外部类名限定的 super 关键字来实现
*/
class FilledRectangle2 : Rectangle2() {
override fun draw() {
println("你好")
}
inner class Filler {
fun fill() {
println("Filling")
}
fun drawAndFill() {
super@FilledRectangle2.draw() // 调用 Rectangle 的 draw() 实现而不是FilledRectangle2的draw方法
fill()
draw()//调用FilledRectangle2的draw
println("Drawn a filled rectangle with color ${super@FilledRectangle2.borderColor}") // 使用 Rectangle 所实现的 borderColor 的 get()
}
}
}
fun main(args: Array<String>) {
var filler2: FilledRectangle2.Filler = FilledRectangle2().Filler()
println(filler2.drawAndFill())
}
package day2Class
/**
* 可以同时继承 Rectangle 与 Polygon, 但是二者都有各自的 draw() 实现,
* 所以我们必须在 Square 中覆盖 draw(), 并提供其自身的实现以消除歧义。
*/
open class Rectangle3 {
open fun draw() { /* …… */
}
}
interface Polygon3 {
fun draw() { /* …… */
} // 接口成员默认就是“open”的
}
class Square() : Rectangle3(), Polygon3 {
// 编译器要求覆盖 draw():
override fun draw() {
super<Rectangle3>.draw() // 调用 Rectangle.draw()
super<Polygon3>.draw() // 调用 Polygon.draw()
}
}
继承抽象方法时,不需要open和override关键字
package day2Class
open class Polygon4 {
open fun draw() {}
}
/**
* 抽象
*/
abstract class Rectangle4 : Polygon4() {
abstract override fun draw()
}
/**
* 继承抽象方法时,不需要open和override关键字
*/
class Rectangle5 : Rectangle4() {
override fun draw() {
TODO("Not yet implemented")
}
}
abstract class Rectangle10 {
abstract fun draw()
}
fun main(args: Array<String>) {
//匿名类对象
var r: Rectangle10 = object : Rectangle10() {
override fun draw() {
TODO("Not yet implemented")
}
}
}
/**
* var字段,默认会提供setter和getter方法
* val字段,默认会提供getter方法
*/
class Address {
var name: String = "Holmes, Sherlock"
var street: String = "Baker"
var city: String = "London"
var state: String? = null // 允许空
var zip: String = "123456"
}
注意下面:
/**
* data关键字,默认
* 所有属性的 getters (对于 var 定义的还有 setters)
* equals()
* hashCode()
* toString()
* copy()
* 所有属性的 component1()、 component2()……等等
*
* 注意,不要去实现已经实现的方法,copy hashCode equals
*/
data class Address2(var name: String, var age: Int) {
// fun copy(name: String, age: Int) {
//
// }
}
field就是counter.
/**
* 幕后字段 field
* getter和setter方法
* field 关键字,代表当前属性的counter的值,只能使用在幕后字段中, 其他地方不能使用
*/
class Rule {
var counter = 0 // 注意:这个初始器直接为幕后字段赋值
set(value:Int) {
if (value >= 0) field = value
}
get() {
return if (field >= 0) field + 1 else 1
}
}
lateinit,是延迟初始化属性,第一次使用之前需要赋值
/**
* 使用注意
* 在var之前添加lateinit,然后选择你想要的时候,初始化,但是有以下需要注意的地方:
* lateinit只能修饰变量var,不能修饰常量val
* lateinit不能对可空类型使用
* lateinit不能对java基本类型使用,例如:Double、Int、Long等
* 在调用lateinit修饰的变量时,如果变量还没有初始化,则会抛出未初始化异常,报错
*/
class Late {
lateinit var a1: String
fun test() {
if (!this::a1.isInitialized) {
a1 = "test1"
}
// 初始化
println(a1)
}
}
lazy是延迟初始化,懒加载而且单例
val a2: String by lazy {
println("开始初始化")
// 初始化的值
"sss"
}
/**
* 接口中属性要么是抽象的,要么提供访问器的实现
* JDK1.8中,接口中无需全部是抽象函数,java中可以写上具体属性数据,或者方法,添加关键字default,
* 说白了,接口和抽象类型几乎等价,甚至有的语言去掉了接口的概念,统一抽象类
*
*/
interface MyInterface2 {
val prop: Int // 抽象的
val propertyWithImplementation: String
get() = "foo"
fun foo() {
print(prop)
}
}
class Child2 : MyInterface2 {
override val prop: Int = 29
}
接口提供属性时,从而既提供基类型成员的实现也声明新的函数与属性
/**
* 个接口可以从其他接口派生,从而既提供基类型成员的实现也声明新的函数与属性
* 实现接口时,就无需实现,默认会添加接口中的属性
* 当作抽象类去理解更容易
*/
interface Person12 : Named {
val firstName: String
val lastName: String
override val name: String get() = "$firstName $lastName"
}
data class Employee(
// 不必实现“name”
override val firstName: String,
override val lastName: String,
val position: Int
) : Person12
fun main(args: Array<String>) {
var employee: Employee = Employee("1", "2", 3)
println(employee.name)
}
SAM函数编程,简单就是接口如同函数一样,省略,java1.8之后lamada匿名接口
package day2Class
import org.omg.CORBA.Object
/**
* 只有一个抽象方法的接口称为函数式接口或 SAM(单一抽象方法)接口。
* 函数式接口可以有多个非抽象成员,但只能有一个抽象成员。
* 可以用 fun 修饰符在 Kotlin 中声明一个函数式接口,1.4新特性,
* SAM函数编程
*/
interface KRunnable {
fun invoke()
}
fun interface MyRun {
fun run()
}
fun interface MyRun2 {
fun run(a: Int)
}
fun runAction(a: MyRun) = a.run()
fun runAction2(k: () -> Unit) = k
fun runAction3(a: Int, b: MyRun2) = b.run(a)
fun String.runAction4(n: (String) -> Unit) = n(this)
interface IntPredicate {
fun accept(i: Int): Boolean
}
fun setIntPredicate(a: IntPredicate) {
}
fun main(args: Array<String>) {
/**
* 匿名内部类接口
*/
val isEven: IntPredicate = object : IntPredicate {
override fun accept(i: Int): Boolean {
return i % 2 == 0
}
}
/**
* 通过 lambda 表达式创建一个实例
* 1.4新特性,当前编译器不知道什么原因不能使用(已更新到1,4-21)
*/
var isEven2 = object : IntPredicate {
override fun accept(i: Int): Boolean {
return i % 2 == 0
}
}
runAction(object : MyRun {
override fun run() {
println("你好")
}
})
runAction {
//实现接口方法
println("你好")
}
runAction2 {
}
runAction3(2) { x ->
println(x.plus(2))
}
var str = "xxxx"
str.runAction4 {
println(it)
}
}
/**
* 如果你不指定任何可见性修饰符,默认为 public,这意味着你的声明将随处可见;
如果你声明为 private,它只会在声明它的文件内可见;
如果你声明为 internal,它会在相同模块内随处可见;
protected 不适用于顶层声明。
*/
在class外的都是静态属性,等价于java中添加static
package day2Class
fun method() {//java static fun method(){}
}
fun method2() {
}
fun method3() {
}
实现接口方法
println(“你好”)
}
runAction2 {
}
runAction3(2) { x ->
println(x.plus(2))
}
var str = "xxxx"
str.runAction4 {
println(it)
}
}
### 12.可见性修饰符
```kotlin
/**
* 如果你不指定任何可见性修饰符,默认为 public,这意味着你的声明将随处可见;
如果你声明为 private,它只会在声明它的文件内可见;
如果你声明为 internal,它会在相同模块内随处可见;
protected 不适用于顶层声明。
*/
在class外的都是静态属性,等价于java中添加static
package day2Class
fun method() {//java static fun method(){}
}
fun method2() {
}
fun method3() {
}