在kotlin中有一些知识点看起来好像挺简单的,好像我们使用着确实也没有问题?但是这不意味我们懂了这些只是点,我们只是知道了怎么用,要说懂,就需要我们去了解它们的本质。今天我们就介绍kotlin中,一些我们看似懂了,却又没有完全懂的知识点。
首先第一个知识点是class,首先来看一个java类。
class MyJavaClass {
static String staticMember; //静态变量
private String word;
public MyJavaClass(){} //无参构造函数
public MyJavaClass(String word){ //一个参数的构造函数
this.word = word;
}
public MyJavaClass(String word,String staticMemberParam){//两个参数的构造函数
this.word = word;
staticMember = staticMemberParam; //静态变量可以在构造函数中使用
}
public void sayWord(){//普通成员方法
System.out.println("hello i am java class i can say "+word);
}
public String getWord() { //get方法
return word;
}
public void setWord(String word) {//set方法
this.word = word;
}
static void printlnStatic(){//静态方法
System.out.println("hello "+staticMember);
}
}
假如你通过java to kotlin的工具去转换得到的结果肯定是错的。接下来,我们来一步步去讲解我们今天的知识点。
首先是定义一个成员word
var word: String? = null
fun getWord(): String? { //报错
return word
}
fun setWord(word: String?) { //报错
this.word = word
}
如果像java中一样,在kotlin中去定义成员变量,并且给它设置setter getter方法,那么编译器就会提示我们出错了。what???
这么简单的一个写法都错?什么lj语言,老子不学了。(假的,捡起课本)。
看看提示的错误是什么The following declarations have the same JVM signature:
也就是说,定义的方法与另一个方法拥有相同的jvm签名
了。也就是说,有另外的一个方法也是fun getWord()。其实在kotlin中,声明成员变量的时候,会默认实现getter与setter方法。所以只需要完成一个变量的声明即可。如下:
var word: String? = null
是不是很简单。
在kotlin中,使用构造函数需要用到关键字constructor,而且构造函数,还区分主构造函数和次构造函数
主构造函数是类头的一部分:它跟在类名(与可选的类型参数)后,并且主构造函数不能包含任何的代码。
//这就是一个简单的主构造函数constructor(),注意它并没有函数体,那要它有什么用?别急,后面会讲到的
class MyKotlinClass constructor() {
var word: String? = null
}
类也可以声明前缀有 constructor的次构造函数:
如果类有一个主构造函数,每个次构造函数需要委托给主构造函数, 可以直接委托或者通过别的次构造函数间接委托。委托到同一个类的另一个构造函数用 this 关键字即可,如下:
class MyKotlinClass constructor() {
var word: String? = null
constructor(word: String?):this() {
this.word = word
}
}
回到上面的问题,主构造函数没有函数体,那它有什么用?在kotlin中,有成员变量的声明,还有init{}代码块的初始化。这一部分其实会成为主构造器的函数体。 什么意思,还是通过一个例子来讲解一下:
class MyKotlinClass constructor(word:String?) {
var mWord: String? = word
init{
println(mWord)
}
constructor(word: String?,word2:String):this(word) {
println(word2)
}
}
看一下上面的这个例子,其实主构造函数的函数体相当于下面这部分
var mWord: String? = word
init{
println(mWord)
}
委托给主构造函数会作为次构造函数的第一条语句,因此所有初始化块与属性初始化器中的代码都会在次构造函数体之前执行。即使该类没有主构造函数,这种委托仍会隐式发生,并且仍会执行初始化块。 这句话对判断一些代码块执行顺序很有用。 还有就是主构造函数中的参数,只能在init代码块或者声明成员变量的时候中使用,不能在其他方法体使用,如果我们想要它在其他方法体使用,应该在前面加上val 或者 var关键字,这就是相当于声明了一个成员变量了。 如下
class MyKotlinClass constructor(var word:String?) {
init{
println(word)
}
constructor(word: String?,word2:String):this(word) {
println(word2)
}
fun test(){
println(word)
}
}
以上就是主构造函数与次构造函数的区别。如果有多个构造函数,那么怎么选择哪一个作为主构造函数呢?选择那一个用的最多的构造函数作为主构造函数即可。
回到上面讲解的例子,如果要在kotlin中去通过static关键字声明静态变量是做不到的,因为kotlin中没有static关键字了。那么如果需要的话,要怎么声明呢?那么这时候就需要伴生对象出场了。
在kotlin中允许使用complain object来创建伴生对象。比如上面我要声明一个staticMember的静态变量,那么我应该这么声明:
companion object{
var staticMember: String? = null
}
反编译成java代码之后,如下
public final class MyKotlinClass {
@Nullable
private static String staticMember;
@NotNull
public static final MyKotlinClass.Companion Companion = new MyKotlinClass.Companion((DefaultConstructorMarker)null);
public static final class Companion {
@Nullable
public final String getStaticMember() {
return MyKotlinClass.staticMember;
}
public final void setStaticMember(@Nullable String var1) {
MyKotlinClass.staticMember = var1;
}
private Companion() {
}
// $FF: synthetic method
public Companion(DefaultConstructorMarker $constructor_marker) {
this();
}
}
}
说明这里其实是实现了一个静态内部类,这个静态成员变量是MyKotlinClass这个类的静态成员变量。这个写法的话,在java中调用静态成员变量和在kotlin中调用的写法是不一样的。
//kotlin中调用
MyKotlinClass.staticMember
//java中调用
MyKotlinClass.Companion.getStaticMember()
这期内容比较基础,主要是想告诉大家遇到一些不懂得知识点,我们可以通过反编译成java代码的方式去看。