班级名称
在Java中,每個類都有一個名稱。 類位于軟件包中,這使我們程序員可以一起工作,避免名稱沖突。 我可以為A類命名,也可以為A類命名,只要它們位于不同的程序包中,它們就可以很好地協同工作。
如果您查看Class的API,您肯定會注意到有三種不同的方法為您提供類的名稱:
- getSimpleName()為您提供不帶包的類的名稱。
- getName()為您提供類的名稱,其全包名稱位于前面。
- getCanonicalName()為您提供類的規范名稱。
簡單嗎? 好吧,第一個很簡單,第二個也很有意義,除非存在令人不安的規范名稱。 這還不是很明顯。 而且,如果您不知道規范名稱是什么,您可能還會在第二時間受到Java技能的干擾。 兩者有什么區別?
如果您想要精確的解釋,請訪問Java語言規范6.7章 。 在這里,我們進行一些更簡單,更簡單的理解,盡管不夠全面。
讓我們看一些例子:
package pakage.subpackage.evensubberpackage; import org.junit.Assert; import org.junit.Test;public class WhatIsMyName {@Testpublic void classHasName() {final Class<?> klass = WhatIsMyName.class;final String simpleNameExpected = "WhatIsMyName";Assert.assertEquals(simpleNameExpected, klass.getSimpleName());final String nameExpected = "pakage.subpackage.evensubberpackage.WhatIsMyName";Assert.assertEquals(nameExpected, klass.getName());Assert.assertEquals(nameExpected, klass.getCanonicalName()); } ...這種“單元測試”運行得很好。 但是正如您所看到的,在這種情況下,名稱和規范名稱沒有區別。 (請注意,程序包的名稱是pakage而不是package 。要測試您的Java詞匯技巧,請回答為什么?)
讓我們看一下來自同一junit測試文件的下一個示例:
@Testpublic void arrayHasName() {final Class<?> klass = WhatIsMyName[].class;final String simpleNameExpected = "WhatIsMyName[]";Assert.assertEquals(simpleNameExpected, klass.getSimpleName());final String nameExpected = "[Lpakage.subpackage.evensubberpackage.WhatIsMyName;";Assert.assertEquals(nameExpected, klass.getName());final String canonicalNameExpected = "pakage.subpackage.evensubberpackage.WhatIsMyName[]";Assert.assertEquals(canonicalNameExpected, klass.getCanonicalName()); }現在有區別。 當我們談論數組時,簡單名稱會發出信號,即在其后面加上了括號,就像在Java源代碼中所做的那樣。 “普通”名稱看起來有點怪異。 它以L開頭并附加分號。 這反映了JVM中類名的內部表示。 規范名稱的更改類似于簡單名稱:對于以前的類,其類具有所有包名稱作為前綴并附加了方括號。 似乎getName()更像是類的JVM名稱,而getCanonicalName()更像是Java源代碼級別的完全限定名稱。
讓我們繼續其他示例(我們仍在同一文件中):
class NestedClass{}@Testpublic void nestedClassHasName() {final Class<?> klass = NestedClass.class;final String simpleNameExpected = "NestedClass";Assert.assertEquals(simpleNameExpected, klass.getSimpleName());final String nameExpected = "pakage.subpackage.evensubberpackage.WhatIsMyName$NestedClass";Assert.assertEquals(nameExpected, klass.getName());final String canonicalNameExpected = "pakage.subpackage.evensubberpackage.WhatIsMyName.NestedClass";Assert.assertEquals(canonicalNameExpected, klass.getCanonicalName()); }區別在于班級名稱中的美元符號。 同樣,“名稱”更多是JVM使用的名稱,而規范名稱是Java源代碼之類的名稱。 如果編譯此代碼,則Java編譯器將生成以下文件:
- WhatIsMyName.class和
- WhatIsMyName$NestedClass.class
即使該類被命名為嵌套類,它實際上也是一個內部類。 但是在命名上沒有什么區別:另一個類中的靜態或非靜態類僅被命名為相同。 現在,讓我們看一些更有趣的東西:
@Testpublic void methodClassHasName() {class MethodClass{};final Class<?> klass = MethodClass.class;final String simpleNameExpected = "MethodClass";Assert.assertEquals(simpleNameExpected, klass.getSimpleName());final String nameExpected = "pakage.subpackage.evensubberpackage.WhatIsMyName$1MethodClass";Assert.assertEquals(nameExpected, klass.getName());final String canonicalNameExpected = null;Assert.assertEquals(canonicalNameExpected, klass.getCanonicalName());}這次我們在方法內部有一個類。 這不是通常的情況,但是從Java語言的角度來看是有效的。 類的簡單名稱就是這樣:類的簡單名稱。 沒什么奇怪的。
但是,“正?!泵Q很有趣。 Java編譯器為該類生成一個JVM名稱,該名稱中包含一個數字。 為什么? 因為沒有什么可以阻止我在測試類的另一個方法中擁有一個具有相同名稱的類,并插入數字是防止JVM名稱沖突的方法。 JVM不了解或不關心內部和嵌套類或方法內部定義的類。 一類就是一類。 如果編譯代碼,則可能會看到javac生成的文件WhatIsMyName$1MethodClass.class 。 我不得不添加“可能”不是因為我認為您可能會盲目,而是因為該名稱實際上是Java編譯器的內部問題。 它可能會選擇其他避免名稱沖突的策略,盡管我不知道有什么不同于上面的編譯器。
規范名稱是最有趣的。 它不存在! 它為空。 為什么? 因為您不能從定義它的方法之外訪問此類。 它沒有規范名稱。 我們繼續。
匿名類呢? 他們不應該有名字。 畢竟,這就是為什么它們被稱為匿名的原因。
@Testpublic void anonymousClassHasName() {final Class<?> klass = new Object(){}.getClass();final String simpleNameExpected = "";Assert.assertEquals(simpleNameExpected, klass.getSimpleName());final String nameExpected = "pakage.subpackage.evensubberpackage.WhatIsMyName$1";Assert.assertEquals(nameExpected, klass.getName());final String canonicalNameExpected = null;Assert.assertEquals(canonicalNameExpected, klass.getCanonicalName());}實際上,它們沒有簡單的名稱。 簡單名稱是空字符串。 它們確實具有名稱,但由編譯器組成。 較差的javac沒有其他選擇。 它甚至必須為未命名的類組成一些名稱。 它必須為JVM生成代碼,并且必須將其保存到某個文件中。 規范名稱再次為null。
我們已經準備好示例了嗎? 否。最后我們有一些簡單的東西(又稱原始)。 Java基元。
@Testpublic void intClassHasName() {final Class<?> klass = int.class;final String intNameExpected = "int";Assert.assertEquals(intNameExpected, klass.getSimpleName());Assert.assertEquals(intNameExpected, klass.getName());Assert.assertEquals(intNameExpected, klass.getCanonicalName());}如果該類表示一個原語,例如int (還有什么比int更簡單?),則簡單名稱,“ the”名稱和規范名稱都全部是該原語的int名稱。
就像原始數組一樣非常簡單嗎?
@Testpublic void intArrayClassHasName() {final Class<?> klass = int[].class;final String simpleNameExpected = "int[]";Assert.assertEquals(simpleNameExpected, klass.getSimpleName());final String nameExpected = "[I";Assert.assertEquals(nameExpected, klass.getName());final String canonicalNameExpected = "int[]";Assert.assertEquals(canonicalNameExpected, klass.getCanonicalName());}好吧,這并不簡單。 名稱為[I ,這有點神秘,除非您閱讀JVM規范的相應章節 。 也許我再說一次。
結論
類的簡單名稱很簡單。 對于JVM級別的事情, getName()返回的“名稱”是一個有趣的東西。 getCanonicalName()是最像Java源代碼的那個。
- 您可以從GitHub的g789 e789d700d3c9abc6afa0獲得上述示例的完整源代碼。
翻譯自: https://www.javacodegeeks.com/2014/09/name-of-the-class.html
總結
- 上一篇: 购买银行代销理财产品有什么条件?
- 下一篇: 京东小金库的钱为什么转不出来?