[精讚] [會員登入]
170

【JAVA】[java.lang.Class]如何不透過new來實體化class

在某些極端狀態下,我們沒有辦法直接將實體化後的 Object 傳入函數內,只能採用傳入 Class 在實體化成物件這種極端的方式來進行

分享此文連結 //n.sfs.tw/15913

分享連結 【JAVA】[java.lang.Class]如何不透過new來實體化class@小編過路君子
(文章歡迎轉載,務必尊重版權註明連結來源)
2022-07-25 19:19:21 最後編修
2022-07-25 15:53:00 By 過路君子
 

哈囉大家好,這裡是成功抓到 Class<T> 邏輯的小編過路君子

對,小編的標題是沒有打錯的,因為我們今天的主角就是 java.lang.Class<T> 這個類別。

 

 

承如本文章開場簡介所述,大部分的時候我們都是將 Object 傳入一個 function 內,那之後要進行什麼動作都直接在 function 內呼叫該 Object 的方法即可。

但如果該 Object 的某個參數只能在實體化(initialization)的時候賦予數值並且該作者沒有提供 setter 怎麼辦?換句話說,該參數僅能透過建構子(Constructor)來賦值,只要一旦建構結束,便會被上鎖。

而且最要命的是,我們是沒有辦法預測究竟是哪個 Object 會被傳入,如果我們貿然寫死讓其產生固定的程式碼的話,那就失去了程式的整體使用彈性,也就是如果需要十種結果,就要寫十個函式,實在是太累了。

 

所以我們今天要做的事情便是寫一個函數,此函數會收一個 Class(不是 Object),具體效果如下圖:

(所有圖片點擊都可以放大、變高清)

你問小編說怎麼不將 index, login, setting, & log 這四個 class 直接強制轉型成 WebPage 在傳入 function 內即可?

因為原本 WebPage 的建構式都已經被覆寫(Override)了,而我們要呼叫的正不巧是這些被覆寫的建構式。

 

所以我們勢必不能將物件(Object)傳入,只能將類別(Class)傳入之後之後在將其實體化成物件(Object)。

在這邊小編順便提一下物件(Object)和類別(Class)的差別在哪裡,以免有人嫌小編囉嗦,為什麼要一直把英文標出來,因為小編真心怕有人誤會。

 

那我們一般只會將物件(Object)傳入函數,但今天我們要傳入的變成了類別(Class)。

其中的 T 是泛型(template),page 則是我們所接收到的類別。

package editor.passing.jinzan; 

import java.lang.Class;
import java.lang.reflect.Constructor;

public class Test
{
	public Test() {}

 	// 接收 Class
 	// receive Class in function.
	public void reply(Class<T> page)
	{
		// code...
	}
}

 

接下來我們假設我們現在有一個名叫 Target 的 class 要使用此函數:

package editor.passing.jinzan; 

import java.lang.Exception;
import org.apache.wicket.markup.html.WebPage;

import editor.passing.jinzan.Test;

public class Target
{
	public Target() {}
	
	public Target(int a, char b) {}
	
	public Target(Exception error, string msg) {}
	
	public void start()
	{
		Test test = new Test();

		// 將自己傳入
 		// send itself to function.
		test.reply(Target.class);
		//test.reply(Target.getClass());
	}

	public void hello() {System.out.println("Hello world!");}
}

 

接下來就可以開始對 Test 內的 reply 動刀了,那在開始前我們會使用到 getConstructor() 這個函數,顧名思義,就是用於取得建構子的函數。

首先來看看位於 Java® Platform, Standard Edition & Java Development Kit Version 17 API SpecificationClass Class<T> 上的解釋吧。

 

也就是說,依照上方的說明文件,如果我要使用此函數必須傳入的資料型態為:Class<?>...

這個 Class<?>... 有沒有很眼熟呢?沒錯,也就是類別(class)的原形,那它會根據我們餵入的類別順序去尋找對應的建構式。

 

所以如果我們需要使用 Target(int a, char b) 這個建構式,就必須這樣寫:

public void reply(Class<T> page)
{
	try
	{
		Constructor<T> constructor = page.getConstructor(int.class, char.class);
	}
	catch(Exception error) {}
}

那如果是包含非基本型態的建構式,例如:Target(Exception error, string msg),就改成這樣即可:

public void reply(Class<T> page)
{
	try
	{
		Constructor<T> constructor = page.getConstructor(Exception.class, string.class);
	}
	catch(Exception error) {}
}

 

由此可以知道 page.getConstructor(int.class, char.class) 和 page.getConstructor(char.class, int.class) 是兩個不同的建構式。

那如果是想要選取 Target() 的話,可以省略這一步,直接進行實體化的動作,下面一塊講。

 

將Class實體化

這部分的話我們需要使用到第二個函數:newInstance(),一樣先來看看此函數在該網站的介紹。

 

依照上圖的解說,接下來我們先來講如何使用 Target() 這個建構式來實體化這個 Class。

public void reply(Class<T> page)
{
	try
	{
		T target = page.newInstance();
		target.hello();
	}
	catch(Exception error) {}
}

還記的我們的泛型 T 嗎?正好這邊可以用來接住實體化後的物件,接住之後的操作方式就跟原本的 Object 一模一樣,要呼函數就呼函數,要餵入其他函數就直接丟進去。

 

其他的建構式也是如法炮製,只是在呼叫的時候要多帶參數進去,至於要帶什麼樣的參數,就跟要帶進去原本建構式的參數一模一樣即可。

public void reply(Class<T> page)
{
	try
	{
		Constructor<T> constructor = page.getConstructor(int.class, char.class);
		T target = constructor.newInstance(295, 'Y');
		target.hello();
	}
	catch(Exception error) {}
}

// OR 或是

public void reply(Class<T> page)
{
	try
	{
		Constructor<T> constructor = page.getConstructor(Exception.class, string.class);
		T target = constructor.newInstance(new Exception("error"), "another msg");
		target.hello();
	}
	catch(Exception error) {}
}

 

 

 

後記

如果是正常寫程式,也就是所有程式都是自己撰寫的,應該是不會用到像小編這麼極端的方式,基本上會使用這個方式來撰寫程式都是在使用別人的套件時候,然後對方只提供建構子且不提供 setter 的時候才會用到這種方式。

小編感覺短時間內應該也不會再用到這個方式,所以特別寫下來,這樣以後要抄作業就快多了。

END

你可能感興趣的文章

【ThinkSpeak】一個IoT數據分析(IoT analytics)及呈現的網站 世界上有著各式各樣的需求,因而誕生出了各式各樣的網站,絕對不是沒有人提供,而是你不知道哪裡有這東西

【C++】class練習 — 檢測該字串是否為迴圈 第一次的C++結構式寫法,雖然以後應該會見怪不怪,但畢竟是第一次所以還是想保存下來

【Maven】[Wicket](Java) 如何部署Wicket到Wildfly內 Wicket 是一個 Java 下的套件,換言之,我們的網頁伺服器後端是由 Java 來撰寫的

【Python3】[Django] (Windows / Liunx) 如何從零開始創建一個網站 除了最基本的運作以外,還小小的加上了如何自導向特定目錄。

【Vim】解決貼上文字時出現過多空格的問題 換了新系統,有時候就算重裝軟體並且複製了設定檔也還是會出現非常奇怪的現象

【C】(%c, %d)解決讀取字元時的緩衝區殘留 不解決就會莫名其妙地冒出一些莫名其妙的東西

我有話要說

>>

限制:留言最高字數1000字。 限制:未登入訪客,每則留言間隔需超過10分鐘,每日最多5則留言。

訪客留言

[無留言]

隨機好文

高捷少女:小穹與果仁巧克力㊦ 「如果妳跟一個女生同班三年,看過她午休流口水跟狼吞虎嚥地吃午餐,就算變成高捷代言人,也很難把她當女神的啦!」她說,小穹氣得搶走她義大利麵裡的蝦子,其他人笑得花枝招展。

高捷少女:購票大作戰② 一個不好的預感浮現,艾米莉亞開始檢查屋子四處。窗戶跟陽台都有關好,也沒有被打開的跡象。但一股無形的壓力,開始在寂靜的公寓中蔓延,她不安地嚥一下喉嚨。最後,她走向那扇窗戶,那前天晚上,白龍為了逃脫,而撞

高捷少女:美麗島的守護者③ 小雅閉上眼睛,思索在高捷發生的點點滴滴。她心意已決,在高捷的日子的確也有快樂的部分,不過她相信換個方向是更好的決定。有關高捷的所有美好回憶,小雅決定保留在心裡就好,繼續在高捷工作只會讓自己更痛苦而已,

高捷少女:美麗島的守護者⑥ 一陣貓叫傳到小雅耳中,原本要朝小雅撲過去的北風轉了個圈,從半空中落地,牠的表情宛如五雷轟頂。這聲音……難道是……

【歌評】蓮台野夜行 - 夜のデンデラ野を逝く 走在夜晚的蓮台野 墳場,總是瀰漫著死亡的氣氛,但是,稍微的來探險一下應該是沒關係的吧?