獲取類類型三種方式


面向對象的世界——萬事萬物皆對象

在面向對象的世界里,我們說萬事萬物皆對象。在Java語言中,只有兩樣不是面向對象:普通數據類型和java中的靜態。

  • 普通數據類型:例如  int a=5;  這就不是一個對象。但是普通數據類型都有封裝類來彌補這個缺陷。
  • java中的靜態:不論是靜態成員變量還是方法,java中的靜態東西並不是屬於某個對象,而是屬於某個類。

所以在面向對象的世界里,最好萬事萬物都看做對象。

 

Class類的對象

既然萬事萬物皆對象,那么每寫的一個類是不是一個對象呢?當然,所寫的任何一個類都屬於對象。那么這些類都是誰的對象呢?其實這些類都是java.lang.Class類的實例對象。比如:

我們寫了一個Student的類,那么這個類是不是一個對象?當然是一個對象。那么是誰的對象呢?Class類的對象。既然如此那么我們是不是就可以用

 

Class classStu=new Class()

 

這種構造方法的方式來表示這個Class類的對象呢?答案是否定的。雖然每寫的每一個類都是Class類的對象,但是這個對象的表達方式比較麻煩。

 

創建Class類對象

看一下Class類中的構造方法:

 1      /*
 2  * Private constructor. Only the Java Virtual Machine creates Class objects.  3  * This constructor is not used and prevents the default constructor being  4  * generated.  5       */
 6      private Class(ClassLoader loader) {  7          // Initialize final field for classLoader. The initialization value of non-null  8          // prevents future JIT optimizations from assuming this final field is null.
 9          classLoader = loader; 10 }
說明
  1. Only the java Virtual Machine creates Class objcts:只能由Java虛擬機來創建Class類對象。
  2. Class類的構造函數使用的是private私有的方法,因此不可以被外部引用。

所以不能天真的像創建其他對象一樣通過Class類的構造函數來創建Class類的對象。那么該如何創建Class類的對象呢?有三種方式:

 

Student.java:創建Student類,並且實例化Student類的一個對象student。如何創建Student類型的Class類的對象?

1 package com.xxj; 2 
3 public class ClassDemo01 { 4     public static void main(String[] args) { 5         Student student=new Student();//Student類的實例對象
6  } 7 } 8 class Student{}

 

第一種:通過  類名.Class  方式

Class<?> class1=Student.class;

通過類名.Class的方式就可以創建了一個Class類的對象。這種方式還透露了一個信息:任何一個類中隱藏了一個靜態的成員變量class。

第二種:通過該類的實例對象的getClass()方法獲取Class類的實例對象

1 // 創建Student類的對象student
2         Student student=new Student(); 3 // 利用該類對象的getClass方法獲取Class類的實例
4         Class<?> class2=student.getClass();

Q:getClass()這個方法又是從哪個地方冒出來的呢?

A:如果一個類沒有明確指明繼承哪個類,就會默認繼承Object。在Object類中有個:public final native Class<?> getClass();方法。

 

說明:

1、student代表的是Student類的實例對象,class1與class2都代表的是Class類的實例對象。

官方對class1、class2的解釋:

class1和class2都表示了Student類的類類型(class type)。

Student類的類類型:本身Student類就是一個Class類的類型的對象。

可以先看一個例子來幫助理解:上面的student是Student類型。同理,Student類是Class類型的,轉個彎即Student類是類類型的。所以class1,class2就是類類型,然而為了加以區分不同的類類型,我們稱之為該類的類類型。因此class1與class2成為Student類的類類型。

Student類的對象是student。

Student類的Class對象是:class1,class2。(Student類的類類型)

 

第三種方式創建Student類的類類型:通過forName(“全限定類名”)

1         Class class3=null; 2         try { 3             class3=Class.forName("com.xxj.Student");//加類的全稱 
4         } catch (ClassNotFoundException e) { 5  e.printStackTrace(); 6         }

這里面必須加上完整的類的全名包名.類名。因為這里需要輸入類的名稱,但是防止輸入的錯誤,所以這里面有ClassNotFoundException異常。

問題:上面我們已經實例化出了三個Student類的類類型對象,那么這三個對象是什么?有什么關系?是否相等呢?

1 System.out.println("class1==class2:"+(class1==class2)); 2 System.out.println("class2==class3:"+(class2==class3)); 3 System.out.println("class1==class3:"+(class1==class3)); 4 System.out.println("student1==student2:"+(student==student2)); 5 System.out.println("class1為:"+class1); 6 System.out.println("student1為:"+student+",student2為:"+student2);
 
         

運行結果:

 

1 class1==class2:true
2 class2==class3:true
3 class1==class3:true
4 student1==student2:false
5 class1為:class com.xxj.Student 6 student1為:com.xxj.Student@2a139a55,student2為:com.xxj.Student@15db9742

 

 

 

說明:一個類只可能是Class類的一個實例對象,也就是說不管創建了多少該類的類類型對象,也不管用了何種方式創建該類的類類型對象,最終都是同一個。

 

該類的類類型創建該類的實例對象(說的簡單些就是通過class1、class2或者class3來創建Student的實例對象。)

說明:如果是A類的類類型創建出來的就是A類的對象,如果是B類的類類型創建出來的就是B類的對象。也因此導致java源碼並不知道具體是哪個類的類類型來創建實例對象的,所以通過該類的類類型創建該類的實例對象Java直接返回一個Object類型,這樣就需要通過強制的類型轉換。

 

通過Class類中的newInstance()方法來定義類實例化的對象。

 
         
public Object newInstance() throw InstantiationException,IllegalAccessException
 
         操作代碼
 
         
 1   try { 2       Student student3=(Student)class1.newInstance();//通過newInstance方法創建該類的類類型對應該類的實例對象
 3       Student student4=(Student)class2.newInstance(); 4       System.out.println("student3為:"+student3); 5       System.out.println("student4為:"+student4); 6 student3.print(); 7   } catch (InstantiationException e) { 8 e.printStackTrace(); 9   } catch (IllegalAccessException e) { 10 e.printStackTrace(); 11   }
 
        

運行結果:

student3為:com.xxj.Student@6d06d69c
student4為:com.xxj.Student@7852e922
Student print 

注意:使用newInstance方法創建實例,要求類中要有個無參的構造函數,因為newInstance()方法會默認的調用無參的構造函數。

問題如果類中沒有無參的構造函數該如何處理呢?可以通過public T newInstance(Object... initargs) throws方法來解決此問題。

1 class Student{ 2     public Student(String name,int age,String school){ 3             
4  } 5     void print(){ 6         System.out.println("Student print "); 7  } 8 }

 

此Student類中就沒有無參的構造函數,我們還是上面的代碼運行發現報錯如下:初始化異常!

java.lang.InstantiationException: com.xxj.Student
at java.lang.Class.newInstance(Unknown Source)
at com.xxj.ClassDemo01.main(ClassDemo01.java:72)
Caused by: java.lang.NoSuchMethodException: com.xxj.Student.<init>()
at java.lang.Class.getConstructor0(Unknown Source)
... 2 more

 解決方法

1 Student student3=(Student)class1.getConstructors()[0].newInstance(new Object[]{"Tom",19,"南工天下"}); 2 Student student4=(Student)class3.getConstructors()[0].newInstance("3QC",20,"水木清華"); 3 student4.print();

因為這里面沒有一個默認的構造方法,所以不可以采用類類型直接調用newInstance()方法實例化對象,只能先通過getConstructors方法獲取全部的構造函數,然后找到匹配的構造函數使用newInstance方法傳入參數才可以實例化對象。

 

完整代碼:

package com.xxj;

public class ClassDemo01 {

    public static void main(String[] args) {
        Student student=new Student();
        Student student2=new Student();
        
        Class<?> class1=Student.class;
        Class<?> class2=student.getClass();
        Class class3=null;
        try {
            class3=Class.forName("com.xxj.Student");//加類的全稱    
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
         
        System.out.println("class1==class2:"+(class1==class2));//返回true
        System.out.println("class2==class3:"+(class2==class3));
        System.out.println("class1==class3:"+(class1==class3));
        System.out.println("class1為:"+class1);
        System.out.println("student1==student2:"+(student==student2));
        System.out.println("student1為:"+student+",student2為:"+student2);
    
        try {
            Student student3=(Student)class1.newInstance();
            Student student4=(Student)class2.newInstance();
            System.out.println("student3==student4:"+(student3==student4));            
            System.out.println("student3為:"+student3);
            System.out.println("student4為:"+student4);
            student3.print();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}
class Student{
    void print(){
        System.out.println("Student print ");
    }
}

運行結果:

class1==class2:true
class2==class3:true     
class1==class3:true     
class1為:class com.xxj.Student
student1==student2:false
student1為:com.xxj.Student@2a139a55,student2為:com.xxj.Student@15db9742
student3==student4:false
student3為:com.xxj.Student@6d06d69c
student4為:com.xxj.Student@7852e922
Student print

 

END.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM