Kotlin学习之面向对象
定义普通类
复制fun main(args: Array<String>) {
val person = Person("lisi") //不需要使用new关键字
println(person) //useranme:lisi,age:20
val person2 = Person("lisi", 23)
println(person2) //useranme:lisi,age:23
}
class Person constructor(username: String) {
private var username: String
private var age: Int
init {
// 通过主构造器为属性赋值
this.username = username
this.age = 20
}
// 次构造器
constructor(username: String, age: Int) : this(username) {
this.age = age
}
// 重写toString()方法
override fun toString(): String {
return "useranme:$username,age:$age"
}
}
每个类都有一个主构造器和多个次构造器(可以没有),
主构造器是类头部的一部分,位于类名称之后,init初始化块为属性赋值,
次构造器使用constructor前缀,每个次构造器要直接或间接的调用主构造器。
复制class Person constructor(private val username: String) {
override fun toString(): String {
return "username:$username"
}
}
这是一种简化的写法,通过主构造器定义属性并初始化。
getter和setter
复制fun main(args: Array<String>) {
val person = Person("lisi")
println(person.username)
person.username = "lisi2"
println(person.username)
}
class Person constructor(username: String) {
var username: String = username
get() {
println("get invoked")
return field
}
set(value) {
println("set invoked")
field = value
}
}
访问属性默认调用属性的get()方法,修改属性默认调用属性的set()方法,如果我们没有定义,kotlin会自动生成getter和setter。
嵌套类和内部类
复制fun main(args: Array<String>) {
println(Person.NestedClass())
println(Person().InnerClass())
}
class Person {
//嵌套类
class NestedClass
//内部类
inner class InnerClass
}
嵌套类类似java的静态内部类,内部类类似java的非静态内部类。
继承
复制fun main(args: Array<String>) {
val person = Child("lisi")
person.printUsername()
}
// 父类
open class Parent constructor(private val username: String) {
open fun printUsername() {
println(this.username)
}
}
// 子类
class Child(private val username: String) : Parent(username) {
//方法重写,且不能被再次重写
final override fun printUsername() {
println(this.username)
}
}
kotlin中所有类默认继承于Any,且默认不可被继承,open标识符表示类可以被继承或方法可以被重写。
通过override标识符重写父类的方法,final表示不允许被子类再次重写。
定义接口
复制fun main(args: Array<String>) {
val person = UserService()
person.saveUser("张三")
}
// 定义接口
interface IUserService {
fun getUser(): String
fun saveUser(user: String) {
println(this.getUser())
}
}
// 定义实现类
class UserService : IUserService {
override fun getUser(): String {
return "lisi"
}
}
kotlin中接口的方法也可以有默认实现,类似java中接口的默认方法。
扩展函数和属性
复制fun main(args: Array<String>) {
val person = Person("lisi")
person.printUsername()
println(person.age)
}
class Person(private val username: String) {
fun getUsername(): String {
return username;
}
}
// 为Person类扩展一个方法
fun Person.printUsername() {
println(this.getUsername())
}
// 为Person类扩展一个属性
val Person.age: Int
get() = 20
扩展函数不会对目标类做修改,静态解析,不支持多态。
复制fun main(args: Array<String>) {
printName(Child()) //Parent
}
open class Parent {
}
class Child : Parent() {
}
fun Parent.name() = "Parent"
fun Child.name() = "Child"
fun printName(p: Parent) {
println(p.name())
}
我们对父类和子类都扩展了name()方法,printName()方法的参数声明为Parent,所以调用的扩展方法为Parent的name()方法,和参数的实际类型无关。反编译结果为
点击查看代码
复制public final class FirstDemoKt {
public static final void main(@NotNull String[] args) {
Intrinsics.checkParameterIsNotNull(args, "args");
printName((Parent)(new Child()));
}
@NotNull
public static final String name(@NotNull Parent $receiver) {
Intrinsics.checkParameterIsNotNull($receiver, "receiver$0");
return "Parent";
}
@NotNull
public static final String name(@NotNull Child $receiver) {
Intrinsics.checkParameterIsNotNull($receiver, "receiver$0");
return "Child";
}
public static final void printName(@NotNull Parent p) {
Intrinsics.checkParameterIsNotNull(p, "p");
String var1 = name(p);
System.out.println(var1);
}
}
对象表达式
复制fun main(args: Array<String>) {
val obj = object {
fun method() = "hello"
}
println(obj.method())
}
类似java的匿名内部类,但功能更加强大。
对象声明
复制fun main(args: Array<String>) {
Person.test("lisi")
}
// 对象声明
object Person {
fun test(p: String) {
println(p)
}
}
可以看做声明了一个单例对象,反编译结果为
点击查看代码
复制public final class FirstDemoKt {
public static final void main(@NotNull String[] args) {
Intrinsics.checkParameterIsNotNull(args, "args");
Person.INSTANCE.test("lisi");
}
}
public final class Person {
public static final Person INSTANCE;
public final void test(@NotNull String p) {
Intrinsics.checkParameterIsNotNull(p, "p");
System.out.println(p);
}
private Person() {
}
static {
Person var0 = new Person();
INSTANCE = var0;
}
}
伴生对象
复制fun main(args: Array<String>) {
Person.testStatic()
println(Person.NAME)
}
class Person {
companion object {
val NAME: String = "LISI"
fun testStatic() {
println("static")
}
}
}
可以理解为java中的static属性和static方法。
定义数据类
复制fun main(args: Array<String>) {
val person = Person("lisi", 23)
println(person) //Person(name=lisi, age=23)
}
data class Person(var name: String, var age: Int) {
}
kotlin为数据类默认创建equals(),hashCode(),toString(),copy(),componentN()等方法,
类似于java中普通数据类,仅用来保存数据,没有额外的功能,java中使用lombok组件也可以达到此效果。
反编译结果为
点击查看代码
复制public final class Person {
@NotNull
private String name;
private int age;
@NotNull
public final String getName() {
return this.name;
}
public final void setName(@NotNull String var1) {
Intrinsics.checkParameterIsNotNull(var1, "<set-?>");
this.name = var1;
}
public final int getAge() {
return this.age;
}
public final void setAge(int var1) {
this.age = var1;
}
public Person(@NotNull String name, int age) {
Intrinsics.checkParameterIsNotNull(name, "name");
super();
this.name = name;
this.age = age;
}
@NotNull
public final String component1() {
return this.name;
}
public final int component2() {
return this.age;
}
@NotNull
public final Person copy(@NotNull String name, int age) {
Intrinsics.checkParameterIsNotNull(name, "name");
return new Person(name, age);
}
// $FF: synthetic method
@NotNull
public static Person copy$default(Person var0, String var1, int var2, int var3, Object var4) {
if ((var3 & 1) != 0) {
var1 = var0.name;
}
if ((var3 & 2) != 0) {
var2 = var0.age;
}
return var0.copy(var1, var2);
}
@NotNull
public String toString() {
return "Person(name=" + this.name + ", age=" + this.age + ")";
}
public int hashCode() {
String var10000 = this.name;
return (var10000 != null ? var10000.hashCode() : 0) * 31 + this.age;
}
public boolean equals(@Nullable Object var1) {
if (this != var1) {
if (var1 instanceof Person) {
Person var2 = (Person)var1;
if (Intrinsics.areEqual(this.name, var2.name) && this.age == var2.age) {
return true;
}
}
return false;
} else {
return true;
}
}
}
解构赋值
复制fun main(args: Array<String>) {
val (name, age) = Person("lisi", 23)
println("$name,$age")//lisi,23
}
data class Person(var name: String, var age: Int) {
}
会依次调动数据类的componentN()方法赋值给左边变量
定义密封类
复制fun main(args: Array<String>) {
println(calc(1, 2, Add()))
println(calc(1, 2, Sub()))
}
fun calc(a: Int, b: Int, oper: Calculator): Int {
return when (oper) {
is Add -> a + b
is Sub -> a - b
}
}
// 密封类
sealed class Calculator
class Add : Calculator()
class Sub : Calculator()
密封类用来表示受限的类继承结构,如例子中的,编译器知道密封类Calculator只有两个子类Add和Sub,被可能还有其他的子类,所以在when表达式中就不需要else语句了。
泛型
复制fun main(args: Array<String>) {
val wrapper = Wrapper("hello")
println(wrapper.item)
Person().save(123)
}
// 泛型类
class Wrapper<T>(var item: T) {
}
// 泛型方法
class Person {
fun <T> save(item: T) {
println(item)
}
}
更多关于kotlin中的泛型知识,如协变和逆变等,可以查看官方文档。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
2021-06-01 java处理emoji表情