Java 基礎 反射機制
Java 反射機制
---------------
認識Class類
在正常情況下,必須知道一個類的完整路徑之後才可以例項化物件,但是在JAVA中也允許通過一個物件來找到其所在的類的資訊,那麼這實際上就是 Class類的功能。
package org.cwt.demo15.getclassdemo ; class X{ }; public class GetClassDemo01{ publicstatic void main(String args[]){ Xx = new X() ; // 例項化X類的物件 System.out.println(x.getClass().getName()); // 得到物件所在的類 } };
此時,所有的操作都是反著來的。
Object類的支援
在Object類中定義了以下的方法,此方法將被所有子類繼承:
publicfinal Class getClass()
以上的方法返回值的型別是一個“Class”類,實際上此類是JAVA反射的源頭。可以通過物件反射求出類的名稱。
Class類
Class本身表示一個類的本身,通過Class可以完整的得到一個類中的完整結構,包括此類中的方法定義,屬性定義等。
例項化Class類物件
第一種:通過forName()方法
第二種:類.Class
第三種:物件.getClass()
例項:
package org.cwt.demo15.getclassdemo ; class X{ }; public class GetClassDemo02{ publicstatic void main(String args[]){ Class<?>c1 = null ; // 指定泛型 Class<?>c2 = null ; // 指定泛型 Class<?>c3 = null ; // 指定泛型 try{ //以下的操作形式是在開發中最常用的一種形式 c1= Class.forName("org.cwt.demo15.getclassdemo.X") ; }catch(ClassNotFoundExceptione){ 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類的方法進行物件的例項化操作。
例項:
package org.cwt.demo15.instancedemo ;
class Person{
privateString name ; // name屬性
privateint age ; // age屬性
publicvoid setName(String name){
this.name= name ;
}
publicvoid setAge(int age){
this.age= age ;
}
publicString getName(){
returnthis.name ;
}
publicint getAge(){
returnthis.age ;
}
publicString toString(){ // 覆寫toString()方法
return"姓名:" +this.name + ",年齡:" + this.age ;
}
};
public class InstanceDemo01{
publicstatic void main(String args[]){
Class<?>c = null ; // 宣告Class物件
try{
c= Class.forName("org.cwt.demo15.instancedemo.Person") ;
}catch(ClassNotFoundExceptione){
e.printStackTrace();
}
Personper = null ; // 宣告Person物件
try{
per= (Person)c.newInstance() ; // 例項化物件
}catch(Exceptione){
e.printStackTrace();
}
per.setName("曹文濤") ; // 設定姓名
per.setAge(26); // 設定年齡
System.out.println(per); // 內容輸出,呼叫toString()
}
};
通過以上的程式碼,可以發現,即使不使用關鍵字new物件也可以進行例項化操作。
但是在使用以上操作的時候,在操作類中必須存在無參構造方法,否則無法例項化。
例項:
package org.cwt.demo15.instancedemo ;
class Person{
privateString name ; // name屬性
privateint age ; // age屬性
publicPerson(String name,int age){
this.setName(name);
this.setAge(age);
}
publicvoid setName(String name){
this.name= name ;
}
publicvoid setAge(int age){
this.age= age ;
}
publicString getName(){
returnthis.name ;
}
publicint getAge(){
returnthis.age ;
}
publicString toString(){ // 覆寫toString()方法
return"姓名:" +this.name + ",年齡:" + this.age ;
}
};
public class InstanceDemo02{
publicstatic void main(String args[]){
Class<?>c = null ; // 宣告Class物件
try{
c= Class.forName("org.cwt.demo15.instancedemo.Person") ;
}catch(ClassNotFoundExceptione){
e.printStackTrace();
}
Personper = null ; // 宣告Person物件
try{
per= (Person)c.newInstance() ; // 例項化物件
}catch(Exceptione){
e.printStackTrace();
}
per.setName("曹文濤") ; // 設定姓名
per.setAge(26); // 設定年齡
System.out.println(per); // 內容輸出,呼叫toString()
}
};
以上程式會出現錯誤。
所以發現,使用以上的方式實際上還是需要類中的構造方法的支援。
例項:呼叫有參構造方法完成例項化
package org.cwt.demo15.instancedemo ;
import java.lang.reflect.Constructor ; // 匯入反射機制包
class Person{
privateString name ; // name屬性
privateint age ; // age屬性
publicPerson(String name,int age){
this.setName(name);
this.setAge(age);
}
publicvoid setName(String name){
this.name= name ;
}
publicvoid setAge(int age){
this.age= age ;
}
publicString getName(){
returnthis.name ;
}
publicint getAge(){
returnthis.age ;
}
publicString toString(){ // 覆寫toString()方法
return"姓名:" +this.name + ",年齡:" + this.age ;
}
};
public class InstanceDemo03{
publicstatic void main(String args[]){
Class<?>c = null ; // 宣告Class物件
try{
c= Class.forName("org.cwt.demo15.instancedemo.Person") ;
}catch(ClassNotFoundExceptione){
e.printStackTrace();
}
Personper = null ; // 宣告Person物件
Constructor<?>cons[] = null ;
cons= c.getConstructors() ;
try{
per= (Person)cons[0].newInstance("曹文濤",26) ; // 例項化物件
}catch(Exceptione){
e.printStackTrace();
}
System.out.println(per); // 內容輸出,呼叫toString()
}
};
反射應用——取得類的結構
定義操作類Person:
package org.cwt.demo15 ;
interface China{ // 定義China介面
publicstatic final String NATIONAL = "China" ; // 定義全域性常量
publicstatic final String AUTHOR = "曹文濤" ; // 定義全域性常量
publicvoid sayChina() ; // 無參的,沒有返回值的方法
publicString sayHello(String name,int age) ; //定義有兩個引數的方法,並返回內容
}
public class Person implements China{
privateString name ;
privateint age ;
publicPerson(){ // 無參構造
}
publicPerson(String name){
this.name= name ; // 設定name屬性
}
publicPerson(String name,int age){
this(name);
this.age= age ;
}
publicvoid sayChina(){ // 覆寫方法
System.out.println("作者:" + AUTHOR + ",國籍:" + NATIONAL) ;
}
publicString sayHello(String name,int age){
returnname + ",你好!我今年:"+ age + "歲了!" ;
}
publicvoid setName(String name){
this.name= name ;
}
publicvoid setAge(int age){
this.age= age ;
}
publicString getName(){
returnthis.name ;
}
publicint getAge(){
returnthis.age ;
}
};
例項:取得類所實現的全部介面
package org.cwt.demo15.classinfodemo ;
public class GetInterfaceDemo{
publicstatic void main(String args[]){
Class<?>c1 = null ; // 宣告Class物件
try{
c1= Class.forName("org.cwt.demo15.Person") ; // 例項化物件
}catch(ClassNotFoundExceptione){
e.printStackTrace();
}
Class<?>c[] = c1.getInterfaces() ; // 以陣列形式返回實現的全部介面
for(inti=0;i<c.length;i++){
System.out.println("實現的介面名稱:" + c[i].getName()) ; // 輸出介面名稱
}
}
};
例項:取得類所繼承的父類
package org.cwt.demo15.classinfodemo ;
public class GetSuperClassDemo{
publicstatic void main(String args[]){
Class<?>c1 = null ; // 宣告Class物件
try{
c1= Class.forName("org.cwt.demo15.Person") ; // 例項化物件
}catch(ClassNotFoundExceptione){
e.printStackTrace();
}
Class<?>c2 = c1.getSuperclass() ; // 取得父類
System.out.println("父類名稱:" + c2.getName()) ;
}
};
例項:取得類中的全部構造方法
package org.cwt.demo15.classinfodemo ;
import java.lang.reflect.Constructor ; // 匯入構造方法的包
import java.lang.reflect.Modifier ; // 匯入構造方法的包
public class GetConstructorDemo03{
publicstatic void main(String args[]){
Class<?>c1 = null ; // 宣告Class物件
try{
c1= Class.forName("org.cwt.demo15.Person") ; // 例項化物件
}catch(ClassNotFoundExceptione){
e.printStackTrace();
}
Constructor<?>con[] = c1.getConstructors() ; // 取得一個類中的全部構造
for(inti=0;i<con.length;i++){
Class<?>p[] = con[i].getParameterTypes() ; //得到構造方法中的全部引數
System.out.print("構造方法:" ) ; // 輸出構造,直接列印
intmo = con[i].getModifiers() ; // 得到所要的訪問許可權
System.out.print(Modifier.toString(mo)+ " ") ; // 得到修飾符
System.out.print(con[i].getName()); // 取得構造方法的名字
System.out.print("(");
for(intj=0;j<p.length;j++){
System.out.print(p[j].getName()+ " arg" + i) ;
if(j<p.length-1){
//判斷此是否是最後一個引數
System.out.print(","); // 輸出“,”
}
}
System.out.println("){}");
}
}
};
例項:取得類中的方法
package org.cwt.demo15.classinfodemo ;
import java.lang.reflect.Method ; // 匯入構造方法的包
import java.lang.reflect.Modifier ; // 匯入構造方法的包
public class GetMethodDemo{
publicstatic void main(String args[]){
Class<?>c1 = null ; // 宣告Class物件
try{
c1= Class.forName("org.cwt.demo15.Person") ; // 例項化物件
}catch(ClassNotFoundExceptione){
e.printStackTrace();
}
Methodm[] = c1.getMethods() ; // 取得全部方法
for(inti=0;i<m.length;i++){
Class<?>r = m[i].getReturnType() ; // 得到返回值型別
Class<?>p[] = m[i].getParameterTypes() ; // 取得全部引數的型別
intxx = m[i].getModifiers() ; // 得到修飾符
System.out.print(Modifier.toString(xx)+ " ") ; // 輸出修飾符
System.out.print(r+ " ") ;
System.out.print(m[i].getName());
System.out.print("(");
for(intj=0;j<p.length;j++){
System.out.print(p[j].getName()+ " " + "arg" + j) ;
if(j<p.length-1){
System.out.print(",");
}
}
Class<?>ex[] = m[i].getExceptionTypes() ; // 取出異常
if(ex.length>0){
System.out.print(")throws ") ;
}else{
System.out.print(")");
}
for(intj=0;j<ex.length;j++){
System.out.print(ex[j].getName());
if(j<p.length-1){
System.out.print(",");
}
}
System.out.println();
}
}
};
例項:取得類中的屬性
package org.cwt.demo15.classinfodemo ;
import java.lang.reflect.Field ; // 匯入構造方法的包
import java.lang.reflect.Modifier ; // 匯入構造方法的包
public class GetFieldDemo{
publicstatic void main(String args[]){
Class<?>c1 = null ; // 宣告Class物件
try{
c1= Class.forName("org.cwt.demo15.Person") ; // 例項化物件
}catch(ClassNotFoundExceptione){
e.printStackTrace();
}
{ // 本類屬性
Fieldf[] = c1.getDeclaredFields() ; // 取得本類中的屬性
for(inti=0;i<f.length;i++){
Class<?>r = f[i].getType() ; // 得到屬性型別
intmo = f[i].getModifiers() ; // 得到修飾符的數字
Stringpriv = Modifier.toString(mo) ; // 還原修飾符
System.out.print("本類屬性:") ;
System.out.print(priv+ " ") ;
System.out.print(r.getName()+ " ") ; // 得到屬性型別
System.out.print(f[i].getName()); // 輸出屬性名稱
System.out.println(";") ;
}
}
{ // 公共屬性
Fieldf[] = c1.getFields() ; // 取得本類中的公共屬性
for(inti=0;i<f.length;i++){
Class<?>r = f[i].getType() ; // 得到屬性型別
intmo = f[i].getModifiers() ; // 得到修飾符的數字
Stringpriv = Modifier.toString(mo) ; // 還原修飾符
System.out.print("公共屬性:") ;
System.out.print(priv+ " ") ;
System.out.print(r.getName()+ " ") ; // 得到屬性型別
System.out.print(f[i].getName()); // 輸出屬性名稱
System.out.println(";") ;
}
}
}
};
Java反射機制的深入研究
通過反射呼叫類中的方法:在正常情況下一個類的反射功能產生之後,就可以直接呼叫類中的方法了,如果要想呼叫的話,則必須知道方法名稱是什麼,之後通過Class類中的方法呼叫。
定義操作類:
package org.cwt.demo15 ;
interface China{ // 定義China介面
publicstatic final String NATIONAL = "China" ; // 定義全域性常量
publicstatic final String AUTHOR = "曹文濤" ; // 定義全域性常量
publicvoid sayChina() ; // 無參的,沒有返回值的方法
publicString sayHello(String name,int age) ; //定義有兩個引數的方法,並返回內容
}
public class Person implements China{
privateString name ;
privateint age ;
publicPerson(){ // 無參構造
}
publicPerson(String name){
this.name= name ; // 設定name屬性
}
publicPerson(String name,int age){
this(name);
this.age= age ;
}
publicvoid sayChina(){ // 覆寫方法
System.out.println("作者:" + AUTHOR + ",國籍:" + NATIONAL) ;
}
publicString sayHello(String name,int age){
returnname + ",你好!我今年:"+ age + "歲了!" ;
}
publicvoid setName(String name){
this.name= name ;
}
publicvoid setAge(int age){
this.age= age ;
}
publicString getName(){
returnthis.name ;
}
publicint getAge(){
returnthis.age ;
}
};
例項操作:
package org.cwt.demo15.invokedemo ;
import java.lang.reflect.Method ;
public class InvokeSayHelloDemo{
publicstatic void main(String args[]){
Class<?>c1 = null ;
try{
c1= Class.forName("org.cwt.demo15.Person") ; // 例項化Class物件
}catch(Exceptione){}
try{
Method met =c1.getMethod("sayHello",String.class,int.class) ; // 找到sayChina()方法
Stringrv = null ;
rv= (String)met.invoke(c1.newInstance(),"曹文濤",26) ; // 呼叫方法
System.out.println(rv);
}catch(Exceptione){
e.printStackTrace();
}
}
};
通過反射呼叫setter及getter
setter及getter方法是一個標準的屬性的訪問方法,如果一個類的屬性被封裝,則必須通過setter及getter方法設定和取得,實際上此方法的操作之所以這樣規定,主要原因就是由於反射機制可以給予支援。
例項:通過反射呼叫setter及getter方法
package org.cwt.demo15.invokedemo ;
import java.lang.reflect.Method ;
public class InvokeSetGetDemo{
publicstatic void main(String args[]){
Class<?>c1 = null ;
Objectobj = null ;
try{
c1= Class.forName("org.cwt.demo15.Person") ; // 例項化Class物件
}catch(Exceptione){}
try{
obj= c1.newInstance() ;
}catch(Exceptione){}
setter(obj,"name","曹文濤",String.class) ; // 呼叫setter方法
setter(obj,"age",26,int.class); // 呼叫setter方法
System.out.print("姓名:") ;
getter(obj,"name");
System.out.print("年齡:") ;
getter(obj,"age");
}
/**
Objectobj:要操作的物件
Stringatt:要操作的屬性
Objectvalue:要設定的屬性內容
Class<?>type:要設定的屬性型別
*/
publicstatic void setter(Object obj,String att,Object value,Class<?> type){
try{
Methodmet = obj.getClass().getMethod("set"+initStr(att),type) ; // 得到setter方法
met.invoke(obj,value); // 設定setter的內容
}catch(Exceptione){
e.printStackTrace();
}
}
publicstatic void getter(Object obj,String att){
try{
Methodmet = obj.getClass().getMethod("get"+initStr(att)) ; // 得到setter方法
System.out.println(met.invoke(obj)); // 呼叫getter取得內容
}catch(Exceptione){
e.printStackTrace();
}
}
publicstatic String initStr(String old){ // 將單詞的首字母大寫
Stringstr = old.substring(0,1).toUpperCase() + old.substring(1) ;
returnstr ;
}
};
通過反射呼叫屬性
如果要操作一個類中的屬性,則也可以通過Filed完成:
package org.cwt.demo15.invokedemo ;
import java.lang.reflect.Field ;
public class InvokeFieldDemo{
publicstatic void main(String args[]) throws Exception{
Class<?>c1 = null ;
Objectobj = null ;
c1= Class.forName("org.cwt.demo15.Person") ; // 例項化Class物件
obj= c1.newInstance() ;
FieldnameField = null ;
FieldageField = null ;
nameField= c1.getDeclaredField("name") ; //取得name屬性
ageField= c1.getDeclaredField("age") ; //取得name屬性
nameField.setAccessible(true); // 此屬性對外部可見
ageField.setAccessible(true); // 此屬性對外部可見
nameField.set(obj,"曹文濤") ; // 設定name屬性內容
ageField.set(obj,26); // 設定age屬性內容
System.out.println("姓名:" + nameField.get(obj)) ;
System.out.println("年齡:" + ageField.get(obj)) ;
}
};
通過反射運算元組
例項:
package org.cwt.demo15.invokedemo ;
import java.lang.reflect.Array ;
public class ClassArrayDemo{
publicstatic void main(String args[]) throws Exception{
inttemp[] = {1,2,3} ;// 宣告一整型陣列
Class<?>c = temp.getClass().getComponentType() ; //取得陣列的Class物件
System.out.println("型別:" + c.getName()) ; // 取得陣列型別名稱
System.out.println("長度:" + Array.getLength(temp)) ;
System.out.println("第一個內容:" + Array.get(temp,0)) ;
Array.set(temp,0,6);
System.out.println("第一個內容:" + Array.get(temp,0)) ;
}
};
例項:通過反射實現對陣列中元素的操作
package org.cwt.demo15.invokedemo ;
import java.lang.reflect.Array ;
public class ChangeArrayDemo{
publicstatic void main(String args[]) throws Exception{
inttemp[] = {1,2,3} ;// 宣告一整型陣列
intnewTemp[] = (int []) arrayInc(temp,5) ; //重新開闢空間5
print(newTemp);
System.out.println("\n-------------------------");
Stringt[] = {"cwt","mldn","mldnjava"} ;
Stringnt[] = (String [])arrayInc(t,8) ;
print(nt);
}
publicstatic Object arrayInc(Object obj,int len){
Class<?>c = obj.getClass() ;
Class<?>arr = c.getComponentType() ; // 得到陣列的
ObjectnewO = Array.newInstance(arr,len) ; // 開闢新的大小
intco = Array.getLength(obj) ;
System.arraycopy(obj,0,newO,0,co); // 拷貝內容
returnnewO ;
}
publicstatic void print(Object obj){ // 陣列輸出
Class<?>c = obj.getClass() ;
if(!c.isArray()){ // 判斷是否是陣列
return;
}
Class<?>arr = c.getComponentType() ;
System.out.println(arr.getName()+"陣列的長度是:" +Array.getLength(obj)) ; // 輸出陣列資訊
for(inti=0;i<Array.getLength(obj);i++){
System.out.print(Array.get(obj,i)+ "、") ; // 通過Array輸出
}
}
};
動態代理
代理設計:一個操作的介面有兩個子類,其中一個是真實操作的實現類,另外一個是代理類,代理類實現類要完成比真實操作類更多的內容。
例項:通過Proxy類、類載入器完成動態代理
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy ;
import java.lang.reflect.Method ;
interface Subject{
publicString say(String name,int age) ; //定義抽象方法say
}
class RealSubject implements Subject{ // 實現介面
publicString say(String name,int age){
return"姓名:" +name + ",年齡:" +age ;
}
};
class MyInvocationHandler implementsInvocationHandler{
privateObject obj ;
publicObject bind(Object obj){
this.obj= obj ; // 真實主題類
returnProxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),this);
}
publicObject invoke(Object proxy,Method method,Object[] args) throws Throwable{
Objecttemp = method.invoke(this.obj,args) ; //呼叫方法
returntemp ;
}
};
public class DynaProxyDemo{
publicstatic void main(String args[]){
Subjectsub = (Subject)new MyInvocationHandler().bind(new RealSubject()) ;
Stringinfo = sub.say("曹文濤",26) ;
System.out.println(info);
}
};
工廠設計模式
例項:簡單的工廠設計
package org.cwt.demo15.factorydemo01 ;
interface Fruit{
publicvoid eat() ; // 吃水果
}
class Apple implements Fruit{
publicvoid eat(){ // 覆寫eat()方法
System.out.println("**吃蘋果");
}
};
class Orange implements Fruit{
publicvoid eat(){
System.out.println("**吃橘子") ;
}
};
class Factory{
publicstatic Fruit getInstance(String className){
Fruitfruit = null ;
try{
fruit= (Fruit)Class.forName(className).newInstance() ;
}catch(Exceptione){
e.printStackTrace();
}
returnfruit ;
}
};
public class FactoryDemo01{
publicstatic void main(String args[]){
Fruitf = Factory.getInstance("org.cwt.demo15.factorydemo01.Apple") ;
if(f!=null){
f.eat();
}
}
};
例項:通過反射完成工廠設計
package org.cwt.demo15.factorydemo02 ;
import java.util.Properties ;
import java.io.File ;
import java.io.FileOutputStream ;
import java.io.FileInputStream ;
interface Fruit{
publicvoid eat() ; // 吃水果
}
class Apple implements Fruit{
publicvoid eat(){ // 覆寫eat()方法
System.out.println("**吃蘋果");
}
};
class Orange implements Fruit{
publicvoid eat(){
System.out.println("**吃橘子") ;
}
};
class Init{
publicstatic Properties getPro(){
Propertiespro = new Properties() ;
Filef = new File("d:\\fruit.properties") ; // 找到屬性檔案
try{
if(f.exists()){ // 檔案存在
pro.load(newFileInputStream(f)) ; // 讀取屬性
}else{
pro.setProperty("apple","org.cwt.demo15.factorydemo02.Apple");
pro.setProperty("orange","org.cwt.demo15.factorydemo02.Orange");
pro.store(newFileOutputStream(f),"FRUIT CLASS") ;
}
}catch(Exceptione){}
returnpro ;
}
};
class Factory{
publicstatic Fruit getInstance(String className){
Fruitfruit = null ;
try{
fruit= (Fruit)Class.forName(className).newInstance() ;
}catch(Exceptione){
e.printStackTrace();
}
returnfruit ;
}
};
public class FactoryDemo02{
publicstatic void main(String args[]){
Propertiespro = Init.getPro() ;
Fruitf = Factory.getInstance(pro.getProperty("apple")) ;
if(f!=null){
f.eat();
}
}
};
其中要建立配置檔案:
fruit.properties:
apple = org.cwt.demo15.factorydemo02.Apple orange = org.cwt.demo15.factorydemo02.Orange |