跟郭神学Kotlin(第三行学习笔记02)
作者:互联网
郭神在开头解释了面向对象的含义,我觉得最经典的一句话就够了。
万物皆对象
类与对象
Kotlin 中 定义一个类也是用 Class 关键字
//一个类的空实现
class Person {
}
再申明一些 变量 和 函数
class Person {
var name = ""//注意这里定义是var 否则后边就无法赋值了
var age = 0//Kotlin变量必须初始化赋值 否则无法通过编译
fun eat() {
println(name + "正在吃茄子。他今年" + age + "岁了!")
println("${name}正在吃茄子。他今年${age}岁了!")//也可以用这种写法
}
}
然后我们来实例化 一个类
fun testClass() {
val person = Person()
person.age = 6
person.name = "臭弟弟"
person.eat()
}
可以看到 和Java 类似 只是 没有了 new,因为Kotlin本着最简化的设计原则 即使没有 new 也能表达 我要new 一个对象的意图。
继承与构造函数
申明一个 Student 类 继承上面的 Person
不过 首先需要将 Person 变得可继承 这一点和Java中有点不一样(其实是我们用法习惯不规范——如果一个类不是专门为继承而设计的,那么它应该加上final禁止它可以被继承)
open 关键字
open class Person {
var name = ""
var age = 0
fun eat() {
println(name + "正在吃奥利给。他今年" + age + "岁了!")
println("${name}正在吃奥利给。他今年${age}岁了!")
}
}
加 open 的作用 就是告诉编译器,我这个类就是专门为了继承而申明的。
然后 在 Student中 使用 : Person() 即可 这里的 :就等于 Java 中的 extends 关键字。
class Student : Person() {
var sno = ""
var grade = 0
}
主构造函数
每个类默认都会有一个不带参数的主构造函数,也可以显示指定参数。
class Student : Person() {
}
主构造函数的特点就是没有函数体,直接定义在类名后即可。如下:
class Student(val sno:String,val grade:Int) : Person() {
var sno = ""
var grade = 0
}
//指定一个Student
val student = Student("2008AD36", 8)
init 结构体
class Student(val sno: String, val grade:Int) : Person() {
init {
println("sno is $sno")
println("grade is $grade")
}
}
如果想在主构造函数里写逻辑 可以用使用 init 结构体
Java继承特性的一个规定:子类中的构造函数必须调用父类中的构造函数,Kotlin也一样
所以说
Student : Person() 的 这个括号() 其实就是Person这个父类的构造函数
如果将父类申明主构造函数
open class Person(val name:String,val age:Int) {
}
那么子类就会报错,此时子类应该这样写
class Student(val sno: String, val grade:Int,name: String,age:Int) : Person(name,age) {
}
//其中 name: String,age:Int 就是父类主构造函数中的参数
这里 需要值得注意的是:Student子类主构造函数中增加的name和age不能再将它们申明成 val 。因为在主构造函数中申明为 val/var 的参数将自动转化为该类的字段,这会导致和Person父类中的 name和age冲突。因此 这里 不需要加任何关键字 让它的作用域仅限主构造函数即可。(虽然很长 但是感觉很重要 还是要说一下)
val student = Student("2021", 8,"臭弟弟",6)
任何一个类只能有一个主构造函数和多个次构造函数。
次构造函数
Kotlin规定,当一个类既有主构造又有次构造时,所有次构造函数都必须调用主构造函数(包括间接调用)。
constructor关键字
class Student(val sno: String, val grade: Int, name: String, age: Int) : Person(name, age) {
constructor(name: String, age: Int) : this("e", 0, "abc", 0) {
}
constructor() : this("dd", 0) {
}
}
可以看到,最前边是 constructor关键字 来定义,最后跟了个 this关键字 来调用主构造函数。这时,我们就可以通过次构造函数来实例化 Student类 。
val student0 = Student("2021", 8, "臭弟弟", 6)
val student1 = Student("2019", 24)
val student2 = Student()
特殊情况:类中只有次构造,没有主要构造
当一个类没有显式地定义构造函数且定义了次构造函数时,它就没有主构造函数。
class Student : Person {
constructor(name: String, age: Int) : super(name, age) {
}
}
这里,Student类后边没有显式地定义主构造函数,同时又定义了次构造函数,所以这里Student类没有主构造函数。所以Person类后边就无需加括号了。再由于没有主构造函数,所以次构造函数可以直接调用父类的构造函数,所以这里 this 变为了 super
接口
Kotlin中的接口几乎和Java一致。Kotlin也是单继承,多接口。我们可以在接口中定义一系列抽象行为,然后由具体的类去实现。
interface Study {
fun readBook()
fun doHomework()
}
在上面的 Student类 中实现我们的 Study接口
class Student(name: String, age: Int) : Person(name, age), Study {
override fun readBook() {
println(name + "在读书")
}
override fun doHomework() {
println(name + "在做作业")
}
}
对比Java的继承(extends)和接口实现(implements)来看,kotlin的( : )和( , )更加简化。
面向接口编程/多态
fun main(){
val student = Student("茄子", 99)
doStudy(student)
}
fun doStudy(study: Study){
study.doHomework()
study.readBook()
}
可以看到,doStudy()接收一个Study类型的参数,由于Student类实现了Study接口,因此Student类的实例是可以传递给doStudy()函数的。接下来调用Study接口里的函数,这种就叫作 面向接口编程 ,也可以成为 多态
接口函数的默认实现
Kotlin和JDK1.8都支持 对接口中定义的函数进行默认实现。
interface Study {
fun readBook()
fun doHomework(){
println("我TM在写作业")
}
}
同样是Study接口,我们给doHomework函数加上了函数体。
如果接口中的一个函数拥有函数体,这个函数体中的内容就是它的默认实现。现在当一个类去实现Study接口时,只会强制要求实现readBook()函数,而doHomework()函数则可以自由选择实现或者不实现,不实现时就会自动使用默认的实现逻辑。
可见性修饰符
Java有
public,private, protected, default(默认)
而kotlin有
public(默认),private, protected, internal
Java和Kotlin修饰符的异同
- private 都是表示 内部可见。
- public 都是表示 全部可见。
- Java 中 default 是默认修饰符 ,Kotlin中 public 是默认修饰符
- Java 中 protected 表示当前类,子类,同一包下的类可见,而kotlin中表示只对当前类和子类可见。
- Kotlin 没有同包下的概念,引入了同一个模块的概念,用 internal 修饰
对照表
修饰符 | Java | kotlin |
---|---|---|
public | 所有类可见 | 所有类可见(默认) |
private | 当前类可见 | 当前类可见 |
protected | 当前类,子类,同一包路径下的类可见 | 当前类,子类可见 |
default | 同一包路径下的类可见(默认) | 无 |
internal | 无 | 同一模块中的类可见 |
数据类和单例类
数据类
data 关键字
/**
* 数据类 演示
*/
data class Cellphone(val brand: String, val price: Double) {
}
当一个类在前面申明了 data 关键字时,就表示这个类是一个数据类,Kotlin会根据主构造函数中的参数自动帮你将equals()、hashCode()、**toString()**等方法自动生成。
验证一下打印
fun testCellphone(){
val cellphone1 = Cellphone("Realme",2999.99)
val cellphone2 = Cellphone("Realme",2999.99)
println(cellphone1)
println("1 equals 2 is : "+(cellphone1==cellphone2))
}
//输出了
Cellphone(brand=HuaWei, price=2999.99)
1 equals 2 is : true
//然后去掉Cellphone前面的data关键字再次输出
info.itloser.line3code.Cellphone@27c170f0
1 equals 2 is : false
可以看到 有data时 输出的是我们想要的值,去掉data时 输出的是整个对象。
单例类
Kotlin中特有的功能 单例类
在Java中我们一般都称为单例模式
/**
* 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("This is Java singleton test");
}
}
调用其中的方法
Singleton singleton = Singleton.getInstance();
singleton.singletonTest();
Kotlin的单例类 更简单 只需要
在创建Kotlin类时 选择 类型为Object 即可
/**
* 一个Kotlin的单例类
*/
object Singleton {
fun singletonTest(){
println("This is Kotlin singleton test");
}
}
可以看到,Kotlin的单例类是简单了很多,无需什么getInstance等方法
当然调用也很简单
Singleton.singletonTest()
标签:02,name,val,第三行,Kotlin,age,Person,Student,构造函数 来源: https://blog.csdn.net/qq_38376757/article/details/114004390