Class類的作用,反射的源頭
在Object類中定義了以下的方法,此方法將被所有子類繼承:
public final Class getClass()
以上方法返回值的類型是一個Class類,實際上此類是Java反射的源頭,
實際上所謂反射從程序的運行結果來看也很好理解,即:
可以通過對象反射求出類的名稱
正常方式:引入需要的包、類名稱,通過new實例化,取得實例化對象
反射方式:實例化對象,getClass()方法,取得完整的包、類名稱
實例化Class類對象的方法有三種:
1.通過forName()方法
2.類.class
3.對象.getClass()
package org.lxh.demo15.getclassdemo ;
class X{
};
public class GetClassDemo02{
public static void main(String args[]){
Class<?> c1 = null ; // 指定泛型
Class<?> c2 = null ; // 指定泛型
Class<?> c3 = null ; // 指定泛型
try{
// 以下的操作形式是在開發中最常用的一種形式
c1 = Class.forName("org.lxh.demo15.getclassdemo.X") ;
}catch(ClassNotFoundException e){
e.printStackTrace() ;
}
c2 = new X().getClass() ; // 通過Object類中的方法實例化
c3 = X.class ; // 通過類.class實例化
System.out.println("類名稱:" + c1.getName()) ; // 得到類的名稱
System.out.println("類名稱:" + c2.getName()) ; // 得到類的名稱
System.out.println("類名稱:" + c3.getName()) ; // 得到類的名稱
}
};
Class類的使用
Class主要是反射的源頭,不光可以取得對象所在類的信息,也可以哦那天通過Class類的方法進行對象的實例化操作,正常情況下,使用new關鍵字爲對象實例化,如果現在已經實例化好了class對象,則就可以通過Class類中提供的
public T newInstance()
throws InstantiationException,
package org.lxh.demo15.instancedemo ;
class Person{
private String name ; // name屬性
private int age ; // age屬性
public void setName(String name){
this.name = name ;
}
public void setAge(int age){
this.age = age ;
}
public String getName(){
return this.name ;
}
public int getAge(){
return this.age ;
}
public String toString(){ // 覆寫toString()方法
return "姓名:" + this.name + ",年齡:" + this.age ;
}
};
public class InstanceDemo01{
public static void main(String args[]){
Class<?> c = null ; // 聲明Class對象
try{
c = Class.forName("org.lxh.demo15.instancedemo.Person") ;
}catch(ClassNotFoundException e){
e.printStackTrace() ;
}
Person per = null ; // 聲明Person對象
try{
per = (Person)c.newInstance() ; // 實例化對象
}catch(Exception e){
e.printStackTrace() ;
}
per.setName("李興華") ; // 設置姓名
per.setAge(30) ; // 設置年齡
System.out.println(per) ; // 內容輸出,調用toString()
}
};
通過以上代碼,可以發現,即使不使用關鍵字new對象也可以進行實例化操作,反射的作用。但是,在使用以上操作的時候有一點要注意,在操作類中必須存在無參構造方法,否則無法實例化。
package org.lxh.demo15.instancedemo ;
class Person{
private String name ; // name屬性
private int age ; // age屬性
public Person(String name,int age){
this.setName(name) ;
this.setAge(age);
}
public void setName(String name){
this.name = name ;
}
public void setAge(int age){
this.age = age ;
}
public String getName(){
return this.name ;
}
public int getAge(){
return this.age ;
}
public String toString(){ // 覆寫toString()方法
return "姓名:" + this.name + ",年齡:" + this.age ;
}
};
public class InstanceDemo02{
public static void main(String args[]){
Class<?> c = null ; // 聲明Class對象
try{
c = Class.forName("org.lxh.demo15.instancedemo.Person") ;
}catch(ClassNotFoundException e){
e.printStackTrace() ;
}
Person per = null ; // 聲明Person對象
try{
per = (Person)c.newInstance() ; // 實例化對象
}catch(Exception e){
e.printStackTrace() ;
}
per.setName("李興華") ; // 設置姓名
per.setAge(30) ; // 設置年齡
System.out.println(per) ; // 內容輸出,調用toString()
}
};
出現以下錯誤:
java.lang.ClassNotFoundException: org.lxh.demo15.instancedemo.Person
at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
at java.lang.ClassLoader.loadClass(ClassLoader.java:423)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:188)
at fanshe.InstanceDemo01.main(InstanceDemo01.java:29)
java.lang.NullPointerException
at fanshe.InstanceDemo01.main(InstanceDemo01.java:35)
Exception in thread "main" java.lang.NullPointerException
at fanshe.InstanceDemo01.main(InstanceDemo01.java:39)
所以說,發現,使用以上的方式實際上還是需要類中構造方法的支持,符合於對象的實例化要求。如果要想解決這樣的問題,則必須明確的指定要調用的構造方法,並傳遞參數,但是從實際的開發角度講,一般使用反射實例化對象的時候,類中都最好存在一個無參構造,這樣的操作比較合理。
如果要想調用有參,則必須按照以下的步驟進行:
- 通過Class類中的getConstructors()取得本類中的全部構造方法。
- 向構造方法中傳遞一個對象數組進去,裏面包含了構造方法中鎖需的各個參數。
- 之後通過Constructor實例化對象
在Constructor類中存在一個方法:
public T newInstance(Object... initargs)
throws InstantiationException,
傳遞初始化參數,以進行對象的實例化操作。
package org.lxh.demo15.instancedemo ;
import java.lang.reflect.Constructor ; // 導入反射機制包
class Person{
private String name ; // name屬性
private int age ; // age屬性
public Person(String name,int age){
this.setName(name) ;
this.setAge(age);
}
public void setName(String name){
this.name = name ;
}
public void setAge(int age){
this.age = age ;
}
public String getName(){
return this.name ;
}
public int getAge(){
return this.age ;
}
public String toString(){ // 覆寫toString()方法
return "姓名:" + this.name + ",年齡:" + this.age ;
}
};
public class InstanceDemo03{
public static void main(String args[]){
Class<?> c = null ; // 聲明Class對象
try{
c = Class.forName("org.lxh.demo15.instancedemo.Person") ;
}catch(ClassNotFoundException e){
e.printStackTrace() ;
}
Person per = null ; // 聲明Person對象
Constructor<?> cons[] = null ;
cons = c.getConstructors() ;
try{
per = (Person)cons[0].newInstance("李興華",30) ; // 實例化對象
}catch(Exception e){
e.printStackTrace() ;
}
System.out.println(per) ; // 內容輸出,調用toString()
}
};
但是,從實際角度看,如果要使用反射進行對象的實例化操作,最好在類中存在無參構造。
總結:
在使用Class實例化對象的時候必須保證類中存在一個無參構造,否則無法使用。
如果要想調用有參構造進行對象的實例化操作,則必須使用constructor類完成,此類表示構造方法,並通過可變參數傳遞要求的內容。