類
類定義格式
使用class關鍵字定義,格式如下:
class T{
//屬性
//建構函式
//函式
//內部類
}
Java Bean類
java bean類
//java bean類
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name) {
this.name = name;
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
java bean類(kotlin實現)
//kotlin寫法,get和set方法預設實現
class Student {
/注意,這裡的var代表著變數的數值之後可以被修改,也可以使用只讀val
//?是可為空的寫法,後面會提到
//這裡其實包含了主構造方法,不過因為主構造方法為空,所以省略了
var name: String? = null
var age: Int = 0
//這幾個constructor是次級構造方法
constructor() {}
constructor(name: String) {
this.name = name
}
constructor(name: String, age: Int) {
this.name = name
this.age = age
}
}
//下面是沒有省略主構造方法的
//注意,因為把預設的主構造方法寫了出來,所以,不允許出現無引數的次構造方法
class Student public constructor() {
//注意,這裡的var代表著變數的數值之後可以被修改,也可以使用只讀val
//?是可為空的寫法,後面會提到
//這裡其實包含了主構造方法,不過因為主構造方法為空,所以省略了
var name: String? = null
var age: Int = 0
//這幾個constructor是次級構造方法
constructor(name: String) : this() {
this.name = name
}
constructor(name: String, age: Int) : this(){
this.name = name
this.age = age
}
}
主函式呼叫
//主函式呼叫
fun main(args: Array<String>){
//宣告類不需要new關鍵字
val student = Student("star",12)
//,使用物件.屬性名呼叫,而不是使用get或set
println(student.age)//獲得屬性
student.name = "stars"//修改屬性
}
主構造方法(kotlin)
kotlin類中可以有主構造方法和次構造方法,次構造方法也就是上面那段使用kotlin實現的Java Bean類(上面的主構造方法其實是省略了的)
/*下面三種方法都是宣告瞭一個Student類
*Student包含了一個構造方法(兩個引數),還有兩個成員變數以及成員變數對應的get和set方法
*/
//原始方式,使用主構造方法
class Student public constructor(name: String,age: Int) {
//注意,這裡的var代表著變數的數值之後可以被修改,也可以使用只讀val
var name = name
var age = age
}
//簡潔寫法,如果主構造方法只有預設的修飾符(public,預設的修飾符可省略),可以把constructor省略
class Student(name: String,age: Int) {
var name = name
var age = age
}
//更簡潔寫法
class Student(var name: String,var age: Int) {
}
//使用Student類
fun main(args: Array<String>) {
//宣告類不需要new關鍵字
val student = Student("star",12)
println(student.name)
println(student.age)
student.age = 19 //修改內容
println(student.age)
}
init(初始化塊)
如果我們想要在主構造方法進行初始化操作,需要在init程式碼塊裡面寫我們的程式碼,如
//更簡潔寫法
class Student(var name: String,var age: Int) {
init{
println("這裡是初始化操作")
}
}
注意,初始化塊是主構造方法的一部分
初始化操作會在次構造方法之前執行,即使沒有寫主構造方法,如:
class Student{
var name: String? = null
var age: Int = 0
init{
println("這裡是初始化操作")
}
constructor(name: String, age: Int) {
this.name = name
this.age = age
}
}
主/次構造方法聯合使用
類定義了主構造器,次構造器必須直接或間接呼叫主構造器;
class Student() {
var name: String? = null
var age: Int = 0
//這幾個constructor是次級構造方法,,這裡的this()就是當前的主構造方法
constructor(name: String) : this() {
this.name = name
}
constructor(name: String, age: Int) : this(){
this.name = name
this.age = age
}
}
class Student public constructor() {
var name: String? = null
var age: Int = 0
//這幾個constructor是次級構造方法,,這裡的this()就是當前的主構造方法
//這裡用專業術語說,是次級構造方法需要委託給主構造方法
constructor(name: String) : this() {
this.name = name
}
constructor(name: String, age: Int) : this(){
this.name = name
this.age = age
}
}
伴生方法(靜態方法)
class Student{
...
companion object {
@JvmStatic
//下面定義一些方法
fun sayHello() {
println("hello")
}
}
}
get/set方法修改
看完上面,我們都知道kotlin預設幫我們實現了get和set方法,val修飾的變數是隻讀的,所以該變數沒有setter方法
格式:
var <propertyName>[: <PropertyType>] [= <property_initializer>]
[<getter>]
[<setter>]
//表示式寫法
get() = ...
//花括號寫法
get(){
...
return xx
}
class Student() {
var name: String = ""
var age: Int = 0
//這裡使用val
val isNameEmpty: Boolean
get() = name.length==0
//使用var就得賦值
//val isNameEmpty: Boolean
// get() = name.length==0
constructor(name: String) : this() {
this.name = name
}
constructor(name: String, age: Int) : this(){
this.name = name
this.age = age
}
}
如果要在get和set引用當前的欄位(屬性值),得使用filed關鍵字代替內容
class Student() {
var name: String = ""
//如果當前的name為"",則返回小紅作為姓名
//這裡的filed就是name,型別也與name一樣
get() {
return if(field.length==0) "小紅" else field
}
var age: Int = 0
constructor(name: String) : this() {
this.name = name
}
constructor(name: String, age: Int) : this(){
this.name = name
this.age = age
}
}
setter方法與之前的getter方法一樣,裡面也是使用field代替當前的數值,只不過setter有一個引數,預設為value,可以修改名字
set(value){
filed = vaule
}
巢狀類和內部類
巢狀類和內部類的區別是,巢狀類無法引用外層類的屬性和方法,而內部類可以
//Nested為巢狀類
class Outer {
private val bar: Int = 1
class Nested {
//這裡因為是巢狀類,無法引用Outer中的bar
fun foo() = 2
}
}
val demo = Outer.Nested().foo() // == 2
內部類,使用inner關鍵字
class Outer {
private val bar: Int = 1
inner class Inner {
//這裡可以引用bar
fun foo() = bar
}
}
val demo = Outer().Inner().foo() // == 1
繼承和介面
繼承
kotlin所有的類都是繼承於Any
,注意,Any 並不是 java.lang.Object
kotlin中的類預設是不可繼承的,需要有open
關鍵字修飾類,需要在子類複寫的方法,也得在父類用open
修飾該方法
open class Person{
var name: String = ""
var age: Int =0
constructor(){}
constructor(name: String, age: Int){
this.name = name
this.age = age
}
open fun hello() {
println("hello this is person")
}
}
class Student: Person {
constructor() : super(){}
constructor(name: String,age: Int) :super(name,age){}
override fun hello() {
println("hello this is student")
}
}
介面
介面的實現也是使用:
,宣告介面也是interface關鍵字,注意,kotlin中的介面方法可以實現
interface Print {
fun print()
fun say(){
println("sayhello")
}
}
Student類繼承Person並實現Print介面:
class Student: Person,Print {
override fun print() {
//複寫介面裡的方法
}
constructor(name: String,age: Int) :super(name,age){}
override fun hello() {
}
}
資料類
介紹
kotlin提供了一個資料類,專門類存放資料,使用關鍵字data修飾類
官方的關於資料類的規範:
- 主建構函式需要至少有一個引數;
- 主建構函式的所有引數需要標記為 val 或 var;
- 資料類不能是抽象、開放、密封或者內部的;
- (在1.1之前)資料類只能實現介面。
資料類主要有下面兩種特點:
- 自動解析
- 直接複製
資料類定義
data class Person(var name: String,var age: Int){
}
自動解析
自動解析有順序,根據類中屬性的屬性
val person = Person("star",19)
//val括號裡可以根據需要選擇不同引數,注意順序,不能跳過一個不需要的屬性
val(name,age) = person
println("$name, $age years of age") // 輸出 "star, 19 years of age"
複製
val person = Person("star",19)
val person1 = person.copy()
//複製並修改部分屬性
val person2 = person.copy(age =23)
總結
個人覺得,如果某個類只有一個構造方法,可以定義類只含有一個主構造方法即可,使用那個最簡潔的方式。
如果需要有不同引數的構造方法(或者是Java Bean),則使用次級構造方法
如果是用來當做資料類,則使用資料類定義