靜態: 事先約定的規則, 執行期間按照固定規則執行.java
動態: 事先沒有約定, 在執行期間動態肯定執行規則.spring
JAVA 中的靜態執行: 編譯已經就肯定執行規則(執行次序), 在運行期間按照編譯結果順序執行.緩存
Foo foo = new Foo(); foo.hello();
JAVA 中的動態執行: 運行期間才能肯定加載哪些類, 建立哪些對象, 執行哪些方法...eclipse
Java 提供了動態加載類的APIide
Class cls=Class.forName(類名);
如:
Class cls=Class.forName("demo.Foo");
案例:測試
Scanner in= new Scanner(System.in); System.out.print("輸入類名:"); String className=in.nextLine(); //動態加載類 Class cls=Class.forName(className); System.out.println(cls);
語法
spa
Object obj = cls.newInstance();
執行cls引用的類信息中的無參數構造器, 動態建立實例. 若是類沒有無參數構造器, 則拋出異常!3d
提示: 反射能夠調用有參數構造器.code
案例:xml
Scanner in= new Scanner(System.in); System.out.print("輸入類名:"); String className=in.nextLine(); //動態加載類 Class cls=Class.forName(className); System.out.println(cls); //動態建立對象 Object obj = cls.newInstance(); System.out.println(obj);
發射API提供了動態獲取類中方法信息的API:
Method[] ary= cls.getDeclaredMethods();
案例:
Scanner in= new Scanner(System.in); System.out.print("輸入類名:"); String className=in.nextLine(); //動態加載類 Class cls=Class.forName(className); System.out.println(cls); //動態獲取類的方法信息 //從cls表明的類信息中獲取所有的方法信息 Method[] ary= cls.getDeclaredMethods(); //天天一個Method表明一個方法信息 //方法的全部要素都在這個對象中 for (Method method : ary) { System.out.println(method); }
Method提供了獲取方法詳細信息的方法:
//獲取方法名 String name = method.getName(); //獲取返回值類型 Class type = method.getReturnType();
案例:
Scanner in= new Scanner(System.in); System.out.print("輸入類名:"); String className=in.nextLine(); //動態加載類 Class cls=Class.forName(className); System.out.println(cls); //動態獲取類的方法信息 //從cls表明的類信息中獲取所有的方法信息 Method[] ary= cls.getDeclaredMethods(); //天天一個Method表明一個方法信息 //方法的全部要素都在這個對象中 for (Method method : ary) { System.out.println(method); //獲取方法的詳細信息: System.out.println( method.getName()); System.out.println( method.getReturnType()); String name=method.getName(); //檢查一個字符串是否以test爲開頭 if(name.startsWith("test")){ System.out.println("找到了"); } }
invoke: 調用 method: 方法
語法:
method.invoke(執行方法的對象, 傳遞的參數) //正確的狀況 購買飲料.invoke(小賣鋪, 錢) //錯誤的狀況 購買飲料.invoke(達內前臺, 錢)
必須在對象上執行一個非靜態方法, 調用方法時候必須有對象.
在invoke方法執行時候, 必須傳遞包含當前方法的對象!!!
案例:
業務需求: 執行某個類中所有的以test爲開頭的無參數無返回值的非靜態方法.
//動態加載類 Scanner in= new Scanner(System.in); System.out.print("輸入類名:"); String className=in.nextLine(); Class cls=Class.forName(className); //動態獲取所有方法信息 Method[] ary= cls.getDeclaredMethods(); //迭代所有方法查找以test爲開頭的方法 Object obj = cls.newInstance();//""; for (Method method : ary) { if(method.getName() .startsWith("test")){ System.out.println(method); //動態執行方法 method.invoke(obj); } }
使用invoke
Object obj=
method.invoke(對象, 參數1, 參數2...)
invoke 方法有返回值, 返回被調用方法執行的結果, 對象後面參數是執行方法時候傳遞的參數.
invoke 能夠調用私有方法.
案例:
//動態加載類 Scanner in = new Scanner(System.in); System.out.print("輸入類名:"); String className=in.nextLine(); Class cls = Class.forName(className); //1. 找到demo方法 // Class 提供了根據方法簽名找到指定 // 方法信息的API String name="demo";//方法名 //類型列表 Class[] // String.class 表示字符串的類型 // int.class 表示int類型 // 任何.class 表示任何的類型 Class[] types={String.class,int.class}; //根據方法簽名在cls查找方法信息 Method method= cls.getDeclaredMethod(name, types); //找到了私有方法 System.out.println(method); //執行私有方法 //打開方法的執行權限!!!違反封裝! method.setAccessible(true); Object obj = cls.newInstance(); Object value= method.invoke(obj, "Tom", 12); System.out.println(value);
@Retention(RetentionPolicy.RUNTIME) public @interface Demo { } public class TestCase { public void test(){ System.out.println("test"); } @Demo public void hello(){ System.out.println("Hello"); } @Demo public void helloKitty(){ System.out.println("Hello Kitty"); } } /* * 動態執行一個類中所有以@Demo註解標註的方法 */ public class Demo05 { public static void main(String[] args) throws Exception{ //動態加載類 //動態獲取所有方法 //動態檢查方法的註解信息 Scanner in=new Scanner(System.in); System.out.print("類名:"); String className=in.nextLine(); Class cls = Class.forName(className); Method[] ary= cls.getDeclaredMethods(); Object obj = cls.newInstance(); for (Method method : ary) { //檢查一個方法的註解信息 //method.getAnnotation(被檢查的註解類型) //返回註解類型對象, 若是爲空表示沒有註解 //不爲空表示找到了被檢查的註解Annotation Demo ann=method.getAnnotation( Demo.class); System.out.println(method); System.out.println(ann); if(ann!=null){ method.invoke(obj); } } } }
代碼:
public class ApplicationContext { //是緩存Spring容器的Bean對象 private Map<String, Object> beans= new HashMap<String, Object>(); /** * 利用配置文件初始化當前容器 * 利用xml配置文件, 初始化所有的Bean對象 */ public ApplicationContext(String xml) throws Exception{ //利用DOM4j, 讀取XML文件 //解析XML文件內容, 獲得Bean的類名 //和Bean的ID: // 根據類名動態加載類而且建立對象 // 將對象和對應的ID添加到map中 //從 Resource(classpath) 中讀取流 InputStream in=getClass() .getClassLoader() .getResourceAsStream(xml); SAXReader reader=new SAXReader(); Document doc=reader.read(in); in.close(); //解析xml :<beans><bean><bean>.... Element root=doc.getRootElement(); //讀取根元素中所有的bean子元素 List<Element> list= root.elements("bean"); for (Element e : list) { //e 就是 bean 元素 id屬性和class屬性 String id=e.attributeValue("id"); String className= e.attributeValue("class"); //動態加載類, 動態建立對象 Class cls=Class.forName(className); Object bean=cls.newInstance(); beans.put(id, bean); } } public Object getBean(String id){ //根據id在map查找對象, 並返回對象 return beans.get(id); } //泛型方法: 優勢是能夠減小一次類型轉換 public<T> T getBean( String id, Class<T> cls){ return (T)beans.get(id); } } <?xml version="1.0" encoding="UTF-8"?> <beans> <bean id="foo" class="demo.Foo"></bean> <bean id="date" class="java.util.Date"></bean> <bean id="testCase" class="demo.TestCase"></bean> </beans> public class Demo06 { public static void main(String[] args) throws Exception { ApplicationContext ctx= new ApplicationContext( "spring-context.xml"); Foo foo = (Foo)ctx.getBean("foo"); Foo f2 = ctx.getBean( "foo", Foo.class); System.out.println(foo); System.out.println(f2); } }