從Java到Kotlin(七)

陳子豪發表於2018-03-02

反射和註解

目錄

  • 1.反射
    1.1類引用
    1.2函式引用
    1.3屬性引用
  • 2.註解
    2.1宣告註解
    2.2建構函式

1.反射

反射機制是在執行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個物件,都能夠呼叫它的任意一個方法和屬性,這種動態獲取的資訊以及動態呼叫物件的方法的功能稱為java語言的反射機制。 Kotlin中使用反射功能所需的執行時元件作為單獨的 JAR 檔案(kotlin-reflect.jar)分發。這樣做是為了減少不使用反射功能的應用程式所需的執行時庫的大小。如果用Android Studio執行Kotlin專案,一般會在建立工程時,自動引入(kotlin-reflect.jar)

1.1類引用

  • Java程式碼
//方式一
Class<?> clazz = User.class;
//方式二
Class<?> clazz = Class.forName("包名.User");
複製程式碼
  • Kotlin程式碼
//如果User是Kotlin的類
 var user = User::class
//如果User是Java的類
 var user = User::class.java
複製程式碼

在Kotlin中,用類名+兩個冒號::+class(如果是java類要在後面加上.java)表示獲取這個類的物件。

1.2函式引用

  • Java程式碼
public class User {
    private String userName;

    public User(String userName) {
        super();
        this.userName = userName;
    }

    public void printUserName() {
        System.out.println(userName);
    }
}

//獲取User物件
Class<?> clazz = Class.forName("com.demo.czh.myapplication.User");
//獲取帶String引數的public建構函式
Constructor c=clazz.getDeclaredConstructor(String.class);
//建立User物件的例項
User user = (User) c.newInstance("Czh");
//根據方法名"printUserName"獲取 method 物件
Method method = clazz.getDeclaredMethod("printUserName");
//通過 method 呼叫 invoke()方法,呼叫User裡的 printUserName
method.invoke(user);
複製程式碼

執行程式碼,得到結果:

從Java到Kotlin(七)

  • Kotlin程式碼
class User(var userName: String) {
    fun printUserName() {
        println(userName)
    }
}

//方式一
//獲取printUserName函式物件
var p = User::printUserName
//呼叫invoke()函式執行printUserName函式
p.invoke(User("Czh"))

//方式二
//利用Java反射機制呼叫getMethod()方法,並指定方法名字"printUserName"
var method = User::class.java.getMethod("printUserName")
//呼叫invoke()函式
method.invoke(User("Czh"))
複製程式碼

執行程式碼,得到結果:

從Java到Kotlin(七)

在Kotlin中,可以用類名+兩個冒號::+函式名直接獲取這個函式的物件;或者利用Java反射機制呼叫getMethod()方法來獲取函式的物件。

1.3屬性引用

  • Java程式碼
public class User {
    public String userName;
}

//獲取User物件
Class<?> clazz = Class.forName("com.demo.czh.myapplication.User");
//建立User物件的例項
User user = (User) clazz.newInstance();
//獲取Field物件並指定屬性名為"userName"
Field field = clazz.getField("userName");
//通過set()方法給userName賦值
field.set(user, "Czh");
//通過get()方法獲取userName的值
System.out.println(field.get(user));
複製程式碼

執行程式碼,得到結果:

從Java到Kotlin(七)

  • Kotlin程式碼
class User {
    var userName: String = "Czh"
        get() = field
        set(value) {
            field = value
        }
}

//方式一
var user = User()
//獲取屬性物件
var userName = User::userName
println(userName.get(user))
//設定屬性值
userName.set(user, "James")
//獲取屬性值
println(userName.get(user))

//方式二
//利用Java反射機制獲取getUserName方法
var getName = User::class.java.getMethod("getUserName")
//利用Java反射機制獲取setUserName方法
var setName = User::class.java.getMethod("setUserName", java.lang.String().javaClass)
//設定屬性值
setName.invoke(user, "Harden")
//獲取屬性值
println(getName.invoke(user))
複製程式碼

執行程式碼,得到結果:

從Java到Kotlin(七)
在Kotlin中,可以用類名+兩個冒號::+屬性名直接獲取屬性物件;或者通過Java反射機制獲取屬性的get/set方法來獲取或修改屬性值。


2.註解

2.1註解宣告

Java宣告註解

public @interface MyAnnotation {
}
複製程式碼

Kotlin宣告註解

annotation class MyAnnotation
複製程式碼

註解的附加屬性可以通過用元註解標註註解類來指定:

  • @Target 指定可以用該註解標註的元素的可能的型別(類、函式、屬性、表示式等);
  • @Retention 指定該註解是否儲存在編譯後的 class 檔案中,以及它在執行時能否通過反射可見 (預設都是 true);
  • @Repeatable 允許在單個元素上多次使用相同的該註解;
  • @MustBeDocumented 指定該註解是公有 API 的一部分,並且應該包含在生成的 API 文件中顯示的類或方法的簽名中。

Java新增元註解

@Target(ElementType.METHOD)//表示可以在方法中使用
@Retention(RetentionPolicy.RUNTIME)//表示執行時註解
public @interface MyAnnotation {
}
複製程式碼

Kotlin新增元註解

@Target(AnnotationTarget.FUNCTION)//表示可以在函式中使用
@Retention(AnnotationRetention.RUNTIME)//表示執行時註解
annotation class MyAnnotation
複製程式碼

2.2建構函式

註解類可以帶有建構函式

  • Kotlin程式碼
annotation class MyAnnotation(val value: Int)

//使用
@MyAnnotation(1)
class Foo {
}
複製程式碼
  • Java程式碼
public @interface MyAnnotation {
    int value();
}

//使用
@MyAnnotation(1)
public class Foo {
}
複製程式碼

註解類的建構函式只允許下列引數型別:

  • 對應於 Java 原生型別的型別(Int、 Long等);
  • 字串;
  • 類(Foo::class);
  • 列舉;
  • 其他註解;
  • 上面已列型別的陣列。
  • Kotlin中只允許用val宣告引數
  • 當引數型別是其他註解時,該註解類的名字前面不能用@

總結

註解和反射都是很多應用中使用到的技術,而本篇文章主要對比了註解和反射在Java和Kotlin中寫法的差別。

參考文獻:
Kotlin語言中文站、《Kotlin程式開發入門精要》

推薦閱讀:
從Java到Kotlin(一)為什麼使用Kotlin
從Java到Kotlin(二)基本語法
從Java到Kotlin(三)類和介面
從Java到Kotlin(四)物件與泛型
從Java到Kotlin(五)函式與Lambda表示式
從Java到Kotlin(六)擴充套件與委託
從Java到Kotlin(七)反射和註解
從Java到Kotlin(八)Kotlin的其他技術
Kotlin學習資料總彙


更多精彩文章請掃描下方二維碼關注微信公眾號"AndroidCzh":這裡將長期為您分享原創文章、Android開發經驗等! QQ交流群: 705929135

從Java到Kotlin(七)

相關文章