面向對象的世界——萬事萬物皆對象
在面向對象的世界里,我們說萬事萬物皆對象。在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 }
- Only the java Virtual Machine creates Class objcts:只能由Java虛擬機來創建Class類對象。
- 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.