1. 程式人生 > >Java 基礎 反射機制

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