異常,簡單來講,就是一個程序執行過程當中發生的不正常狀況的事件。它發生在程序的運行期間,干擾了正常的指令流程。若是沒有處理異常,那麼出現異常以後,程序會中止運行。異常分爲運行異常和非運行異常。非運行異常也叫編譯異常。對於編譯異常編譯器要求必須處理。不然沒法運行。運行時異常編譯器不要求強制處理。運行時異常通常是由程序邏輯錯誤引發的,程序應該從邏輯角度儘量避免這類異常的發生。它們都繼承於Exception類。運行異常和非運行異常也下分各種異常。異常發生的緣由是程序錯誤或偶然的外在因素致使的通常性問題。html
繼承關係如圖java
若是一個方法內拋出異常,該異常會被拋到調用方法中。若是異常沒有在調用方法中處理,它繼續被拋給這個方法的調用者。這個過程將一直繼續下去,直到異常被處理。這一過程稱爲捕獲異常。api
在運行狀態中,對於任意一個類,都可以知道這個類的全部屬性和方法;框架
對於任意一個對象,都可以調用它的任意一個方法和屬性;ide
這種動態獲取的信息以及動態調用對象的方法的功能稱爲java語言的反射機制。函數
反射的思惟導圖以下工具
當使用反射時候,首先須要獲取到Class類的對象,獲得了這個類以後,就能夠獲得class文件裏面的全部內容。google
如下是具體的反射應用方式spa
Person類是一個普通的實體類,裏面包含三個私有的成員屬性及它們的Set和Get函數。Map是集合框架裏使用的Map類型框架,裏面能夠加入泛型。具體轉換代碼以下3d
1 //param1:要轉化的數據類型Person.class String.class 2 public static Object toBean(Class<?> type,Map<String,? extends Object> map) throws Exception{ 3 4 //Introspector專門處理Bean的工具類。好比獲取Class的屬性或者方法或構造 5 BeanInfo beanInfo = Introspector.getBeanInfo(type);//參數傳遞的就是類的類型 6 //調用newInstance方法建立這個類 7 Object o = type.newInstance(); 8 //獲取o的方法 9 PropertyDescriptor[] ps = beanInfo.getPropertyDescriptors(); 10 for (int i = 0; i < ps.length; i++) { 11 12 PropertyDescriptor p = ps[i]; 13 //獲取方法描述的名稱(屬性名稱)若是是Person --->name(name,age,sex) 14 String name = p.getName(); 15 //name是否就是map中的key? 16 if(map.containsKey(name)){ 17 //經過key獲取map的值 18 Object value = map.get(name); 19 //經過反射,value賦給o 20 //p.getWriteMethod();//set方法 21 //p.getReadMethod();//get方法 22 p.getWriteMethod().invoke(o, value); 23 } 24 } 25 //獲取map中的key的值,以及value的值 26 return o; 27 } 28 public static void main(String[] args) throws Exception { 29 Map pMap = new HashMap(); 30 pMap.put("name", "張三"); 31 pMap.put("age", 1); 32 pMap.put("sex", 2); 33 //Map--->Object 34 Person p = new Person("張三"); 35 p.setAge(1); 36 p.setSex(2); 37 Person o = (Person)toBean(Person.class,pMap); 38 System.out.println(" "+o.toString()); 39 }
以上代碼的思想就是,建立一個相對於想要的類的BeanInfo,而後經過這個BeanInfo對象獲得全部的屬性名稱(對應到Map裏就是全部鍵值對的鍵),而後判斷Map裏是否有與獲取的鍵名稱同名的鍵,若是有的話就經過Map獲取那個鍵的值,而後經過PropertyDescriptor對象獲取須要的對象的set方法,將值賦值給相應的屬性,最後返回相應的類型的對象。
1>直接用new調用該類的構造函數
new Person("張三");
2>使用class類中的newInstance方法建立對象,調用構造函數
1 public static void test1() throws ClassNotFoundException, InstantiationException, IllegalAccessException{ 2 //一、獲取Class類的對象 3 Class c = Class.forName("com.Person"); 4 //二、經過Class類中的newInstance方法建立Person對象 5 Person p = (Person)c.newInstance(); 6 //三、檢測一下 7 p.setName("張三"); 8 System.out.println(p.getName()); 9 }
3>使用class類型中的構造函數中的newInstance方法
public static void test2() throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{ //一、獲取Person類型 Constructor c = Person.class.getConstructor(); //二、建立方法 Person p = (Person)c.newInstance(); //三、檢測 p.setName("張三"); System.out.println(p.getName()); }
4>經過clone方法建立。前提是須要在實體類裏重寫clone()方法
/** *實體類 **/
public class Person implements Cloneable{ private String name; private int age; private int sex; @Override protected Person clone() throws CloneNotSupportedException { Person person = null; person = (Person)super.clone(); return person; } } /** *功能類中clone功能函數 **/
public static void test3(){ //須要重寫clone方法,重寫cloneable接口。很是特殊 //在Person類裏實現cloneable接口
Person p1 =new Person("王五"); //調用clone方法建立一個新的對象p2
Person p2 = null; try { p2 = p1.clone(); } catch (CloneNotSupportedException e) { // TODO Auto-generated catch block
e.printStackTrace(); } System.out.println(p1==p2); }
5>序列化和反序列化的方法,經過這種方法能夠將對象轉換爲字節序列的方式,把對象傳輸到另外一臺機器上。
1>經過反射獲取方法
經過反射獲取方法的方式是先申明一個Class對象,而後經過該對象的getDeclaredMethod方法建立Method對象,經過Method對象的invoke方法調用獲取到的方法實現功能。具體示例代碼以下
1 public static void test5() { 2 try { 3 Class c = Class.forName("com.hpe.ref.Person"); 4 //獲取方法 Person setName getName 5 //param1:方法名的String類型 6 //param2:方法的參數類型 7 Method m = c.getDeclaredMethod("setName", String.class); 8 //建立Object對象 9 Object obj = c.newInstance(); 10 //invoke調用方法(反射的方式調用方法) 11 //param1:反射的類,param2:m方法的值 12 m.invoke(obj, "張三"); 13 //驗證 14 Method gM =c.getDeclaredMethod("getName"); 15 System.out.println(gM.invoke(obj)); 16 } catch (Exception e) { 17 // TODO Auto-generated catch block 18 e.printStackTrace(); 19 } 20 }
2>經過反射獲取屬性
經過反射獲取屬性的方法是經過Class獲取該對象的Class對象形式,以後經過Field以字符串的形式獲取類中的屬性,而後經過Field對象來操做該屬性。具體代碼以下。
public static void test4(){ //經過反射,在運行階段建立這個person對象 try { Class c = Class.forName("com.hpe.ref.Person"); Field field = c.getDeclaredField("name"); //經過字符串的形式獲取類中的屬性。 Field[] fs = c.getDeclaredFields(); //設置對屬性,若是是私有的,能夠有權限訪問 field.setAccessible(true); Object o =c.newInstance(); //set方法----操做屬性的方式 field.set(o, "張三"); System.out.println(field.get(o)); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (NoSuchFieldException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InstantiationException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } }
這段代碼的功能分析
public int indexOf(int ch)
返回指定字符第一次出現的字符串內的索引。 若是與值的字符ch在此表示的字符序列發生String第一事件發生之對象,則索引(在Unicode代碼單元)被返回。
public StringBuffer insert(int offset, char c)
在此序列中插入char參數的字符串表示形式。
整體效果就好像第二個參數經過方法String.valueOf(char)轉換爲一個字符串,而且該字符串中的字符而後是inserted到指定的偏移量的這個字符序列。
offset參數必須大於或等於0 ,小於或等於該序列的length 。
因此它的功能是,以小數點爲界,每往前數三位,就在str字符串裏插入一個逗號。以達到計算數字的位數效果。