注:编码工具为IntelliJ
目录
类的继承和方法重写
智能转换:is as
object类型
object表达式
伴生对象:companion object
嵌套类和内部类
数据类型:data class
自定义解构函数
运算符重载
枚举:enum class
密封类:sealed class
类的继承和方法重写
Kotlin的类和方法默认都是public final的,如果想要让类可以被继承、方法可以被重写,需要在类声明和方法声明前添加open关键字。
open class base(var info: String){
open fun show(){
println("base info:$info")
}
}
class Subbase():base("World from Sub"){
override fun show() {
super.show()
println("sub info:$info")
}
}
fun main() {
val b: base = base("Universe from base")
val b2: base = Subbase()
b.show()
b2.show()
}
输出:
base info:Universe from base base info:World from Sub sub info:World from Sub
智能转换:is as
Kotlin中判断某个对象是否某种数据类型的对象时使用is,相当于Java的instanceof,如果该对象确实是该数据类型的对象,is判断后会智能转换为该数据类型对象,可以直接使用该对象;
Kotlin中使用as将一种类型对象转换为另一种数据类型对象,相当于Java的强制类型转换。
open class base2(var info: String){
open fun show(){
println("base2 info: $info")
}
}
class Subbase2(): base2("Subbase2"){
override fun show() {
println("subbase2 info: $info")
}
fun unique(){
println("subbase2特有方法")
}
}
class Subbase21(): base2("Subbase22"){
override fun show() {
println("subbase22 info: $info")
}
fun test(){
println("subbase21特有方法")
}
}
fun traverse(b: base2){
when (b) {
is Subbase2 -> {
b.unique()// is判断后智能转换为Subbase2
}
is Subbase21 -> {
b.test()// is判断后只能转换为Subbase21
}
else -> {
b.show()
}
}
}
fun main() {
val b: base2 = base2("base2")
val b2: base2 = Subbase2()
val b3: base2 = Subbase21()
// 只有as转换后,才能调用Subbase2的特有方法
(b2 as Subbase2).unique()
// 只有as转换后,才能调用Subbase21的特有方法
(b3 as Subbase21).test()
println("---------------------------------")
traverse(b)
traverse(b2)
traverse(b3)
}
输出:
subbase2特有方法 subbase21特有方法 --------------------------------- base2 info: base2 subbase2特有方法 subbase21特有方法
object类型
object XXXUtils{
fun op(input: String){
println("handle $input via op func")
}
}
fun main() {
val x = XXXUtils
XXXUtils.op("输入")
}
输出:
handle 输入 via op func
反编译为Java代码:
public final class XXXUtils {
@NotNull
public static final XXXUtils INSTANCE;
public final void op(@NotNull String input) {
Intrinsics.checkNotNullParameter(input, "input");
String var2 = "handle " + input + " via op func";
boolean var3 = false;
System.out.println(var2);
}
private XXXUtils() {
}
static {
XXXUtils var0 = new XXXUtils();
INSTANCE = var0;
}
}
public final class ObjectTestKt {
public static final void main() {
XXXUtils x = XXXUtils.INSTANCE;
XXXUtils.INSTANCE.op("输入");
}
// $FF: synthetic method
public static void main(String[] var0) {
main();
}
}
看反编译的Java代码,可以发现,XXXUtils类内部会声明一个public static的XXXUtils变量,并在static代码框中创建对象,之后的调用XXXUtils类的成员都用这个对象,有点类似于Java的单例。object类型直接用 类型名. 的格式访问成员,类似于Java调用静态成员。
object表达式
kotlin没有匿名内部类,可以用object表达式定义对象,实现类似的效果。
fun main() {
val i = object : I{
override fun test() {
println("object expression test")
}
}
i.test()
}
输出:
object expression test
Java的某些只有一个方法的接口可以有另外一种定义对象的方式,但Kotlin的只含有一个函数的接口不可以。
fun main() {
val run = object: Runnable{
override fun run() {
println("run")
}
}
val run2 = Runnable {
println("run2")
}
run.run()
run2.run()
}
输出:
run run2
伴生对象:companion object
Kotlin中没有static关键字,可以用伴生对象代替。
class CompanionObjectTest{
companion object {
var TAG = "PRINT"
fun show(info: String){
println("info: $info")
}
}
}
fun main() {
CompanionObjectTest.show("test companion object")
println(CompanionObjectTest.TAG)
}
输出:
info: test companion object PRINT
嵌套类和内部类
Kotlin的类内部定义的没有inner修饰的类是嵌套类,相当于Java类内部定义的static类;
Kotlin的类内部定义的有inner修饰的类是内部类,相当于Java的内部类。
class Outer {
class Nested {
fun show() {
println("Nested")
}
}
inner class Inner {
fun show() {
println("Inner")
}
}
}
fun main() {
Outer.Nested().show()
Outer().Inner().show()
}
输出:
Nested Inner
数据类型:data class
数据类是Kotlin提供的为了方便开发人员开发的类似于JavaBean的类。
数据类的特点:
1、类声明后会自动生成主构造函数参数相关的getter、setter、componetN系列(解构用)、copy、equals、hashCode、toString方法;
2、主构造函数参数必须带var/val修饰符;
3、不能在类声明前加sealed/abstract/open/inner等修饰符。
data class Student(var name: String, var age: Int, var gender: Char)
fun main() {
val stu = Student("gg", 14, 'F')
println(stu)
val(name, age, gender) = stu// 解构 通过componentN系列函数实现
println("name:$name, age:$age, gender:$gender")
val(n, a, _) = stu// 不想解构的函数可以用_屏蔽
println("name:$n, age:$a")
}
输出:
Student(name=gg, age=14, gender=F) name:gg, age:14, gender:F name:gg, age:14
反编译为Java代码:
public final class Student {
@NotNull
private String name;
private int age;
private char gender;
@NotNull
public final String getName() {
return this.name;
}
public final void setName(@NotNull String var1) {
Intrinsics.checkNotNullParameter(var1, "");
this.name = var1;
}
public final int getAge() {
return this.age;
}
public final void setAge(int var1) {
this.age = var1;
}
public final char getGender() {
return this.gender;
}
public final void setGender(char var1) {
this.gender = var1;
}
public Student(@NotNull String name, int age, char gender) {
Intrinsics.checkNotNullParameter(name, "name");
super();
this.name = name;
this.age = age;
this.gender = gender;
}
@NotNull
public final String component1() {
return this.name;
}
public final int component2() {
return this.age;
}
public final char component3() {
return this.gender;
}
@NotNull
public final Student copy(@NotNull String name, int age, char gender) {
Intrinsics.checkNotNullParameter(name, "name");
return new Student(name, age, gender);
}
// $FF: synthetic method
public static Student copy$default(Student var0, String var1, int var2, char var3, int var4, Object var5) {
if ((var4 & 1) != 0) {
var1 = var0.name;
}
if ((var4 & 2) != 0) {
var2 = var0.age;
}
if ((var4 & 4) != 0) {
var3 = var0.gender;
}
return var0.copy(var1, var2, var3);
}
@NotNull
public String toString() {
return "Student(name=" + this.name + ", age=" + this.age + ", gender=" + this.gender + ")";
}
public int hashCode() {
String var10000 = this.name;
return ((var10000 != null ? var10000.hashCode() : 0) * 31 + Integer.hashCode(this.age)) * 31 + Character.hashCode(this.gender);
}
public boolean equals(@Nullable Object var1) {
if (this != var1) {
if (var1 instanceof Student) {
Student var2 = (Student)var1;
if (Intrinsics.areEqual(this.name, var2.name) && this.age == var2.age && this.gender == var2.gender) {
return true;
}
}
return false;
} else {
return true;
}
}
}
自定义解构函数
可以为普通类定义解构函数,实现解构操作,componentN函数要从component1开始。
解构函数要用operator修饰。
解构函数的数目可以不和成员变量的数目一致,顺序也可以不和成员变量声明的顺序一致。如下面的代码所示,总共三个成员变量name,age,gender,但只声明了两个解构函数,且第一个解构函数返回的是gender,和成员变量声明的顺序不一致。
class ComponentTest(var name:String, var age: Int, var gender: Char){
operator fun component1(): Char{
return gender
}
operator fun component2(): Int{
return age
}
}
fun main() {
val c = ComponentTest("name", 1, 'M')
println("name:${c.name}, age:${c.age}, gender:${c.gender}")
val (gender, age) = c
println("gender:$gender, age:$age")
}
输出:
name:name, age:1, gender:M gender:M, age:1
运算符重载
用于对象之间+、-、*、/等操作。
class Point(var x: Int, var y: Int){
// +
operator fun plus(another: Point) : Point{
return Point(x + another.x, y + another.y)
}
// -
operator fun minus(another: Point) : Point{
return Point(x - another.x, y - another.y)
}
override fun toString(): String {
return "Point{x:$x, y:$y}"
}
}
fun main() {
val p1 = Point(4, 8)
val p2 = Point(3, 9)
val sum = p1 + p2
val diff = p1 - p2
println(sum)
println(diff)
}
输出:
Point{x:7, y:17}
Point{x:1, y:-1}
枚举:enum class
Kotlin中的枚举也是类,用enum class定义,枚举类可以有构造函数、成员变量、成员函数。构造函数只有在枚举类内部定义枚举项的时候可以使用,其他的时候不能使用;成员变量和成员函数可以跟普通类的一样使用。
enum class Shape(var cname: String){
TRIANGLE("三角形"),
CIRCLE("圆形"),
RECTANGLE("矩形"),
SQUARE("正方形");
var state = 1
fun show(){
println("$this cname is $cname, state is $state")
}
}
fun main() {
Shape.CIRCLE.state = 0
Shape.CIRCLE.show()
println(Shape.RECTANGLE)
Shape.SQUARE.cname = "square"
println(Shape.SQUARE.cname)
}
输出:
CIRCLE cname is 圆形, state is 0 RECTANGLE square
用when判断枚举类型,可以不写else分支,编译器可以自动推断是否覆盖所有枚举项。下面要说的密封类类似。
密封类:sealed class
sealed class Color{
object red: Color()
object green: Color()
object blue: Color()
class other(val name: String): Color()
}
fun show(color: Color) =
when(color)
{
is Color.red -> "红色"
is Color.green -> "绿色"
is Color.blue -> "蓝色"
is Color.other -> color.name// 智能转换
}
fun main() {
println(show(Color.red))
println(show(Color.green))
println(show(Color.blue))
println(show(Color.other("紫色")))
println(show(Color.other("粉色")))
}
输出:
红色 绿色 蓝色 紫色 粉色



