Java中a.getClass方法和A.class之間的區別

1.概述

在Java中,java.lang.Class是所有反射操作的入口點。一旦有了java.lang.Class對象,就可以調用相應的方法來獲取反射類的對象。

在本教程中,我們將討論兩種不同的獲取java.lang.Class對象的方式之間的區別:

2.兩種方法的簡要介紹

Object.getClass() Object類的實例方法。如果有一個對象,則可以調用object.getClass()以獲取其類型Class

同樣,我們可以使用ClassName.class語法獲取Class對象。一個例子可以清楚地解釋它:

@Test

 public void givenObjectAndType_whenGettingClassObject_thenTwoMethodsHaveTheSameResult() {

 String str = "I am an object of the String class";



 Class fromStrObject = str.getClass();

 Class clazz = String.class;



 assertSame(fromStrObject, clazz);

 }

在上面的測試方法中,我們嘗試使用我們提到的兩種方法String Class對象。最後,斷言方法告訴我們兩個Class像是同一實例。

但是,這兩種方法之間存在差異。讓我們仔細看看它們。

3.運行時類型與靜態類型

讓我們快速回顧一下前面的示例。**當我們調用str.getClass()方法時,我們將獲得str對象的運行時類型。另一方面, String.class靜態評估String**類。在此示例中, strString.class的運行時類型相同。

但是,如果使用了類繼承,則它們可以不同。讓我們看兩個簡單的類:

public class Animal {

 protected int numberOfEyes;

 }



 public class Monkey extends Animal {

 // monkey stuff

 }

現在,讓我們實例化Animal類的對象並進行另一個測試:

@Test

 public void givenClassInheritance_whenGettingRuntimeTypeAndStaticType_thenGetDifferentResult() {

 Animal animal = new Monkey();



 Class runtimeType = animal.getClass();

 Class staticType = Animal.class;



 assertSame(staticType, runtimeType);

 }

如果我們運行上面的測試,將會導致測試失敗:

java.lang.AssertionError: ....

 Expected :class com.baeldung.getclassobject.Animal

 Actual :class com.baeldung.getclassobject.Monkey

在測試方法中,即使我們通過Animal animal = new Monkey(); animal而不是Monkey animal = new Monkey(); animal對象的運行時類型仍然是Monkey.這是因為animal像在運行時Monkey的實例。

但是,當我們獲得Animal類的靜態類型時,該類型始終是Animal

4.處理基本類型

在編寫Java代碼時,我們經常使用基本類型。讓我們嘗試object.getClass()方法獲取原始類型Class

int number = 7;

 Class numberClass = number.getClass();

如果我們嘗試編譯上面的代碼,則會收到編譯錯誤:

Error: java: int cannot be dereferenced

編譯器不能取消引用number變量,因為它是原始變量。因此, object.getClass()方法無法幫助我們獲取基本類型Class

讓我們看看是否可以使用.class語法獲取原始類型:

@Test

 public void givenPrimitiveType_whenGettingClassObject_thenOnlyStaticTypeWorks() {

 Class intType = int.class;

 assertNotNull(intType);

 assertEquals("int", intType.getName());

 assertTrue(intType.isPrimitive());

 }

因此,我們可以int.class int基本類型Class對象。在Java版本9和更高版本中,原始類型Class java.base模塊。

如測試所示, .class語法是獲取原始類型Class

5.在沒有實例的情況下獲取類

我們已經了解到object.getClass()方法可以為我們提供其運行時類型Class

現在,讓我們考慮要獲取Class對象但由於目標類是abstract類, interface,或某些類不允許實例化而無法獲取目標類型的實例的情況:

public abstract class SomeAbstractClass {

 // ...

 }



 interface SomeInterface {

 // some methods ...

 }



 public class SomeUtils {

 private SomeUtils() {

 throw new RuntimeException("This Util class is not allowed to be instantiated!");

 }

 // some public static methods...

 }

在這些情況下,我們無法object.getClass()方法獲取這些類型Class對象,但仍可以使用.class語法來獲取它們**Class對象:**

@Test

 public void givenTypeCannotInstantiate_whenGetTypeStatically_thenGetTypesSuccefully() {

 Class interfaceType = SomeInterface.class;

 Class abstractClassType = SomeAbstractClass.class;

 Class utilClassType = SomeUtils.class;



 assertNotNull(interfaceType);

 assertTrue(interfaceType.isInterface());

 assertEquals("SomeInterface", interfaceType.getSimpleName());



 assertNotNull(abstractClassType);

 assertEquals("SomeAbstractClass", abstractClassType.getSimpleName());



 assertNotNull(utilClassType);

 assertEquals("SomeUtils", utilClassType.getSimpleName());

 }

如上面的測試所示, .class語法可以獲取這些類型Class

因此,當我們想擁有Class對象,但又無法獲得該類型的實例時, .class語法是可行的方法。

六,結論

在本文中,我們學習了兩種獲取Class對象的object.getClass()方法和.class語法。

稍後,我們討論了兩種方法之間的區別。下表可以給我們清晰的概述:

object.getClass()SomeClass.class
類對象object的運行時類型SomeClass的靜態類型
原始類型-直接工作
接口,抽像類或無法實例化的類-直接工作