1. 程式人生 > >Java基礎知識隨意記錄

Java基礎知識隨意記錄

reflect java框架 ann 類庫 nts 名稱 不同的 打印機 row

多態:

首先明確一點我們在這裏只考慮運行時多態,而不考慮編譯時多態(方法重載)。因此下列多態默認都是指運行時多態。 多態是面向對象編程裏面的概念,一個接口的多種不同的實現方式,即為多態。註意這裏的接口,不應理解得太死板,比如在java裏面,繼承一個類和實現一個接口本質上都是一種繼承行為,因此都應該理解為多態的體現。 在計算機的世界裏,尤其是編程的世界裏,多態體現在:只有在運行的時候才知道引用變量所指向的具體實例對象。且有三個必要的條件: 繼承
重寫/實現
父類引用指向子類對象
多態的概念來源於生活,生活中的很多現象都是多態的體現,例如打印機,打印功能可以打印黑白色也可以打印彩色。同一款汽車可以用2.0l排量也可以有1.0l的排量。
多態的技術帶來的一個重要影響是:由於一個借口可能有多個實現,而每個實現之間的大小,規模,是不一樣的。因此多態對內存的分配是有影響的,不同的實現會有不同的內存分配. 這一點與現實世界的多態例子相比就會非常有意思,第一,我們會發現軟件裏的多態是動態的多態,而現實世界裏的多態大部分是一個預先設定好的多態體現,現實裏的多態更多的類似於編譯時多態,即方法重載,例如打印機的例子。 多態通常有兩種實現方法:
  1. 子類繼承父類(extends)
  2. 類實現接口(implements)
核心之處就在於對父類方法的改寫或對接口方法的實現,以取得在運行時不同的執行效果。要使用多態,在聲明對象時就應該遵循一條法則:聲明的總是父類類型或接口類型,而創建的是實際類型.
以ArrayList為例子,要使用多態的特性,要按照如下方式定義 List list = new ArrayList(); 此外,在定義方法參數時也通常總是應該優先使用父類類型或接口類型,例如: public void test(List list); 這樣聲明最大的好處在於它的靈活性,假如某一天ArrayList無法滿足要求,我們希望用LinkedList來代替它,那麽只需要在對象創建的地方把new ArrayList()改為new LinkedList即可,其它代碼一概不用改動。 ---------------------------不定時增加------------------------

反射 :

定義如下:java程序在運行狀態中,對於任意一個類,都能夠在運行時知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意方法和屬性;這種動態獲取信息以及動態調用對象方法的功能稱為java語言的反射機制。

問題1:什麽叫獲取一個方法,什麽叫獲取一個屬性? 這是一個很好的問題,理解了這個問題之後也就不會覺得反射過於抽象了。java當中提供了專門的方法的抽象Method類和專門的屬性的抽象Field類,以及專門的所有類的抽象Class類,並提供了一系列的方法,來幫助我們獲取一個類的屬性和方法。獲取到的屬性和方法,將以普通對象的方式存在。與我們自己寫的類並無任何區別。下面是一個代碼例子: public class MethodClass { public static void main(String[] args) throws Exception { //1.獲取Class對象 Class xxxClass = Class.forName("com.XXX.XXX"); //2.獲取所有公有方法 Method[] methodArray = xxxClass .getMethods(); //3.獲取字段 Field[] fieldArray = xxxClass .getFields(); }} 反射原理: Class類與java.lang.reflect庫一起對反射的概念提供了技術支持。java.lang.reflect類庫包含了Field類,Method類以及Constructor類。這些類用來表示未知類裏對應的成員。Class類提供了獲取getFields()、getMethods()和getConstructors()等方法,而這些方法的返回值類型就定義在java.lang.reflect當中。 如果不知道某個對象的確切類型(即list引用到底是ArrayList類型還是LinkedList類型),RTTI可以告訴你,但是有一個前提:這個類型在編譯時必須已知,這樣才能使用RTTI來識別它。 要想理解反射的原理,必須要結合類加載機。反射機制並沒有什麽神奇之處,當通過反射與一個未知類型的對象打交道時,JVM只是簡單地檢查這個對象,看它屬於哪個特定的類,然後再通過拿到的某一個類的全限定名去找這個類的Class文件 。因此,那個類的.class對於JVM來說必須是可獲取的,要麽在本地機器上,要麽從網絡獲取。所以對於RTTI和反射之間的真正區別只在於: RTTI,編譯器在編譯時打開和檢查.class文件
反射,運行時打開和檢查.class文件
對於反射機制而言.class文件在編譯時是不可獲取的,所以是在運行時獲取和檢查.class文件。 總結起來說就是,反射是通過Class類和java.lang.reflect類庫一起支持而實現的,其中每一個Class類的對象都對應了一個類,這些信息在編譯時期就已經被存在了.class文件裏面了,Class 對象是在加載類時由 Java 虛擬機以及通過調用類加載器中的defineClass方法自動構造的。對於我們定義的每一個類,在虛擬機中都有一個應的Class對象。 那麽在運行時期,無論是通過字面量還是forName方法獲取Class對象,都是去根據這個類的全限定名(全限定名必須是唯一的,這也間接回答了為什麽類名不能重復這個問題。)然後獲取對應的Class對象 總結: java虛擬機幫我們生成了類的class對象,而通過類的全限定名,我們可以去獲取這個類的字節碼.class文件,然後再獲取這個類對應的class對象,再通過class對象提供的方法結合類Method,Filed,Constructor,就能獲取到這個類的所有相關信息. 獲取到這些信息之後,就可以使用Constructor創建對象,用get和set方法讀取和修改與Field對象相關的字段,用invoke方法調用與Method對象關聯的方法。 反射機制非常重要,應用也非常之廣泛。在使用反射時,我們的代碼裏面可以出現任何一個具體的構造器,字段信息,方法,但是卻能動態的生成對象,調用他們的方法,這是一個非常通用的功能,由此帶來的價值也是驚人的。反射比較出名的應用有: 1. Spring/Mybatis等框架,行內有一句這樣的老話:反射機制是Java框架的基石。最經典的就是xml的配置模式。 2. JDBC 的數據庫的連接 3. 動態生成對象,應用於工廠模式中. spring的bean容器也就是一個工廠 4. jdk動態代理 利用反射獲取傳入接口的實現類 5. 註解機制的實現 利用反射可以獲取每一個filed,Filed類提供了getDeclaredAnnotations方法以數組形式返回這個字段所有的註解.... 6. 編輯器代碼自動提示的實現 等等

反射樣例:

反射應用實例 下面的代碼是使用反射獲取方法的例子程序 model類 package com.dr.Reflection.getMethodByReflect; public class Student { //**************成員方法***************// public void show1(String s) { System.out.println("調用了:公有的,String參數的show1(): s = " + s); } protected void show2() { System.out.println("調用了:受保護的,無參的show2()"); } void show3() { System.out.println("調用了:默認的,無參的show3()"); } private String show4(int age) { System.out.println("調用了,私有的,並且有返回值的,int參數的show4(): age = " + age); return "abcd"; } } 測試類 package com.dr.Reflection.getMethodByReflect;import java.lang.reflect.Method; public class MethodClass { public static void main(String[] args) throws Exception { //1.獲取Class對象 Class stuClass = Class.forName("com.dr.Reflection.getMethodByReflect.Student"); //2.獲取所有公有方法 System.out.println("***************獲取所有的”公有“方法*******************"); stuClass.getMethods(); Method[] methodArray = stuClass.getMethods(); for(Method m : methodArray){ /* 註意,這裏雖然student類自身只寫了一個public方法,但是由於java所有的類都繼承於object類,因此object類中所有的public方法也會被打印出來 */ System.out.println(m); } System.out.println("***************獲取所有的方法,包括私有的*******************"); methodArray = stuClass.getDeclaredMethods(); for(Method m : methodArray) { //不包含父類的,僅僅是這個自身定義的方法 System.out.println(m); } System.out.println("***************獲取公有的show1()方法*******************"); Method m = stuClass.getMethod("show1", String.class); //根據方法名稱,以及參數,獲取方法對象 System.out.println(m); //實例化一個Student對象 Object obj = stuClass.getConstructor().newInstance(); m.invoke(obj, "劉德華"); System.out.println("***************獲取私有的show4()方法******************"); m = stuClass.getDeclaredMethod("show4", int.class); System.out.println(m); m.setAccessible(true);//解除私有限定 Object result = m.invoke(obj, 20); //需要兩個參數,一個是要調用的對象(獲取有反射),一個是實參 System.out.println("返回值:" + result); } }

Java基礎知識隨意記錄