Kotlin系列二:面向对象编程(类与对象),Android程序员秋招三面蚂蚁金服

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip204888 (备注Android)
img

正文

Kotlin规定,当一个类既有主构造函数又有次构造函数时,所有的次构造函数都必须调用主构造函数(包括间接调用)。这里我通过一个具体的例子就能简单阐明,代码如下:

class Student(val sno: String, val grade: Int, name: String, age: Int) :

Person(name, age) {

constructor(name: String, age: Int) : this(“”, 0, name, age) {

}

constructor() : this(“”, 0) {

}

}

次构造函数是通过constructor关键字来定义的,这里我们定义了两个次构造函数:第一个次构造函数接收name和age参数,然后它又通过this关键字调用了主构造函数,并将sno和grade这两个参数赋值成初始值;第二个次构造函数不接收任何参数,它通过this关键字调用了我们刚才定义的第一个次构造函数,并将name和age参数也赋值成初始值,由于第二个次构造函数间接调用了主构造函数,因此这仍然是合法的。

那么现在我们就拥有了3种方式来对Student类进行实体化,分别是通过不带参数的构造函数、通过带两个参数的构造函数和通过带4个参数的构造函数,对应代码如下所示:

val student1 = Student()

val student2 = Student(“Jack”, 19)

val student3 = Student(“a123”, 5, “Jack”, 19)

这样我们就将次构造函数的用法掌握得差不多了,但是到目前为止,继承时的括号问题还没有进一步延伸,暂时和之前学过的场景是一样的。

那么接下来我们就再来看一种非常特殊的情况:类中只有次构造函数,没有主构造函数。这种情况真的十分少见,但在Kotlin中是允许的。当一个类没有显式地定义主构造函数且定义了次构造函数时,它就是没有主构造函数的。我们结合代码来看一下:

class Student : Person {

constructor(name: String, age: Int) : super(name, age) {

}

}

注意这里的代码变化,首先Student类的后面没有显式地定义主构造函数,同时又因为定义了次构造函数,所以现在Student类是没有主构造函数的。那么既然没有主构造函数,继承Person类的时候也就不需要再加上括号了。其实原因就是这么简单,只是很多人在刚开始学习Kotlin的时候没能理解这对括号的意义和规则,因此总感觉继承的写法有时候要加上括号,有时候又不要加,搞得晕头转向的,而在你真正理解了规则之后,就会发现其实还是很好懂的。

另外,由于没有主构造函数,次构造函数只能直接调用父类的构造函数,上述代码也是将this关键字换成了super关键字,这部分就很好理解了,和Java比较像。

五 接口

====

Kotlin中的接口部分和Java几乎是完全一致的。接口是用于实现多态编程的重要组成部分。

然后在Study接口中添加几个学习相关的函数,注意接口中的函数不要求有函数体,代码如下所示:

interface Study {

fun readBooks()

fun doHomework()

}

接下来就可以让Student类去实现Study接口了,这里我将Student类原有的代码调整了一下,以突出继承父类和实现接口的区别:

class Student(name: String, age: Int) : Person(name, age), Study {

override fun readBooks() {

println(name + " is reading.")

}

override fun doHomework() {

println(name + " is doing homework.")

}

}

Java中继承使用的关键字是extends,实现接口使用的关键字是implements,而Kotlin中统一使用冒号,中间用逗号进行分隔;

上述代码表示Student类继承了Person类,同时还实现了Study接口,另外接口的后面不用加上括号,因为它没有构造函数可以去调用;

Study接口中定义了readBooks()和doHomework()这两个待实现函数,因此Student类必须实现这两个函数。Kotlin中使用override关键字来重写父类或者实现接口中的函数,这里我们只是简单地在实现的函数中打印了一行日志。

现在我们可以在main()函数中编写如下代码来调用这两个接口中的函数:

fun main() {

val student = Student(“Jack”, 19)

doStudy(student)

}

fun doStudy(study: Study) {

study.readBooks()

study.doHomework()

}

这里为了演示一下多态编程的特性,故意将代码写得复杂了一点:

首先创建了一个Student类的实例,本来是可以直接调用该实例的readBooks()和doHomework()函数的,但是没有这么做,而是将它传入到了doStudy()函数中。doStudy()函数接收一个Study类型的参数,由于Student类实现了Study接口,因此Student类的实例是可以传递给doStudy()函数的,接下来我们调用了Study接口的readBooks()和doHomework()函数,这种就叫作面向接口编程,也可以称为多态。

这样我们就将Kotlin中接口的用法基本学完了,是不是很简单?不过为了让接口的功能更加灵活,Kotlin还增加了一个额外的功能:允许对接口中定义的函数进行默认实现。其实Java在JDK 1.8之后也开始支持这个功能了,因此总体来说,Kotlin和Java在接口方面的功能仍然是一模一样的。

下面我们学习一下如何对接口中的函数进行默认实现,修改Study接口中的代码,如下所示:

interface Study {

fun readBooks()

fun doHomework() {

println(“do homework default implementation.”)

}

}

可以看到,我们给doHomework()函数加上了函数体,并且在里面打印了一行日志。如果接口中的一个函数拥有了函数体,这个函数体中的内容就是它的默认实现。现在当一个类去实现Study接口时,只会强制要求实现readBooks()函数,而doHomework()函数则可以自由选择实现或者不实现,不实现时就会自动使用默认的实现逻辑。

现在回到Student类当中,你会发现如果我们删除了doHomework()函数,代码是不会提示错误的,而删除readBooks()函数则不行。

六 数据类与单例类

=========

6.1 数据类


在一个规范的系统架构中,数据类通常占据着非常重要的角色,它们用于将服务器端或数据库中的数据映射到内存中,为编程逻辑提供数据模型的支持。或许你听说过MVC、MVP、MVVM之类的架构模式,不管是哪一种架构模式,其中的M指的就是数据类。

数据类通常需要重写equals()、hashCode()、toString()这几个方法。其中,equals()方法用于判断两个数据类是否相等。hashCode()方法作为equals()的配套方法,也需要一起重写,否则会导致HashMap、HashSet等hash相关的系统类无法正常工作。toString()方法用于提供更清晰的输入日志,否则一个数据类默认打印出来的就是一行内存地址。

这里我们新构建一个手机数据类,字段就简单一点,只有品牌和价格这两个字段。如果使用Java来实现这样一个数据类,代码就需要这样写:

public class Cellphone {

String brand;

double price;

public Cellphone(String brand, double price) {

this.brand = brand;

this.price = price;

}

@Override

public boolean equals(Object obj) {

if (obj instanceof Cellphone) {

Cellphone other = (Cellphone) obj;

return other.brand.equals(brand) && other.price == price;

}

return false;

}

@Override

public int hashCode() {

return brand.hashCode() + (int) price;

}

@Override

public String toString() {

return “Cellphone(brand=” + brand + “, price=” + price + “)”;

}

}

看上去挺复杂的吧?关键是这些代码还是一些没有实际逻辑意义的代码,只是为了让它拥有数据类的功能而已。而同样的功能使用Kotlin来实现就会变得极其简单,右击com.example. helloworld包→New→Kotlin File/Class,在弹出的对话框中输入“Cellphone”,创建类型选择“Class”。然后在创建的类中编写如下代码:

data class Cellphone(val brand: String, val price: Double)

你没看错,只需要一行代码就可以实现了!神奇的地方就在于data这个关键字,当在一个类前面声明了data关键字时,就表明你希望这个类是一个数据类,Kotlin会根据主构造函数中的参数帮你将equals()、hashCode()、toString()等固定且无实际逻辑意义的方法自动生成,从而大大减少了开发的工作量。

另外,当一个类中没有任何代码时,还可以将尾部的大括号省略。

下面我们来测试一下这个数据类,在main()函数中编写如下代码:

fun main() {

val cellphone1 = Cellphone(“Samsung”, 1299.99)

val cellphone2 = Cellphone(“Samsung”, 1299.99)

println(cellphone1)

println("cellphone1 equals cellphone2 " + (cellphone1 == cellphone2))

}

这里我们创建了两个Cellphone对象,首先直接将第一个对象打印出来,然后判断这两个对象是否相等。

6.2 单例类


Java的常见写法:

public class Singleton {

private static Singleton instance;

private Singleton() {}

public synchronized static Singleton getInstance() {

if (instance == null) {

instance = new Singleton();

}

return instance;

}

public void singletonTest() {

System.out.println(“singletonTest is called.”);

}

}

调用:

Singleton singleton = Singleton.getInstance();

singleton.singletonTest();

虽然Java中的单例实现并不复杂,但是Kotlin明显做得更好,它同样是将一些固定的、重复的逻辑实现隐藏了起来,只暴露给我们最简单方便的用法。

在Kotlin中创建一个单例类的方式极其简单,只需要将class关键字改成object关键字即可。现在我们尝试创建一个Kotlin版的Singleton单例类,右击com.example.helloworld包→New→Kotlin File/Class,在弹出的对话框中输入“Singleton”,创建类型选择“Object”,点击“OK”完成创建,初始代码如下所示:

object Singleton {

}

现在Singleton就已经是一个单例类了,我们可以直接在这个类中编写需要的函数,比如加入一个singletonTest()函数:

object Singleton {

fun singletonTest() {

println(“singletonTest is called.”)

}

}

可以看到,在Kotlin中我们不需要私有化构造函数,也不需要提供getInstance()这样的静态方法,只需要把class关键字改成object关键字,一个单例类就创建完成了。而调用单例类中的函数也很简单,比较类似于Java中静态方法的调用方式:

Singleton.singletonTest()

这种写法虽然看上去像是静态方法的调用,但其实Kotlin在背后自动帮我们创建了一个Singleton类的实例,并且保证全局只会存在一个Singleton实例。

七 密封类

=====

密封类用来表示受限的类继承结构:当一个值为有限几种的类型、而不能有任何其他类型;

在某种意义上,他们是枚举类的扩展:枚举类型的值集合也是受限的,但每个枚举常量只存在一个实例,而密封类的一个子类可以有可包含状态的多个实例。

要声明一个密封类,需要在类名前面添加 sealed 修饰符。虽然密封类也可以有子类,但是所有子类都必须在与密封类自身相同的文件中声明。密封类及其所有子类只能定义在同一个文件的顶层位置,不能嵌套在其他类中。但扩展密封类子类的类(间接继承者)可以放在任何位置,而无需在同一个文件中。

sealed class Expr

data class Const(val number: Double) : Expr()

data class Sum(val e1: Expr, val e2: Expr) : Expr()

object NotANumber : Expr()

一个密封类是自身抽象的,它不能直接实例化并可以有抽象(abstract)成员;

密封类不允许有非-private 构造函数(其构造函数默认为 private);

使用密封类的关键好处在于使用when表达式的时候,如果能够验证语句覆盖了所有情况,就不需要为该语句再添加一个 else 子句了。当然,这只有当你用 when 作为表达式(使用结果)而不是作为语句时才有用。

fun eval(expr: Expr): Double = when(expr) {

is Const -> expr.number

is Sum -> eval(expr.e1) + eval(expr.e2)

NotANumber -> Double.NaN

// 不再需要 else 子句,因为我们已经覆盖了所有的情况

}

八 嵌套类与内部类

=========

嵌套类:类可以嵌套在其他类中:

class Outer {

private val bar: Int = 1

class Nested {

fun foo() = 2

}

}

val demo = Outer.Nested().foo() // == 2

最后

那我们该怎么做才能做到年薪60万+呢,对于程序员来说,只有不断学习,不断提升自己的实力。我之前有篇文章提到过,感兴趣的可以看看,到底要学习哪些知识才能达到年薪60万+。

通过职友集数据可以查看,以北京 Android 相关岗位为例,其中 【20k-30k】 薪酬的 Android 工程师,占到了整体从业者的 30.8%!

北京 Android 工程师「工资收入水平 」

今天重点内容是怎么去学,怎么提高自己的技术。

1.合理安排时间

2.找对好的系统的学习资料

3.有老师带,可以随时解决问题

4.有明确的学习路线

当然图中有什么需要补充的或者是需要改善的,可以在评论区写下来,一起交流学习。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注Android)
img

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

知识才能达到年薪60万+。

通过职友集数据可以查看,以北京 Android 相关岗位为例,其中 【20k-30k】 薪酬的 Android 工程师,占到了整体从业者的 30.8%!

北京 Android 工程师「工资收入水平 」

[外链图片转存中…(img-xS81qVoU-1713562051116)]

今天重点内容是怎么去学,怎么提高自己的技术。

1.合理安排时间

2.找对好的系统的学习资料

3.有老师带,可以随时解决问题

4.有明确的学习路线

当然图中有什么需要补充的或者是需要改善的,可以在评论区写下来,一起交流学习。

[外链图片转存中…(img-2pql6lle-1713562051116)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注Android)
[外链图片转存中…(img-swP6bG8a-1713562051116)]

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值