Kotlin学习笔记基础篇之类和构造函数

基础类型

在Java中有基本类型和引用类型之分,但是在Kotlin中一切都是对象

// Java
short
int 
long
char
float
double
Short
Integer
// ...
// Kotlin
Double
Float 
Long 
Int 
Short
Char
Boolean

类型转换

在Kotlin中为了兼容Java,Kotlin中的Double、Int等基本类型在编译后会转化为Java的基本数据类型double、int等,但是Kotlin的Double?、Int?等可空对象将会转化为Java的引用类型Double、Integer。

// Kotlin必须显示转换 1. 可读性强 2. 一切都是透明的可控制的
fun main(){
    val intValue = 666
    val longValue : Long = intValue.toLong()

    // Char类型
    val c = 'A'
    val code: Int = c.toInt()
    println(code) // 65
}

/** 反编译后的代码
 public final class Simple08Kt {
   public static final void main() {
      int intValue = 666;
      long longValue = (long)intValue;
      char c = 65;
      System.out.println(c);
   }

   // $FF: synthetic method
   public static void main(String[] var0) {
      main();
   }
}
 */

类和构造函数

在学习类和构造函数时我们可以将Kotlin和Java对比起来学习这样学习效率会更高,Java中一般一个文件定义一个类,类名与文件名一致,如果同一个文件中有多个类,那么只能有一个类时public。我们都知道Java是一门面向对象语言,在面向对象设计中需要考虑一个基本问题:“如何把变动的事物与保持不变的事物区分开来”。为了解决这一问题,Java提供了访问权限修饰词,为程序员指明被修饰关键词,哪些是可以访问的哪些是不能访问的。访问权限控制的等级,从最大权限到最小权限一次为:publicprotected、默认(没有关键词)、private

public protected 默认 private
当前类
子类 ×
同一个包下 × ×
外部包或外部模块 × × ×

总结:被public修饰的关键词任意位置都可以访问;被protected修饰的关键词只有当前类、⼦类、同⼀个包中可以访问,外部包或者外部模块⽆法访问;没有修饰词修饰的关键词,只有当前类、⼦类、同⼀个包中可以访问,外部包或者外部模块⽆法访问;被private修饰的关键词,当前类可以访问其他位置都⽆法访问。

对象的创建

Animal a1 = new Animal()

当我们用上面Java语句创建一个对象时会发生什么。

首先Jvm虚拟机遇到new指令时,会在常量池中定位到一个类的符号引用,并且检查这个符号引用所代表的类是否被加载,如果没有被加载就需要进行类加载过程,类加载器将当前这个类的字节码文件加载到内存中。

接下来虚拟机为该新生对象分配内存,虚拟机会将分配的内存空间都初始化为零值(除了对象头)。我们都知道如果类的某个成员是基本数据类型,即使没有进行初始化,Java也会确保它获得一个默认值(不适用于局部变量,即并非某个类的字段),便是虚拟机这时候进行初始化的。

然后,虚拟机对对象进行必要的设置,例如这个对象是哪个类的实例、如何才能找到类的元数据信息、对象的哈希码、对象的GC分代年龄等信息。这些信息存放在对象的对象头(Object Header)之中。

最后创建的对象的地址会放在操作数栈中 的某个地址中,在当前线程栈中的⽅法栈帧的局部变量区域申请内存空间给a1,从操作数栈中弹出顶部操作数的地址赋值给a1

构造函数

为什么要有构造函数?初始化和清理是涉及安全的两个问题,C++引入了构造器的概念,这是一个在创建对象时被自动调用的特殊方法。Java中也采用的构造器,使用构造器能确保初始化每个对象,此外Java还提供了"垃圾回收器",对于不在使用的内存资源,垃圾回收器能自动将其释放。

class Person {
    Person(){
        System.out.print("Person ");
    }
}

public class Sample01 {
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            new Person();
        }
    }
}
/** Output:
 * Person Person Person Person Person Person Person Person Person Person
 */

上面是一个带有构造器的简单类,在Java中,构造器的名称必须与类名完全相同,没有参数的构造函数被称为默认构造函数,如果在定义类的时候没有写构造函数,编译器在编译的时候会自动生成无参构造函数。当一个构造参数无法满足需求时,还可以重载多个不同参数构造函数。

// 1. 主构造函数
//创建⼀个没有主体的类
class Person
//显示指定构造⽅法
class Person2 constructor()
//主构造函数需要传递⼀个字符串对象 constructor不能省略
class Person3 constructor(var name:String){
    init {
        println("First initializer block that prints ${name}")
    }
}
//有修饰符限定构造函数权限时 constructor不能省略
class Person4 private constructor()
//如果有⽗类 必须直接调⽤⽗类的构造函数
open class Father   // open 关键词,kotlin中的类默认是private修饰的无法被继承,如需继承则添加open关键字在类前面
class Person5 : Father()
//如果⽗类有参数 ⼦类必须提供相应有参的构造函数
open class Father2 constructor(name: String)
class Person6 constructor(name: String) : Father2(name)

// 2. 此构造函数
// 注意:a.次构造函数必须直接调⽤主构造函数
//      b.如果有⽗类,必须调⽤⽗类的构造函数
//次构造函数必须继承主构造函数
class Person7(name: String) {
    constructor(name: String, age: Int):this(name)
}

open class Father3 constructor(name: String)    
class Person8 constructor(name: String) : Father3(name){
    constructor(name: String, age: Int):this(name)
}

上面是Kotlin中带有构造函数的实例,Kotlin 中的一个类可以有一个主构造函数以及一个或多个次构造函数。主构造函数可以用关键字constructor显示的指定,也可以跟在类名(与可选类型参数)后。主构造函数不能包含任何的代码。初始化的代码可以放到以 init{} 关键字作为前缀的初始化块(initializer blocks)中。

如果类有一个主构造函数,每个次构造函数需要委托给主构造函数,可以直接委托或者通过别的次构造函数间接委托。委托到同一个类的另一个构造函数用 this() 关键字即可。

实践应用

如何巧妙使⽤private来私有化构造⽅法,给外部提供⼀个单例对象(整个程序运⾏中这个类只有⼀个对象)

  1. 首先私有化构造函数,外部⽆法创建这个类的实例
  2. 提供⼀个静态的成员属性,这个静态变量只会初始化⼀次
  3. 给外部提供⼀个静态⽅法,外部可以通过这个方法获取该对象,但是需要注意:我们这⾥只是一个简单的单例没考虑内存消耗和线程安全
  4. 最后外部获取这个对象
class Person9 private constructor(){
    companion object{
        private val defaultInstance = Person9()
        fun getInstance():Person9{
            return defaultInstance
        }
    }
}
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容