1.面向對向編程
- 本質上就是解決如何用程序描述世界的問題
- 討論如何把實際存在東西映射成程序的類和對象
- 一種程序設計的思路、思想、方法
/**
* 面向對向編程
* 對某種事物進行抽象化,稱之為建模
*
*/
//kotlin 定義:class 類名 constructor(屬性列表){更多的屬性和方法描述}
//構造器:用來設置類新實例的出廠配置
//類要被繼承需要加open
open class Chinese constructor(val sex: Boolean, var region: String) {
//普通屬性,與變量定義相似
open val skin = "yellow"
//組合屬性,由其它屬性計算而來(get)
val avgLife: Double
get() {
when (this.region) {
"Shanghai" -> {
return 82.4
}
"Beijing" ->{
return 80.0
}
else -> {
return 72.1
}
}
}
//組合屬性反過來可以影響其它屬性(set,可選) this代表實例
var avgSalary : Int
get(){
when(this.region){
"Shanghai" ->{ return 4000}
"Beijing" ->{ return 5100}
else ->{ return 3500}
}
}
set(value) {
when (value) {
in 4500..Int.MAX_VALUE -> {
this.region ="Beijing"
}
in 2800..4100->{
this.region ="Shanghai"
}
else -> {
this.region = "homeland"
}
}
}
//方法:廚藝
open fun cook(): Unit {
val meau = arrayOf("宮爆雞丁","番茄炒雞蛋","蔥爆牛肉")
val desc = meau.reduce{s1,s2->s1+","+s2}
println("我會${desc}")
}
}
class BeijingPeople(sex: Boolean, region: String = "Beijing") : Chinese(sex, region) {
val greatBuilding="the Forbidden City"
//override覆蓋屬性好方法
override val skin ="BeijingYellow"
override fun cook() {
super.cook()
val meau = arrayOf("北京烤鴨","北京炸醬面","北京包子")
val desc = meau.reduce{s1,s2->s1+","+s2}
println("我還會${desc}")
}
}
class ShanghaiPeople(sex: Boolean, region: String = "Shanghai") : Chinese(sex, region){
val greatBuilding="the Oriental Pearl Tower"
override val skin ="ShanghaiYellow"
override fun cook() {
super.cook()
val meau = arrayOf("大閘蟹","小湯包","芝士焗面")
val desc = meau.reduce{s1,s2->s1+","+s2}
println("我還會${desc}")
}
}
fun main(args: Array<String>) {
//實例化一個類
val Lili = BeijingPeople(true)
Lili.avgSalary = 6000
println(Lili.region)
println(Lili.avgSalary)
Lili.cook()
println()
val Jack = ShanghaiPeople(true)
Lili.avgSalary = 5000
println(Jack.region)
println(Jack.avgSalary)
Jack.cook()
}
Beijing
5100
我會宮爆雞丁,番茄炒雞蛋,蔥爆牛肉
我還會北京烤鴨,北京炸醬面,北京包子
Shanghai
4000
我會宮爆雞丁,番茄炒雞蛋,蔥爆牛肉
我還會大閘蟹,小湯包,芝士焗面
2.抽象類和接口
抽象類:理解為半成品
接口:類似于協議或者某種成品就有的功能
接口
- 不能有狀態
- 必須有類對其進行實現后實現
- 接口,直觀理解就是一種約定
Kotlin的接口與Objective-C的Protocol比較類似
- 舉例
interface InputDevice{
fun input(event: Any)
}
抽象類
- 實現了一部分協議的半成品
- 可以有狀態,可以有方法實現
- 必須由子類繼承后使用
抽象類和接口的共性
- 比較抽象,不能直接實例化
- 有需要子類(實現類)實現的方法
- 父類(接口)變量可以接受子類(實現類)的實例賦值
抽象類和接口的區別
- 抽象類有狀態,接口沒有狀態
- 抽象類有實現方法,接口只能有無狀態的默認實現
- 抽象類只能單繼承,接口可以多實現
- 抽象類反應本質,接口提現能力
interface InputDevice {
fun input(event: Any)
}
interface USBInputDevice : InputDevice
interface BLEInputDevice : InputDevice
abstract class USBMouse(val name:String) : USBInputDevice,OpticalMouse {
override fun input(event: Any) {
}
override fun toString(): String {
return name
}
}
interface OpticalMouse{
}
class LogitechMouse:USBMouse("羅技鼠標"){
}
class Computer {
fun addUSBInputDevice(inputDevice: USBInputDevice) {
//插入輸入設備
println("add usb input device:$inputDevice")
}
fun addBLEInputDevice(inputDevice: BLEInputDevice) {
//插入輸入設備
println("add input device:$inputDevice")
}
fun addInputDevice(inputDevice: InputDevice) {
when (inputDevice) {
is BLEInputDevice -> {
addBLEInputDevice(inputDevice)
}
is USBInputDevice -> {
addUSBInputDevice(inputDevice)
}
else -> {
throw IllegalArgumentException("輸入設備不支持")
}
}
}
}
fun main(args: Array<String>) {
val computer = Computer()
val mouse = LogitechMouse()
computer.addInputDevice(mouse)
}
add usb input device:羅技鼠標
3.繼承(實現)
繼承(實現)語法要點
- 父類需要open才可以被繼承
- 父類方法、需要open才可以被覆寫
- 接口、接口方法、抽象類默認為open
- 覆寫父類(接口)成員需要override關鍵字
- class D:A(),B,C
- 注意繼承類時實際上調用了父類的構造方法
- 類只能單繼承,接口可以多實現
接口代理
- class Manager(driver:Driver):Driver by driver
- 接口方法實現交給代理類實現
接口方法沖突
- 接口方法可以有默認實現
- 簽名一致且返回值有沖突
- 子類(實現類)必須覆寫沖突方法
- super<[父類(接口)名]>.方法名
abstract class Person(open val age: Int) {
open fun work() {
}
}
class Coder(age: Int) : Person(age) {
override val age: Int
get() = 0
override fun work() {
super.work()
println("我是程序員")
}
}
class Doctor(override val age: Int) : Person(age) {
override fun work() {
super.work()
println("我是醫生")
}
}
fun main(args: Array<String>) {
val person = Coder(28)
person.work()
println(person.age)
val person2 = Doctor(25)
person2.work()
println(person2.age)
}
我是程序員
0
我是醫生
25
class Manager : Driver, Writer {
override fun write() {
}
override fun drive() {
}
}
//寫法一
//class SeniorManager(val driver: Driver,val writer: Writer):Driver,Writer{
// override fun drive(){
// driver.drive()
// }
// override fun write(){
// writer.write()
// }
//}
//簡寫二
class SeniorManager(val driver: Driver, val writer: Writer) : Driver by driver, Writer by writer
class CarDriver : Driver {
override fun drive() {
println("開車了")
}
}
class PPTWriter :Writer{
override fun write(){
println("做PPT了")
}
}
interface Driver {
fun drive() {
}
}
interface Writer {
fun write() {
}
}
fun main(args: Array<String>) {
val driver = CarDriver()
val writer = PPTWriter()
val seniorManager = SeniorManager(driver,writer)
seniorManager.drive()
seniorManager.write()
}
開車了
做PPT了
interface InputDevice {
fun input(event: Any)
}
interface USBInputDevice : InputDevice
interface BLEInputDevice : InputDevice
abstract class USBMouse(val name:String) : USBInputDevice,OpticalMouse {
override fun input(event: Any) {
}
override fun toString(): String {
return name
}
}
interface OpticalMouse{
}
class LogitechMouse:USBMouse("羅技鼠標"){
}
class Computer {
fun addUSBInputDevice(inputDevice: USBInputDevice) {
//插入輸入設備
println("add usb input device:$inputDevice")
}
fun addBLEInputDevice(inputDevice: BLEInputDevice) {
//插入輸入設備
println("add input device:$inputDevice")
}
fun addInputDevice(inputDevice: InputDevice) {
when (inputDevice) {
is BLEInputDevice -> {
addBLEInputDevice(inputDevice)
}
is USBInputDevice -> {
addUSBInputDevice(inputDevice)
}
else -> {
throw IllegalArgumentException("輸入設備不支持")
}
}
}
}
fun main(args: Array<String>) {
val computer = Computer()
val mouse = LogitechMouse()
computer.addInputDevice(mouse)
}
add usb input device:羅技鼠標
4.Kotlin和Java可見性對比
Kotlin | Java |
---|---|
public | public |
private | priavte |
protected | protected |
- | default(包內可見) |
internal(模塊類可見) | - |
5.對象聲明和表達式
object
- 只有一個實例的類
- 不能自定義構造方法
- 可以實現接口、繼承父類
- 本質上就是單例模式最基本的實現
/**
* 有時候只要對某各類進行改造,供零時使用,避免繼承
* 對象聲明和表達式就很有作用
*
* 面向對象編程的優化,避免一些繼承導致的代價過高,保持代碼的整潔
*/
//對中國人來說,這個類,可能各省人適合繼承
open class Chinese(var name: String) {
open val skin = "yellow"
}
fun main(args: Array<String>) {
//但如果外國人入籍,就不適合用繼承
//對象表達式:val 對象名 = object : 類,接口 {//屬性或方法的override定義}
val Jack= object : Chinese ("Jack Marry")
{
override val skin = "white"
}
println(Jack.skin)
//純對象表達式:臨時使用,無須繼承任何類
val loc = object {
var x = 100
var y = 200
}
println(loc.x)
//相當于調用函數
NetworkRequestManager.register()
//半生對象的方法,與類關聯性強
IDCard.create()
}
//對象聲明,不能用在函數中
//一般用于對其他類使用上的包裝
object NetworkRequestManager{
fun register(){
println("連接網絡注冊中...")
}
}
//半生對象:一般用于創建一個類的實例"工廠"方法
//Java中的 靜態成員
class IDCard{
companion object {
fun create() = IDCard()
}
}
white
100
連接網絡注冊中...
6.半生對象與靜態成員
- 每個類可以對應一個伴生對象
- 伴生對象的成員全局獨一份
- 伴生對象的成員類似Java的靜態成員
- 靜態成員考慮用包級函數、變量替代
- JvmField和JvmStatic的使用
fun main(args: Array<String>) {
val a = minOf(args[0].toInt(), args[1].toInt())
val latitude = Latitude.ofDouble(3.0)
val latitude2 = Latitude.ofLatitude(latitude)
println(Latitude.TAG)
}
class Latitude private constructor(val value: Double) {
companion object {
@JvmStatic
fun ofDouble(double: Double): Latitude {
return Latitude(double)
}
fun ofLatitude(latitude: Latitude): Latitude {
return Latitude(latitude.value)
}
@JvmField
val TAG:String = "Latitude"
}
}
Latitude
JvmStatic JvmField 用于Java類調用
public class StaticJava {
public static void main(String[] args){
Latitude latitude = Latitude.ofDouble(4);
System.out.println("Java:"+Latitude.TAG);
}
}
Java:Latitude
6.方法重載Overloads 和默認參數
方法重載Overloads
- 名稱相同、參數不同的方法
- Jvm函數簽名的概念:函數名、參數列表
- 跟返回值沒有關系
默認參數
- 為函數參數設定一個默認值
- 可以為任意位置的參數設置默認值
- 函數調用產生混淆時用具名參數
兩者關系
- 避免定義關系不大的重載
- 方法重載最好能轉化為默認參數
- 不好的設計:
- List.remove(int)
- List.remove(Object)
//方法重載和函數名有和參數列表有關系,和函數返回值沒關系
class Overloads {
// fun a(): Int {
// return 0
// }
@JvmOverloads //默認參數 是給java調用的
fun a(int: Int = 0): Int {
return int
}
}
fun main(args: Array<String>) {
val overloads = Overloads()
overloads.a()
val integerList = ArrayList<Int>()
integerList.add(555)
integerList.add(2)
integerList.add(3)
integerList.add(4)
integerList.add(9)
integerList.add(45)
println(integerList.toString())
integerList.removeAt(1)
integerList.remove(9)
println(integerList.toString())
}
[555, 2, 3, 4, 9, 45]
[555, 3, 4, 45]
7.擴展成員
- Java調用擴展成員類似調用靜態方法
- 為現有類添加方法、屬性
- fun X.y():Z{...}
- val X.m 主義擴展屬性不能初始化,類似接口屬性
fun main(args: Array<String>) {
println("abc" * 16)
"abc".b = 5
println("abc".b)
}
operator fun String.times(int: Int): String {
val stringBuilder = StringBuilder()
for (i in 0 until int) {
stringBuilder.append(this)
}
return stringBuilder.toString()
}
val String.a: String
get() = "abc"
var String.b: Int
set(value) {
}
get() = 5
abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc
5
8.屬性代理
- 定義方法:
- val/var <property name>:<Type> by
<expression>
- 代理者需要實現相應的setValue/getValue方法:
- lazy原理剖析
9.數據類
- 再見,JavaBean
- 默認實現的copy,toString等方法
- componentN方法
- allOpen和noArg插件 在編譯器 把final關鍵字去掉
import com.haocai.kotlindemo.annotations.Poko
@Poko
data class Country(val id: Int, val name: String)
class ComponentX {
operator fun component1(): String {
return "您還,我是"
}
operator fun component2(): Int {
return 1
}
operator fun component3(): Int {
return 1
}
operator fun component4(): Int {
return 0
}
}
fun main(args: Array<String>) {
val china = Country(0, "中國")
println(china)
println(china.component1())
println(china.component2())
val (id, name) = china
println(id)
println(name)
// for ((index, value) in args.withIndex()) {
// println(index)
// println(value)
// }
val componentX = ComponentX()
val (a, b, c, d) = componentX
println("$a $b $c $d")
}
10.內部類
- 定義在類內部的類
- 與類成員有相似的訪問控制
- 默認是靜態內部類,非靜態用inner關鍵字
- this@Outter,this@Inner的用法
- 沒有定義名字的內部類
- 類名編譯時生成,類似Outter$1.class
- 可繼承父類、實現多個接口,與Java注意區別
Kotlin寫法:
open class Outter {
val a: Int = 0
inner class Inner {
val a: Int = 5
fun hello() {
println(this@Outter.a)
}
}
}
interface OnClickListener {
fun onClick()
}
class View {
var onClickListener: OnClickListener? = null
}
fun main(args: Array<String>) {
val inner = Outter().Inner()
inner.hello()
val view = View()
//匿名內部類 即可以實現接口,同時繼承外部類(如,Outter())
view.onClickListener = object : Outter(),OnClickListener{
override fun onClick() {
}
}
}
0
Java類似寫法:
public class InnerClassJava {
private int a;
public static void main(String... args) {
InnerClassJava innerClassJava = new InnerClassJava();
Inner inner = innerClassJava.new Inner();
//Inner inner = new Inner(); 報錯 除非Inner 是靜態
inner.hello();
View view = new View();
view.setOnClickListener(new OnClickListener() {
@Override
public void onClick() {
}
});
}
public class Inner {
public void hello() {
System.out.println(InnerClassJava.this.a); //非靜態內部類可以持有外部類的狀態
}
}
}
0
11.枚舉
- 實例可數的參數,注意枚舉也是類
- 可以修改構造,添加成員
- 可以提升代碼的表現力,也有一定的性能開銷
enum class LogLevel(val id: Int) {
VERBOSE(0), DEBUG(1), INFO(2), WARN(3), ERROR(4), ASSERT(5);
fun getTag(): String {
return "$id,$name"
}
override fun toString(): String {
return "$name,$ordinal"
}
}
class LogLevel2 protected constructor() {
companion object {
val VERBOSE = LogLevel2()
val DEBUG = LogLevel2
val INFO = LogLevel2
val WARN = LogLevel2
val ERROR = LogLevel2
val ASSERT = LogLevel2
}
}
fun main(args: Array<String>) {
println(LogLevel.INFO.getTag())
println(LogLevel.DEBUG.ordinal)
LogLevel.values().map(::println)
}
2,INFO
1
VERBOSE,0
DEBUG,1
INFO,2
WARN,3
ERROR,4
ASSERT,5
12.密封類
- 子類可數(從v1.1開始,只需要與密封類在同一個文件中)
- 枚舉是實例可數
sealed class PlayerCmd{
class Play(val url:String ,val position:Long = 0):PlayerCmd()
class Seek(val position:Long ):PlayerCmd()
object Pause:PlayerCmd()
object Resume:PlayerCmd()
object Stop:PlayerCmd()
}
enum class PlayerState{
IDLE,PAUSE,PLAYING
}