Kotlin对比Java 入门学习记录(柒)

Kotlin入门学习记录
2023/12/03 - 2023/12/04

方法重写

在KT中默认所有属性和方法以及类都为final修饰,即不可继承,如果想要能够被继承需要使用open关键字修饰,并且在重写时需要在方法前加上override关键字,代码实现如下

open class Product(val name:String){
    fun description() = "Product:$name"
    open fun load() = "Nothing"
}
class XiaomiProduct:Product("Xiaomi 14"){
    override fun load(): String = "XiaomiProduct loading"
}
fun main() {
    val p:Product = XiaomiProduct()
    println(p.load())//XiaomiProduct loading
}

类型识别

使用is关键字和Java中的instanceof关键字类似,代码实现如下

...
fun main() {
    val p:Product = XiaomiProduct()
    println(p is XiaomiProduct)//true
    println(p is Product)//true
    println(p is File)//false
}
...

强制类型转换

KT中使用as关键字进行强制类型转换,调用子类方法,代码实现如下

class XiaomiProduct:Product("Xiaomi 14"){
    ...
    fun special() = "XiaomiProduct special fun"
}
fun main() {
    val p:Product = XiaomiProduct()
    if (p is XiaomiProduct) {
        println((p as XiaomiProduct).special())
        	//XiaomiProduct special fun
    }
}

Java实现代码如下

public static void main(String[] args) {
	Product p = new XiaomiProduct();
	if (p instanceof XiaomiProduct){
		System.out.println(((XiaomiProduct) p).special());
			//XiaomiProduct special fun
	}
}

智能类型转换

当需要频繁调用子类方法时,在Java中的多态需要频繁转换类型,在KT中只需要转换一次就可以调用子类方法,代码实现如下

fun main() {
    val p:Product = XiaomiProduct()
    println((p as XiaomiProduct).special())//XiaomiProduct special fun
    println(p.special())//XiaomiProduct special fun
}

将Jvm字节码转为Java,如下,
var1 = ((XiaomiProduct)p).special();可以看出编译器自动将类型强制转换

public static final void main() {
      Product p = (Product)(new XiaomiProduct());
      String var1 = ((XiaomiProduct)p).special();
      System.out.println(var1);
      var1 = p.load();
      System.out.println(var1);
      var1 = ((XiaomiProduct)p).special();
      System.out.println(var1);
}

Any超类

在KT中所有的类都继承Any就像Java中的Object一样,KT中的Any包含的函数如下
注意
Any类中的函数没有具体实现,是因为KT要实现跨平台性,所以放到编译器中去实现函数
Any类中的equals(==)比较的是引用和String中的===一样

public open class Any {
    public open operator fun equals(other: Any?): Boolean
    public open fun hashCode(): Int
    public open fun toString(): String
}

对象

使用object关键字创建单例类,object关键字有三种方式:对象声明(object declaration)、对象表达式(object expression)和伴生对象(companion object)

对象声明

object ApplicationConfig{
    init {
        println("loading config")
    }
    fun setSomething(){
        println("setSomething")
    }
}
fun main() {
    ApplicationConfig.setSomething()
}

对象表达式

KT中的对象表达式和Java中的匿名内部类类似,不同的是Java中只能是实现一个接口或类,但KT可以实现多个,代码实现如下

open class Player{
    open fun load() = "load nothing"
}
fun main() {
    val p = object : Player(){
        override fun load(): String =
            "anyone classload"
    }
    println(p.load())//anyone classload
}

伴生对象

如果你想将某个对象的初始化和一个类实例捆绑在一起,可以考虑使用伴生对象。使用
companion,代码实现如下
注意
一个类只能有一个伴生对象,包含伴生对象的类初始化时,伴生对象就会被初始

open class ConfigMap{
    companion object{
        private const val PATH = "test.txt"
        fun load() = File(PATH).readLines()
    }
}
fun main() {
    println(ConfigMap.load())
}

嵌套类

就是类中类,相当于Java中的内部类,默认为static修饰,代码实现如下

class Player2{
    class Equipment(var name:String){
        fun show() = println("equipment $name")
    }
    fun battle(){
        Equipment("LY_C").show()
    }
}
fun main() {
    Player2().battle()
    Player2.Equipment("CRY").show()
}

Java代码实现如下

public class Player2 {
    static class Equipment{
        String name;
        public Equipment(String name) {
            this.name = name;
        }
        void show(){
            System.out.println("equipment"+name);
        }
    }
    void battle(){
        new Equipment("LY_C").show();
    }
}
class MAIN{
    public static void main(String[] args) {
        new Player2().battle();
        new Player2.Equipment("LY_C").show();
    }
}

数据类

数据类就是使用了data关键字的class,重写了超类的toStringequals方法,添加了方便复制对象的copy方法

toString

重写了toString方法,代码实现如下

data class CardinalDirection(var x:Int,var y:Int) {
    val isInBounds = x > 0 && y > 0
}

fun main() {
    println(CardinalDirection(10, 20))
    	//CardinalDirection(x=10, y=20)
}

equals

重写了Any的equals(==)方法,从比较引用改成比较内容,代码实现如下

...
fun main() {
    ...
    println(CardinalDirection(10, 10) == CardinalDirection(10, 10))
    	//true
}

copy

类似于Java中的clone,用来方便地复制一个对象,代码实现如下

data class Student(var name:String,var age:Int){
    var scorce = 10
    private val habby = "music"
    var subject:String
    init {
        subject = "Kotlin编程权威指南"
    }
    constructor(_name:String):this(_name,21){
        scorce = 90
    }

    override fun toString(): String {
        return "Studnet $name $age " +
                "scorce $scorce,habby $habby" +
                "subject $subject"
    }
}

fun main() {
    val student = Student("LY_C")
	println(student)
		//Studnet LY_C 21 scorce 90 ,habby music subject Kotlin编程权威指南
    val copy = student.copy("CRY")
    println(copy)
    	//Studnet CRY 21 scorce 10 ,habby music subject Kotlin编程权威指南
}

结构声明

data类中自动添加解构声明,后台实现就是声明 component1、component2 等若干个组件函数,让每个函数负责管理你想返回的一个属性数据,Jvm中转为Java代码实现如下

public final class Student {
	...
   @NotNull
   public final String component1() {
      return this.name;
   }

   public final int component2() {
      return this.age;
   }
   ...
}

解构代码使用如下

fun main(){
	...
	var (name,age) = Student("LY_C",21)
    println(name + age)//LY_C21
	...
}

将上方代码从Jvm中转为Java,代码如下

...
public static final void main() {
	Student var2 = new Student("LY_C", 21);
	String name = var2.component1();
	int age = var2.component2();
	String var3 = name + age;
	System.out.println(var3);
}
...

普通Class中的结构声明

利用data类解构声明的原理,使用operator关键字重写componentx方法,代码实现如下

class Player(val x:Int,val y:Int){
    operator fun component1() = x
    operator fun component2() = y
}
fun main() {
    val (x,y) = Player(10,20)
    println(x + y) //30
}

注意

数据类必须有至少带一个参数的主构造函数
数据类主构造函数的参数必须是 val 或 var
数据类不能使用 abstract、open、sealed 和 inner 修饰符

重载运算符

要将内置运算符应用在自定义类身上,必须重写运算符函数,例如使用plus和其关联的+运算符实现属性值的相加时,使用operator关键字重写plus方法,代码实现如下

data class Coordindate2(var x:Int,var y:Int){
    val isInBounds = x > 0 && y > 0
    operator fun plus(other:Coordindate2) =
        Coordindate2(x + other.x,y + other.y)
}
fun main() {
    val c1 = Coordindate2(10,20)
    val c2 = Coordindate2(10,29)
    println(c1 + c2)//Coordindate2(x=20, y=49)
}

常见操作符如下

操作符函数名作用
+plus把一个对象添加到另一个对象里
+=plusAssign把一个对象添加到另一个对象里,然后将结果赋值给第一个对象
==equals如果两个对象相等,则返回 true,否则返回 false
>compareTo如果左边的对象大于右边的对象,则返回 true,否则返回 false
[]get返回集合中指定位置的元素
..rangeTo创建一个 range 对象
incontains如果对象包含在集合里,则返回 true

枚举类

  1. 使用enum关键字声明枚举类,除了Java中的常用方法以外,还可以添加一个主构造函数,每个枚举常量也要传递参数,代码实现如下
enum class Direction {
    EAST,
    WEST,
    SOUTH,
    NORTH
}
...
fun main() {
    println(Direction.EAST)//EAST
}

Java代码实现如下

enum Direction {
    EAST,
    WEST,
    SOUTH,
    NORTH
}
public class Direction1{
    public static void main(String[] args) {
        System.out.println(Direction.EAST);//EAST
    }
}
  1. 添加构造函数,下方代码由于传递的是Coordinate类,并且每一个枚举项本质上都是枚举类自身的实例,所以枚举中的实例都要传递Coordinate对象,代码实现如下
enum class Direction(private val coordinate:Coordinate) {
    EAST(Coordinate(5,-1)),
    WEST(Coordinate(1,0)),
    SOUTH(Coordinate(0,1)),
    NORTH(Coordinate(-1,0));
    fun updateCoordindate(playerinate:Coordinate) =
        Coordinate(playerinate.x + coordinate.x,
            playerinate.y + coordinate.y)
}
data class Coordinate(val x: Int, val y: Int) {
    val isInBounds = x >= 0 && y >= 0
}
fun main() {
    println(Direction.EAST.updateCoordindate(Coordinate(100, 200)))
    	//Coordinate(x=105, y=199)
}

代数数据类型

代数数据类型用来表示一组子类型的闭集,枚举类型相当于简单的ADT(代数数据类型),因为每个枚举常量都为枚举本身的实例,使用枚举类型和其他代数数据类型有一个好处,即编译器会帮你检查代码处理是否有遗漏,因为代数数据类型表示的是一组子类型的闭集,代码实现如下
enum实现如下

enum class LicenseStats{
    UNQUALIFIED,
    LEARNING,
    QUALIFIED
}
class Driver(var stats: LicenseStats){
    fun checkLicense():String {
        return when(stats){
            LicenseStats.QUALIFIED -> "合格"
            LicenseStats.LEARNING -> "在学"
            LicenseStats.UNQUALIFIED -> "不合格"
        }
    }
}
fun main() {
    println(Driver(LicenseStats.LEARNING.checkLicense()))//在学
}

编译器检查代码处理有遗漏,如有遗漏直接爆红
在这里插入图片描述

密封类

对于更复杂的 ADT,你可以使用 Kotlin 的密封类(sealed class)来实现更复杂的定义。密封类可以用来定义一个类似于枚举类的 ADT,但你可以更灵活地控制某个子类型。密封类可以有若干个子类,子类都要继承密封类,这些子类必须和它定义在同一个文件里,代码实现如下

sealed class LicenseStats2{
    object Unqualified :LicenseStats2()
    object Learning :LicenseStats2()
    class Qualified(val licenseId:String):LicenseStats2()
}
class Dricer2(var stats:LicenseStats2){
    fun check():String{
        return when(stats){
            is LicenseStats2.Learning -> "在学"
            is LicenseStats2.Qualified -> "合格 编号为 " +
             	"${(stats as LicenseStats2.Qualified).licenseId}"
            is LicenseStats2.Unqualified -> "不合格"
            else -> {
                "Error"
            }
        }
    }
}
fun main() {
    println(Dricer2(LicenseStats2.Qualified("3114541245")).check())
    	//合格 编号为3114541245
}
  • 11
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LuKey_C

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值