- 一、前言
- 二、案例
- 三、詳解
一、前言:
在說明Class類的靜态方法forName()之前,先清楚有關Class類的幾個概念:
1、 Class類封裝了類或接口的運作時狀态
Java程式在運作時,Java運作時系統一直對所有的對象進行所謂的運作時類型辨別,這些标示紀錄了每個對象所屬的類。
虛拟機通常使用運作時類型資訊選擇正确方法去執行,用來儲存這些類型資訊的類是Class類。
2、Class類型的對象,是加載類時自動建立的
Class 沒有公共構造方法。Class 對象是在加載類時,由Java 虛拟機以及通過調用類加載器中的 defineClass 方法自動構造的,是以不能顯式地聲明一個Class對象。
3、虛拟機為每種類型管理一個獨一無二的Class對象
每個類(型)都有一個Class對象。
運作程式時,Java虛拟機(JVM)首先檢查所要加載的類對應的Class對象是否已經加載。如果沒有加載,JVM就會根據類名查找.class檔案,并将其Class對象載入。
1.基本的 Java 類型(boolean、byte、char、short、int、long、float 和 double)和關鍵字 void 也都對應一個 Class 對象。
2.每個數組屬于被映射為 Class 對象的一個類,所有具有相同元素類型和維數的數組都共享該 Class 對象。
3.一般某個類的Class對象被載入記憶體,它就用來建立這個類的所有對象。
以上說法檢視Class源碼會發現,
Book.class.getName()
最終調用的:
private transient String name;
public String getName() {
String name = this.name;
if (name == null)
this.name = name = getName0();
return name;
}
此時Book也是一個獨一無二的Class對象,即對象中的對象。
二、案例:
Book.java類
package com.junit.demo;
public class Book {
private static final String defName = "《程式猿植發》";
static {
System.out.println("我是靜态代碼塊,輸出: " + defName);
}
//列印生産日期:
public static String printProduceDate(String name) {
return "我是靜态方法printProduceDate,輸出: " + name + ", produce is:" + System.currentTimeMillis();
}
private String name;
public Book() {
System.out.println("我是Book聲明的構造方法!");
name = defName;
}
public String toString(String msg) {
return name + msg;
}
}
執行方法:
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
//1-将指定類加載到JVM中(ClassNotFoundException)
Class aClass = Class.forName("com.junit.demo.Book");
System.out.println(aClass);
//2.1-通路靜态方法:NoSuchMethodException,InvocationTargetException
Method method = aClass.getMethod("printProduceDate", String.class);
String result = (String) method.invoke(aClass, "《程式猿的頸椎自傳》");
System.out.println(result);
System.out.println("---------------------------\n");
//2.2-初始化對象:
Book obj = (Book) aClass.newInstance();
System.out.println("得到對象後通路get方法:" + obj.toString(""));
System.out.println("---------------------------\n");
//2.3-初始化對象後通路方法:
Method method3 = aClass.getMethod("toString", String.class);
String result3 = (String) method3.invoke(aClass.newInstance()/*obj*/, "這本書是我的夥伴!");
System.out.println(result3);
System.out.println("---------------------------\n");
System.out.println(Book.class.getName());
}
輸出:
我是靜态代碼塊,輸出: 《程式猿植發》
class com.junit.demo.Book
我是靜态方法printProduceDate,輸出: 《程式猿的頸椎自傳》, produce is:1626682894095
---------------------------
我是Book聲明的構造方法!
得到對象後通路get方法:《程式猿植發》
---------------------------
我是Book聲明的構造方法!
《程式猿植發》這本書是我的夥伴!
---------------------------
com.junit.demo.Book
三、詳解:
1、通路靜态方法:
// 由Class擷取方法:第一個參數為方法名,第二個參數為方法的參數類型。
// 如add(int a,int b)則getMethod("add",int.class,int.class)。當然,也可以是Java對象。
Method method = aClass.getMethod("printProduceDate", String.class);
// 引用方法:(引用執行個體/調用靜态方法可為null,參數值/有多個用逗号隔開),參數值要和參數類型的數量比對!
String result = (String) method.invoke(aClass, "《程式猿的頸椎自傳》");
簡寫:
2、通路執行個體方法:
- 重要:
aClass.newInstance();
,執行個體化指定對象。
和 new Book() 效果一樣。
//方法一:直接轉化執行個體化後的對象,直接調用方法
Book book= (Book) aClass.newInstance();
// book.setName('xxx'); or book.getName(); or more...
//方法二:使用invoke調用指定執行個體a的指定方法b
Method method3 = aClass.getMethod("toString", String.class);
//這裡的book可以是已執行個體化的對象,或者使用 aClass.newInstance() 傳入,詳見簡寫:
String result3 = (String) method3.invoke(book, "這本書是我的夥伴!");
簡寫:
值得注意的是,如果是類似于工具類可用于全部類通路的,可以使用一個執行個體化對象,而不需要每次都newInstance。
另外,方法一适用于需要映射的類是已知或少數時,反之需要統一按指定字元串反射調用方法的話,需使用方法二。
end.