如何唯一確定一個 Java 類?
今天偶然想起之前和朋友討論過的一個問題:如何唯一確定一個 Java 類?我相信大多數朋友遇到這個問題的回答都是:類的全路徑唄。但事實上,唯一確定一個 Java 類,單單靠類路徑是不夠的,還要多加上一個東西:類載入器。也就是說,類載入器 + 類路徑才唯一確定一個 Java 類。
為了證明我所說的,我們來做一個簡單的實驗。
//自定義一個類載入器ClassLoader myLoader = new ClassLoader() { @Override public Class> loadClass(String name) throws ClassNotFoundException { try { String fileName=name.substring(name.lastIndexOf(".")+1)+".class"; InputStream is=getClass().getResourceAsStream(fileName); if( is == null ){ return super.loadClass(name); } byte[] bytes = new byte[is.available()]; is.read(bytes); //透過自定義類載入器讀取class檔案的二進位制流 return defineClass(name, bytes, 0,bytes.length); } catch (IOException e) { e.printStackTrace(); throw new ClassNotFoundException(name); } } };//比較類是否相同Object obj = myLoader.loadClass("com.chenshuyi.UniqueClass").newInstance(); System.out.println(obj.getClass()); System.out.println(UniqueClass.class); System.out.println(obj instanceof UniqueClass);
在上面這段程式碼中,我首先定義了一個自定義類載入器 myLoader,之後讓其去載入com.chenshuyi.UniqueClass
類,之後呼叫newInstance()
獲得該類的例項 obj。
接著分別列印輸出 obj 物件的類路徑,以及 UniqueClass 類的類路徑,最後使用 instanceof 符號判斷 obj 物件是否是 UniqueClass 類的例項。最後的輸出結果是:
class com.chenshuyi.UniqueClassclass com.chenshuyi.UniqueClassfalse
上面的結果顯示:obj 物件和 UniqueClass 類的類路徑完全相同,都是com.chenshuyi.UniqueClass
。但是 obj 物件卻不是 UniqueClass 類的例項。這就驗證了我的說法,即:類載入器 + 類路徑才唯一確定一個 Java 類。
其實在 Java 語言中,還有一個與之非常類似的情況:如何唯一確定類中的一個方法?按照我們一直以來的直覺,我們會回答:方法名、形參型別、形參個數。例如下面的兩個方法雖然方法名相同,但是引數型別和個數不同,所以他們是不同的方法。
public void Hello(String name)public void Hello(String name, int age)
但下面兩個方法雖然返回型別不同,但他們的方法名和引數型別是一致的,所以他們無法透過編譯。
public void Hello(String name)public String Hello(String name)
但是其實對於 JVM 來說,在同一個類中是可以存在方法名相同並且引數型別相同的方法名的。也就是說,在JVM 中判斷一個方法的要素是:類名、方法名以及方法描述符。與 Java 原始碼中的不同在於方法描述符這個概念。方法描述符由方法的引數型別和返回型別所構成。例如下面的這個方法,方法描述符就是 name 這個引數,以及 String 這個返回型別。
public String Hello(String name)
為了證明我上面的觀點,我們再做一個簡單的實驗。
下面的程式碼宣告瞭一個方法 a 和 方法 b,方法名不同,返回型別不同。
public class UniqueMethod { public void a(){} public String b(){ return "b"; } public static void main(String[] args) { System.out.println("Hello"); } }
為了證明在 JVM 對於方法唯一性判斷,我將透過修改位元組碼的方式,讓 UniqueMethod 位元組碼變成下面這樣。即有兩個相同的 a 方法,它們的方法名、形參型別、形參個數都相同,但是返回引數型別不同。
public class UniqueMethod { public void a(){} public String a(){ return "b"; } public static void main(String[] args) { System.out.println("Hello"); } }
那麼實驗開始了!
首先我們用 javac 命令編譯出位元組碼 class 檔案,接著使用 asmtools 工具將 class 檔案再轉為 jasm 檔案。我們開啟 jasm 檔案看看:
可以看到裡面有三個方法,分別是 a 方法、b 方法和 main 方法。此時我們將 b 方法名稱直接修改成 a 方法,接著使用 asmtools 工具將 jasm 檔案轉為 class 檔案。透過這種方式,我們就可以在一個類中擁有兩個名為 a 的方法了。這兩個 a 方法,它們的方法名、形參型別、形參個數都相同,但是返回引數型別不同。
生成修改後的 class 檔案之後,我們執行 java UniqueMethod
命令,順利列印出字元:Hello。這說明 class 檔案並沒有任何錯誤,JVM 對於方法名、形參型別、形參個數都相同,但是返回引數型別不同的方法,是完全接受的。
讓我們再用 javap 命令來看看 class 檔案的位元組碼結構,我們會發現確實是存在了兩個名稱為 a 的方法的。
最後讓我們來總結一下:在 JVM 中,類路徑和類載入器唯一確定一個 Java 類,方法名、形參型別、形參個數、返回引數型別唯一確定一個 Java 類中的方法。
其實不僅僅是類與方法的唯一性,在很多方面 JVM 和 Java 語言規範真是有很大的差別。很多在 Java 中成立的東西,到了 JVM 其實就不一定成立了。例如:Java 的泛型、Java 的 lambla 表示式等等,其實只在 Java 語言層面存在,而在 JVM 中其實是不存在的。
原文出處:https://www.cnblogs.com/chanshuyi/p/how_to_confirm_an_unique_class.html
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/430/viewspace-2814233/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 建模的時候如何確定一個名詞是類還是別一個類的屬性?
- Java演算法面試題(004) 實現一個演算法來確定一個字串是否具有所有唯一的字元Java演算法面試題字串字元
- 【指令碼】如何確保應用程式的唯一性指令碼
- [apue] 一個快速確定新系統上各類限制值的工具
- Kmeans如何確定聚類個數K聚類
- Java類方法(定義一個工具類,儲存一些常用的方法)Java
- 如何確定一個 Go 變數會被分配在哪裡?Go變數
- java的一個類!Java
- 用數學歸納法證明前序序列和中序序列唯一的確定一個二叉樹序列二叉樹
- 如何確定一個字串中是否所有字元全部互不相同字串字元
- 定製一個BitmapButton類 (轉)
- 怎麼解決new一個類欄位唯一標識問題?
- Java如何停止執行緒,確定你知道的都是正確的麼?Java執行緒
- 一個確定trace檔案的指令碼指令碼
- 如何確定一個嚴重規範化的資料庫系統?資料庫
- 如何獲取Android唯一標識(唯一序列號)Android
- 確保物件的唯一性——單例模式 (五)物件單例模式
- 確保物件的唯一性——單例模式 (四)物件單例模式
- 確保物件的唯一性——單例模式 (三)物件單例模式
- 確保物件的唯一性——單例模式 (二)物件單例模式
- 一個Java類的載入Java
- 如何實現簡單的定時全域性唯一任務?
- 如何判斷一個類是從另一個類繼承繼承
- PostgreSQL唯一約束如何使用?SQL
- 如果Java是你唯一的愛Java
- 將不確定變為確定~類中的屬性何時被執行
- jvm如何載入一個類JVM
- 如何設定一個定時任務?
- Java自定義一個字典類(Dictionary)Java
- Alpaquita Linux:唯一為Java量身定製的Linux作業系統UILinuxJava作業系統
- pytest之將多個測試用例放在一個類中,生成唯一臨時資料夾
- 前端如何定義一個常量前端
- 如何確定一個dmp檔案是exp匯出的還是expdp匯出的?
- 利用MYSQL的C API程式設計,如何確定一個資料庫/表是否存在???MySqlAPI程式設計資料庫
- 如何從weblogic叢集環境中獲得一個唯一物件Web物件
- LeetCode 387. 字串中的第一個唯一字元 (Java)LeetCode字串字元Java
- 教你寫一個彈幕庫,確定不瞭解一下?
- java 一個類實現兩個介面的案例Java