1. 靜態導入和自動裝箱拆箱
(1).靜態導入: 導入java里面類的靜態成員 import static 包名 類名 靜態屬性/靜態方法/*
(2).自動裝箱拆箱:
自動裝箱:把基本數據類型賦值給對應的包裝類(對象)
自動拆箱:把包裝類的對象賦值給對應的基本數據類型
1 package com.study.lgs; 2 import static java.lang.System.out; 3 4 import java.util.ArrayList; 5 import java.util.Iterator; 6 import java.util.List; 7 public class ZhuangXiangChaiXiang { 8 9 public static void main(String[] args) { 10 // TODO Auto-generated method stub 11 //1、靜態導入 12 //out.println("aaa"); 13 14 //2.自動裝箱拆箱: 15 Integer i=1;//自動裝箱 jdk1.5+才能這樣寫 否則這樣寫:Integer i=new Integer(1) 16 int j=i;//自動拆箱 17 18 //3.自動裝箱拆箱的典型應用 19 List l=new ArrayList(); 20 l.add(1);//裝箱 把對象1裝到list對象l里面去 21 l.add(2); 22 l.add(3); 23 24 //迭代器遍歷輸出 25 Iterator k=l.iterator(); 26 while(k.hasNext()){ 27 int j1=(Integer)k.next(); 28 out.println(j1); 29 30 31 } 32 /*ArrayList<Integer> al=new ArrayList<Integer>(); 33 al.add(1); 34 al.add(2); 35 al.add(3); 36 for(Integer k:al){ 37 out.println(k); 38 }*/ 39 } 40 41 }
2. 增強for循環
用途:遍歷數組或者遍歷實現Iterable泛型接口的集合
1 package cn.study.lgs; 2 import static java.lang.System.out; 3 4 import java.util.ArrayList; 5 import java.util.HashMap; 6 import java.util.Iterator; 7 import java.util.List; 8 import java.util.Map; 9 import java.util.Map.Entry; 10 import java.util.Set; 11 12 import org.junit.Test; 13 14 public class StrongFor { 15 16 @Test 17 public void test1(){ 18 //1、遍歷數組 19 int i[]={1,2,3}; 20 for(int k:i){ 21 out.println(k); 22 } 23 } 24 @Test 25 public void test2(){ 26 //2、遍歷集合 27 List l=new ArrayList(); 28 l.add(1); 29 l.add(2); 30 l.add(3); 31 // l.add("aaa"); 32 33 for(Object o:l){ 34 // out.println(o); //不用包裝直接以對象的形式輸出 也可以 35 int i=(Integer) o; 36 out.println(i); 37 } 38 } 39 @Test 40 public void testMap(){ 41 Map m=new HashMap(); 42 m.put("1", "aaa"); 43 m.put("2", "bbb"); 44 m.put("3", "ccc"); 45 //1、傳統方案取出Map里面的值 1 46 Set s=m.keySet();//通過keyset方法把map里面的每個key存到s里面去 47 Iterator i=s.iterator();//迭代遍歷s里面的key值 48 while(i.hasNext()){ 49 // String key=(String) i.next(); 50 // String value=(String) m.get(key); 51 // out.println(key+"對應的值為:"+value); 52 String st=(String) i.next(); 53 System.out.println(st+ "對應的值為"+m.get(st)); 54 55 // System.out.println(i.next()); //有錯 兩次的i.next()不一樣 56 // System.out.println(m.get(i.next())); 57 58 59 } 60 61 62 } 63 @Test 64 public void testMap2(){ 65 Map m=new HashMap(); 66 m.put("1", "aaa"); 67 m.put("2", "bbb"); 68 m.put("3", "ccc"); 69 //1、傳統方案取出Map里面的值 2 70 Set s=m.entrySet();//通過entrySet方法把每組鍵值存到s中 71 Iterator i=s.iterator();//迭代遍歷輸出s中的值 72 while(i.hasNext()){ 73 Map.Entry me=(Entry) i.next(); 74 System.out.println(me.getKey()+"對應的值為"+me.getValue()); 75 } 76 77 78 79 } 80 81 @Test 82 public void testMap3(){ 83 Map m=new HashMap(); 84 m.put("1", "aaa"); 85 m.put("2", "bbb"); 86 m.put("3", "ccc"); 87 //1、增強for循環 1 (keySet實現Iterable泛型接口) 88 for(Object o:m.keySet()){ 89 // String s=(String) o; 90 // String value=(String) m.get(o); 91 // System.out.println(o+" "+value); 92 out.println(o+" "+m.get(o)); 93 } 94 95 96 } 97 @Test 98 public void testMap4(){ 99 Map m=new HashMap(); 100 m.put("1", "aaa"); 101 m.put("2", "bbb"); 102 m.put("3", "ccc"); 103 //1、增強for循環 2 (entrySet實現Iterable泛型接口) 104 for(Object o:m.entrySet()){ 105 Map.Entry me=(Entry) o; 106 System.out.println(me.getKey()+" "+me.getValue()); 107 } 108 109 110 } 111 112 @Test //增強for循環應該注意的問題 增強for循環只能取數組或者集合里面的數據 不能更改數據;要改數據的話只能用傳統方法 113 public void test3(){ 114 // int []i=new int[]{1,2,3}; 115 // for(int j:i){ 116 // j=10;//j僅僅是指向取出來的值而已 並不能改變數組里面的值 117 // 118 // } 119 // //傳統方法改變數組的值 120 // for(int j=0;j<i.length;j++){ 121 // i[j]=10; 122 // } 123 // out.println(i[0]); 124 // out.println(i[1]); 125 // out.println(i[2]); 126 // 127 128 List l=new ArrayList(); 129 l.add("a"); 130 l.add("b"); 131 l.add("c"); 132 for(Object k:l){ 133 k="d";//k僅僅是指向取出來的值而已 並不能改變集合里面的值 134 135 } 136 //傳統方案刪除集合里面的元素 137 for(int i=0;i<l.size();i++){ 138 139 l.removeAll(l); 140 141 142 143 } 144 l.add("e"); 145 l.add("e"); 146 l.add("e"); 147 System.out.println(l.get(0)); 148 System.out.println(l.get(1)); 149 System.out.println(l.get(2)); 150 151 152 } 153 }
3. 可變參數
使用可變參數的精髓:就是看需要什么類型的數據,需要對象就傳入對象/對象數組,需要基本數據類型就傳基本數據類型/基本數組
1 package com.study.lgs; 2 import java.util.Arrays; 3 import java.util.List; 4 5 import org.junit.Test; 6 7 public class KeBianCanShu { 8 9 @Test 10 public void testSum(){ 11 int []i={1,2,3}; 12 sum(i);//可變參數里面可以看成一個數組,所以可以向里面傳入數組i 13 sum(1,2,3); 14 } 15 //可變參數按數組方式進行處理,只能放在參數列表的最后,一個參數列表中只能有一個可變參數 16 17 public void sum(int...nums){ 18 int sum=0; 19 for(int k:nums){ 20 sum+=k; 21 } 22 System.out.println(sum); 23 } 24 @Test 25 public void testArrays(){ 26 List l=Arrays.asList("1","2","3");//傳入普通字符串對象 27 System.out.println(l); 28 29 String [] s={"1","2","3","4"};//傳入字符數組對象 30 l=Arrays.asList(s); 31 System.out.println(l); 32 33 //int []i={1,2,3,4,5}; 34 Integer []i={1,2,3,4,5}; 35 l=Arrays.asList(i);//傳入基本數據類型整型數組對象 List的l會吧i數組看作一個對象,所以輸出的l為一個地址,必須使用包裝類的對象以對象方式傳入才可輸出實際的值 36 System.out.println(l); 37 } 38 39 }
4. 枚舉
4.1 枚舉的作用和特性
作用:限定某些程序運行時所需要數據的取值范圍
特性:
(1) 枚舉類也是一種特殊形式的java類
(2) 枚舉類中聲明的每一個枚舉值代表枚舉類的一個實例對象
(3) 與java中的普通類一樣,在聲明枚舉類時,也可以聲明屬性、方法和構造函數,但枚舉類的構造函數必須是私有的(因為枚舉類的作用就是限定某些程序運行時所需要數據的取值范圍,如果構造函數公有,別人就可以隨便更改)
(4) 枚舉類也可以實現接口、繼承抽象類
(5) jdk5擴展了switch語句,它除了可以接收int,byte,char,short外,還可以接收一個枚舉類型
(6) 若枚舉類只有一個枚舉值,則可以單作單態設計模式使用
1 package enumeration; 2 3 import org.junit.Test; 4 5 //枚舉的作用:限定某些程序運行時所需要數據的取值范圍 6 enum Grade{ 7 A,B,C,D 8 } 9 public class DefineEnum { 10 @Test 11 public void test(){ 12 DefineEnum.printGrade(Grade.A); 13 } 14 public static void printGrade(Grade a){ 15 switch(a){ 16 case A: 17 System.out.println("90"); 18 break; 19 case B: 20 System.out.println("80"); 21 break; 22 case C: 23 System.out.println("70"); 24 break; 25 case D: 26 System.out.println("60"); 27 break; 28 default: 29 System.out.println("傳入參數有錯"); 30 31 } 32 } 33 }
4.2 定義枚舉的字段、構造函數、方法去封裝更多的信息
1 package enumeration; 2 3 import org.junit.Test; 4 5 //枚舉的作用:限定某些程序運行時所需要數據的取值范圍 6 //怎樣定義枚舉的字段、構造函數、方法去封裝更多的信息 7 enum Grade{ 8 A("100-90"),B("89-80"),C("79-70"),D("69-60");//對枚舉進行實例化 9 private String value;//定義每個枚舉類型里面存的值 10 private Grade(String value){ 11 this.value=value; 12 } 13 public String getValue(){ //外部對象獲取每個枚舉類型里面存的值 14 return this.value; 15 } 16 } 17 public class DefineEnum { 18 @Test 19 public void test(){ 20 printGrade(Grade.B); 21 } 22 public void printGrade(Grade a){ 23 System.out.println(a.getValue()); 24 } 25 }
4.3 帶抽象方法的枚舉 實例化時必須實現抽象方法
1 package enumeration; 2 3 import org.junit.Test; 4 5 //枚舉的作用:限定某些程序運行時所需要數據的取值范圍 6 //帶抽象方法的枚舉 實例化時必須實現抽象方法 7 enum Grade{ 8 A("100-90") { 9 @Override 10 public String getLocalValue() { 11 // TODO Auto-generated method stub 12 return "優"; 13 } 14 }, 15 B("89-80") { 16 @Override 17 public String getLocalValue() { 18 // TODO Auto-generated method stub 19 return "良"; 20 } 21 }, 22 C("79-70") { 23 @Override 24 public String getLocalValue() { 25 // TODO Auto-generated method stub 26 return "中"; 27 } 28 }, 29 D("69-60") { 30 @Override 31 public String getLocalValue() { 32 // TODO Auto-generated method stub 33 return "差"; 34 } 35 };//對枚舉進行實例化 必須實現抽象方法 36 37 private String value;//定義每個枚舉類型里面存的值 38 private Grade(String value){ 39 this.value=value; 40 } 41 public String getValue(){ //外部對象獲取每個枚舉類型里面存的值 42 return this.value; 43 } 44 //帶抽象方法的枚舉 45 public abstract String getLocalValue(); 46 } 47 public class DefineEnum { 48 @Test 49 public void test(){ 50 printGrade(Grade.B); 51 } 52 public void printGrade(Grade a){ 53 System.out.println(a.getValue()); 54 System.out.println(a.getLocalValue()); 55 56 } 57 }
4.4 普通單例設計模式與枚舉單例設計模式
1 package enumeration; 2 3 //定義普通單態設計模式 4 class Single{ 5 private static Single sin=null; 6 private Single(){} 7 private Single(Single sin){ 8 this.sin=sin; 9 } 10 public static Single createShiLi(){ 11 if(sin==null){ 12 sin=new Single(); 13 } 14 return sin; 15 16 } 17 } 18 //定義枚舉類型單態設計模式 當枚舉里面只有一個對象時也屬於單態設計模式 19 enum EnumSingle{ 20 A;//枚舉中聲明的每一個枚舉值表示枚舉類的一個實例化對象 21 //m枚舉類的構造函數必須是私有的,因為枚舉就是用來限制實例化的對象的,如果構造函數為公有的就可以實例化新的對象,不符合枚舉規范 22 } 23 public class DefineSingle { 24 25 public static void main(String[] args) { 26 // TODO Auto-generated method stub 27 //普通設計模式的實例化 28 Single s1=Single.createShiLi(); 29 Single s2=Single.createShiLi(); 30 Single s3=Single.createShiLi(); 31 System.out.println(s1); 32 System.out.println(s2); 33 System.out.println(s3); 34 35 36 37 } 38 39 }
4.6 測試枚舉中的常用方法
1 package enumeration; 2 3 import org.junit.Test; 4 5 //枚舉的作用:限定某些程序運行時所需要數據的取值范圍 6 //帶抽象方法的枚舉 實例化時必須實現抽象方法 7 //枚舉中聲明的每一個枚舉值表示枚舉類的一個實例化對象 8 //m枚舉類的構造函數必須是私有的,因為枚舉就是用來限制實例化的對象的,如果構造函數為公有的就可以實例化新的對象,不符合枚舉規范 9 10 enum Grade { 11 A("100-90") { 12 @Override 13 public String getLocalValue() { 14 // TODO Auto-generated method stub 15 return "優"; 16 } 17 }, 18 B("89-80") { 19 @Override 20 public String getLocalValue() { 21 // TODO Auto-generated method stub 22 return "良"; 23 } 24 }, 25 C("79-70") { 26 @Override 27 public String getLocalValue() { 28 // TODO Auto-generated method stub 29 return "中"; 30 } 31 }, 32 D("69-60") { 33 @Override 34 public String getLocalValue() { 35 // TODO Auto-generated method stub 36 return "差"; 37 } 38 };// 對枚舉進行實例化 必須實現抽象方法 39 40 private String value;// 定義每個枚舉類型里面存的值 41 42 private Grade(String value) { 43 this.value = value; 44 } 45 46 public String getValue() { // 外部對象獲取每個枚舉類型里面存的值 47 return this.value; 48 } 49 50 // 帶抽象方法的枚舉 51 public abstract String getLocalValue(); 52 } 53 54 public class DefineEnum { 55 @Test 56 public void test() { 57 printGrade(Grade.B); 58 } 59 60 public void printGrade(Grade a) { 61 System.out.println(a.getValue()); 62 System.out.println(a.getLocalValue()); 63 64 } 65 66 // 測試枚舉的常用方法 67 @Test 68 public void test2() { 69 System.out.println(Grade.A.name());// name()方法返回枚舉的名字 70 System.out.println(Grade.A.ordinal());// ordinal()方法返回枚舉對象在枚舉類中的序號 71 String str = "B"; 72 Grade g = Grade.valueOf(Grade.class, str);// valueOf()方法將某個枚舉對象對應的字符串轉變為枚舉對象 73 // 實際開發中用於檢測用戶提交的字符串是否屬於自己定義的枚舉類型 74 // Grade 75 // g=Grade.valueOf(str); 76 System.out.println(g); 77 // for(Grade g:Grade.values()){ //values()方法獲取枚舉中的每個值 78 // System.out.println(g); 79 // } 80 81 } 82 }
4.7 定義一個星期的枚舉設置方法返回對應中文星期
1 package enumeration; 2 3 import org.junit.Test; 4 5 //定義一個星期的枚舉WeekDay 6 //枚舉值:Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday 7 //該枚舉有一個方法,調用該方法返回中文格式的日期 8 enum WeekDay{ 9 Monday { 10 @Override 11 public String getChineseDay() { 12 // TODO Auto-generated method stub 13 return "星期一"; 14 } 15 }, 16 Tuesday { 17 @Override 18 public String getChineseDay() { 19 // TODO Auto-generated method stub 20 return "星期二"; 21 } 22 }, 23 Wednesday { 24 @Override 25 public String getChineseDay() { 26 // TODO Auto-generated method stub 27 return "星期三"; 28 } 29 }, 30 Thursday { 31 @Override 32 public String getChineseDay() { 33 // TODO Auto-generated method stub 34 return "星期四"; 35 } 36 }, 37 Friday { 38 @Override 39 public String getChineseDay() { 40 // TODO Auto-generated method stub 41 return "星期五"; 42 } 43 }, 44 Saturday { 45 @Override 46 public String getChineseDay() { 47 // TODO Auto-generated method stub 48 return "星期六"; 49 } 50 }, 51 Sunday { 52 @Override 53 public String getChineseDay() { 54 // TODO Auto-generated method stub 55 return "星期天"; 56 } 57 }; 58 public abstract String getChineseDay(); 59 60 } 61 public class HomeWork { 62 63 @Test 64 public void test(){ 65 printDay(WeekDay.Friday); 66 } 67 public void printDay(WeekDay wd){ 68 System.out.println(wd.getChineseDay()); 69 } 70 71 }
5. 反射
5.1 反射的概念
反射:加載類(獲取類的字節碼),獲取類里面的各種組成成分
反射的用途:寫框架
通過反射獲取類里面的各種組成干什么?
(1) 獲取構造函數去實例化對象
(2) 獲取字段去封裝數據
(3) 獲取方法去運行
加載類的三種方式:
1 package refelect; 2 3 public class LoadClass { 4 5 public static void main(String[] args) throws ClassNotFoundException { 6 // TODO Auto-generated method stub 7 //加載類的方法 8 //1、Class類的forName()方法 9 Class c1=Class.forName("refelect.Person"); //把類的字節碼加載到內存中去 10 System.out.println(c1); 11 //2、通過對象的getClass()方法 12 Person p=new Person(); 13 Class c2=p.getClass(); //把類的字節碼加載到內存中去 14 System.out.println(c2); 15 //3、通過.class 16 Class c3=Person.class; //把類的字節碼加載到內存中去 17 System.out.println(c3); 18 19 } 20 21 }
5.2 通過反射獲取類的構造函數
1 package refelect; 2 3 import java.io.InputStream; 4 import java.util.List; 5 6 public class Person { 7 8 public String name = "aaa"; 9 10 private int password = 123; 11 12 private static int age = 23; 13 14 public static int score = 90; 15 16 public Person() { 17 System.out.println("person"); 18 } 19 20 public Person(String name) { 21 System.out.println("person name"); 22 } 23 24 public Person(String name, int password) { 25 System.out.println("person name password"); 26 } 27 28 private Person(List list) { 29 System.out.println("list"); 30 } 31 32 public void aa() { 33 System.out.println("aa"); 34 } 35 36 public void aa(String name, int password) { 37 System.out.println(name + password); 38 } 39 40 public Class[] aa(String name, int[] password) { 41 return new Class[] { String.class }; 42 } 43 44 private void aa(InputStream in) { 45 System.out.println(in); 46 } 47 48 public static void aa(int num) { 49 System.out.println(num); 50 } 51 52 public static void main(String[] args) { 53 System.out.println("main"); 54 } 55 }
1 package refelect; 2 3 import java.lang.reflect.Constructor; 4 import java.util.ArrayList; 5 import java.util.List; 6 7 import org.junit.Test; 8 9 public class GetConstructor { 10 11 //通過反射獲取類里面的無參構造函數 public Person() 12 @Test 13 public void test1() throws Exception{ 14 //1、獲取無參構造函數 public Person() 15 Class c1=Class.forName("refelect.Person");//加載類到內存中去 16 Constructor cs1=c1.getConstructor(null);//通過傳入的可變參數獲取對應的構造函數,此處獲取無參構造函數 17 Person p1=(Person) cs1.newInstance(null);//通過無參構造函數實例化對象 18 String s=p1.name; 19 System.out.println(s); 20 } 21 //通過反射獲取類里面的有一個參數構造函數 public Person(String name) 22 @Test 23 public void test2() throws Exception{ 24 25 Class c1=Class.forName("refelect.Person");//加載類到內存中去 26 Constructor cs1=c1.getConstructor(String.class);//記住:必須傳入String.class告知參數類型為字符串,不能傳入"aaa"之流 27 Person p=(Person) cs1.newInstance("aaa");//通過構造函數實例化對象 28 System.out.println(p.name); 29 } 30 //通過反射獲取類里面的有兩個參數構造函數 public Person(String name,int passord) 31 @Test 32 public void test3() throws Exception{ 33 34 Class c1=Class.forName("refelect.Person");//加載類到內存中去 35 Constructor cs1=c1.getConstructor(String.class,int.class); 36 Person p=(Person) cs1.newInstance("aaa",123); 37 System.out.println(p.name); 38 } 39 //通過反射獲取類里面的私有帶參構造函數 private Person(List l) 40 @Test 41 public void test4() throws Exception{ 42 //getConstructor()方法只能獲取public類型的構造函數 43 //getDeclaredConstructor()方法能夠獲取所有聲明的構造函數包括私有的 44 Class c1=Class.forName("refelect.Person");//加載類到內存中去 45 Constructor cs1=c1.getDeclaredConstructor(List.class); 46 cs1.setAccessible(true);//記住:一定要暴力地將私有的構造函數屬性設置為可以被外部訪問,否則將會報錯 47 Person p=(Person) cs1.newInstance(new ArrayList()); 48 System.out.println(p.name); 49 } 50 //創建對象的另一種途徑 直接通過反射出的類的newInstance()方法 ,自動調用無參構造函數實例化,以下代碼等價於test1 51 @Test 52 public void test5() throws Exception{ 53 //getConstructor()方法只能獲取public類型的構造函數 54 //getDeclaredConstructor()方法能夠獲取所有聲明的構造函數包括私有的 55 Class c1=Class.forName("refelect.Person");//加載類到內存中去 56 Person p=(Person) c1.newInstance(); 57 System.out.println(p.name); 58 } 59 60 }
5.3 通過反射獲取類的方法以及main方法的特殊獲取
1 package refelect; 2 3 import java.io.FileInputStream; 4 import java.io.InputStream; 5 import java.lang.reflect.Method; 6 7 import org.junit.Test; 8 9 //通過反射獲取類里面的方法 10 public class GetMethods { 11 12 //獲取方法 public void aa() 13 @Test 14 public void test1() throws Exception{ 15 Class c1=Class.forName("refelect.Person");//加載類 16 Method m=c1.getMethod("aa", null);//獲取類里面的方法 第一個參數指定是哪一個方法,第二個參數指定方法的參數類型 17 m.invoke(c1.newInstance(), null);//執行方法,第一個參數指定執行方法需要實例化的對象,第二個參數為需要傳入的參數 18 } 19 20 //獲取方法 public void aa(String name,int password) 21 @Test 22 public void test2() throws Exception{ 23 Class c1=Class.forName("refelect.Person");//加載類 24 Method m=c1.getMethod("aa", String.class,int.class); 25 m.invoke(c1.newInstance(), "lgs",21); 26 } 27 28 //獲取方法 public Class[] aa(String name,int[] password) 29 @Test 30 public void test3() throws Exception{ 31 Class c1=Class.forName("refelect.Person");//加載類 32 Method m=c1.getMethod("aa", String.class,int[].class); 33 Class [] cls=(Class[]) m.invoke(c1.newInstance(), "lgs",new int[]{1,2,3}); 34 System.out.println(cls[0]); 35 } 36 //獲取方法 private void aa(InputStream in) 37 @Test 38 public void test4() throws Exception{ 39 Class c1=Class.forName("refelect.Person");//加載類 40 Method m=c1.getDeclaredMethod("aa", InputStream.class);//獲取私有方法 41 m.setAccessible(true);//暴力解除方法私有屬性 42 m.invoke(c1.newInstance(), new FileInputStream("c:\\1.txt")); 43 44 } 45 //獲取方法 public static void aa(int num) 46 @Test 47 public void test5() throws Exception{ 48 Class c1=Class.forName("refelect.Person");//加載類 49 Method m=c1.getDeclaredMethod("aa", int.class);//獲取私有方法 50 51 m.invoke(c1.newInstance(), 23);//靜態方法調用時不需要對象,因此第一個參數可以為空 52 53 } 54 //獲取方法 public static void main(String[] args) 55 @Test 56 public void test6() throws Exception{ 57 Class c1=Class.forName("refelect.Person");//加載類 58 Method m=c1.getDeclaredMethod("main", String[].class);//獲取私有方法 59 60 //m.invoke(null, new String[]{"1","2"});//錯誤的 因為在傳數組參數進去給main函數的時候會被自動拆分為String s1和String s2 main函數里面沒有這兩種參數所以報錯參數個數不正確 61 //m.invoke(null, new Object[]{new String[]{"1","2"}});//靜態方法調用時不需要對象,因此第一個參數可以為空,此時main函數會被自動拆分為String[]數組,不會報錯 62 m.invoke(null, (Object)new String[]{"1","2"});//這哥們不是喜歡把數組拆分為字符串嗎,就加Object強制轉換騙他我不是數組 63 } 64 }
5.4 通過反射獲取類的字段
1 package refelect; 2 3 import java.lang.reflect.Field; 4 5 import org.junit.Test; 6 7 //通過反射獲取字段 8 public class GetFields { 9 //獲取字段public String name="lgs"; 10 @Test 11 public void test1() throws Exception{ 12 13 Class c1=Class.forName("refelect.Person");//加載類 14 Field f=c1.getField("name");//獲取字段 參數為要獲取的字段的名稱 15 // String s= (String) f.get(c1.newInstance());//獲取字段的值 參數為對應的對象 16 Object o=f.get(c1.newInstance());//獲取字段的值 參數為對應的對象 17 18 //獲取字段的類型 19 Class type=f.getType(); 20 if(type.equals(String.class)){ 21 String s=(String) o; 22 System.out.println(s); 23 } 24 25 //設置字段的值 26 Person p=(Person) c1.newInstance(); 27 f.set(p, "yc"); 28 System.out.println(p.name); 29 30 31 } 32 //獲取字段private int password=123; 33 @Test 34 public void test2() throws Exception{ 35 36 Class c1=Class.forName("refelect.Person");//加載類 37 Field f= c1.getDeclaredField("password"); 38 f.setAccessible(true);//暴力修改字段的可視性為公有 39 Object o=f.get(c1.newInstance()); 40 System.out.println(o); 41 } 42 //獲取字段private static int age=23; 43 @Test 44 public void test3() throws Exception{ 45 46 Class c1=Class.forName("refelect.Person");//加載類 47 Field f= c1.getDeclaredField("age"); 48 f.setAccessible(true);//暴力修改字段的可視性為公有 49 Object o=f.get(c1.newInstance()); 50 System.out.println(o); 51 } 52 //獲取字段public static int score=90; 53 @Test 54 public void test4() throws Exception{ 55 56 Class c1=Class.forName("refelect.Person");//加載類 57 Field f= c1.getField("score"); 58 // Object o=f.get(c1.newInstance()); 59 System.out.println(f.get(c1.newInstance())); 60 } 61 }
6. 內省(Introspector)
6.1 為什么要學習內省
開發框架時,經常需要使用java對象的屬性來封裝程序的數據,每次都使用反射技術完成此類操作過於麻煩,所以sun公司開發了一套API,專門用於操作java對象的屬性
6.2 通過內省操作javabean屬性
1 package refelect; 2 3 /** 4 * Person就是一個javabean 5 * 里面的字段有對應的get或者set方法,這個字段就稱為一個屬性 6 * 7 * @author lgs 8 * 9 */ 10 public class Person { 11 12 // 字段 13 public String name; 14 15 // 字段 16 private int password; 17 18 // 字段 19 private int age; 20 21 // 字段 22 private int score; 23 24 public String getName() { 25 return name; 26 } 27 28 public void setName(String name) { 29 this.name = name; 30 } 31 32 public int getPassword() { 33 return password; 34 } 35 36 public void setPassword(int password) { 37 this.password = password; 38 } 39 40 public int getAge() { 41 return age; 42 } 43 44 public void setAge(int age) { 45 this.age = age; 46 } 47 48 public int getScore() { 49 return score; 50 } 51 52 public void setScore(int score) { 53 this.score = score; 54 } 55 56 }
1 package introspector; 2 3 import java.beans.BeanInfo; 4 import java.beans.IntrospectionException; 5 import java.beans.Introspector; 6 import java.beans.PropertyDescriptor; 7 import java.lang.reflect.Method; 8 9 import org.junit.Test; 10 11 //通過內省來操作bean(即Person類)的屬性 12 public class TestIntroSpector { 13 14 //獲取bean的所有屬性 15 @Test 16 public void test1() throws Exception{ 17 //BeanInfo bi=Introspector.getBeanInfo(Person.class);//通過內省Introspector的getBeanInfo(Person.class)方法獲取bean的所有屬性 18 BeanInfo bi=Introspector.getBeanInfo(Person.class, Object.class);//只獲取本身增加的屬性,不要從Object類獲取的屬性 與使用getDisplayName()方法的效果一樣 19 PropertyDescriptor [] pd=bi.getPropertyDescriptors();//讀取bean的所有屬性存到數組pd里面去 20 for(PropertyDescriptor k:pd){ 21 System.out.println(k.getName()); 22 23 } 24 25 } 26 27 //獲取並操作bean指定的屬性 age 28 @Test 29 public void test2() throws Exception{ 30 Person p=new Person(); 31 //使用構造函數 PropertyDescriptor(String 屬性名, 對應的bean)操作特定屬性 32 PropertyDescriptor pd=new PropertyDescriptor("age", Person.class); 33 34 //獲取屬性的寫方法,並為屬性賦值 35 Method m=pd.getWriteMethod();//獲取bean的setAge屬性 public void setAge(int age) 36 m.invoke(p, 23);//執行SetAge屬性並寫入屬性值 37 38 //傳統方式獲取屬性的值 39 System.out.println(p.getAge()); 40 41 //內省獲取屬性的值 42 Method mt=pd.getReadMethod();//獲取getAge()方法 讀屬性值 43 System.out.println(mt.invoke(p, null));//輸出屬性值 44 45 } 46 //獲取bean指定的屬性的類型 age 47 @Test 48 public void test3() throws Exception{ 49 Person p=new Person(); 50 //使用構造函數 PropertyDescriptor(String 屬性名, 對應的bean)操作特定屬性 51 PropertyDescriptor pd=new PropertyDescriptor("age", Person.class); 52 System.out.println(pd.getPropertyType());//獲取age屬性的類型 53 54 55 } 56 57 }
6.3 使用BeanUtils類操作javabean屬性
使用第三方框架beanutils
beanutils的配置過程:
(1)、新建一個開發庫文件夾lib,然后向里面添加commons-beanutils-1.8.0.jar和commons-logging.jar包
(2)、同時選中上面的兩個jar包-右鍵-build path-add build path
(3)、當上面的兩個jar包在Referenced Libraries(會自動生成這個文件夾)里面變為奶瓶時就可以使用beanutils操作javabean的屬性了
1 package refelect; 2 3 import java.util.Date; 4 5 /** 6 * Person就是一個javabean 7 * 里面的字段有對應的get或者set方法,這個字段就稱為一個屬性 8 * 9 * @author lgs 10 * 11 */ 12 public class Person { 13 14 // 字段 15 public String name; 16 17 // 字段 18 private int password; 19 20 // 字段 21 private int age; 22 23 // 字段 24 private int score; 25 26 //生日 27 private Date birthday; 28 29 public String getName() { 30 return name; 31 } 32 33 public void setName(String name) { 34 this.name = name; 35 } 36 37 public int getPassword() { 38 return password; 39 } 40 41 public void setPassword(int password) { 42 this.password = password; 43 } 44 45 public int getAge() { 46 return age; 47 } 48 49 public void setAge(int age) { 50 this.age = age; 51 } 52 53 public int getScore() { 54 return score; 55 } 56 57 public void setScore(int score) { 58 this.score = score; 59 } 60 61 public Date getBirthday() { 62 return birthday; 63 } 64 65 public void setBirthday(Date birthday) { 66 this.birthday = birthday; 67 } 68 69 }
1 package beanutils; 2 3 import java.lang.reflect.InvocationTargetException; 4 import java.text.ParseException; 5 import java.text.SimpleDateFormat; 6 import java.util.Date; 7 import java.util.HashMap; 8 import java.util.Map; 9 10 import org.apache.commons.beanutils.BeanUtils; 11 import org.apache.commons.beanutils.ConversionException; 12 import org.apache.commons.beanutils.ConvertUtils; 13 import org.apache.commons.beanutils.Converter; 14 import org.apache.commons.beanutils.locale.converters.DateLocaleConverter; 15 import org.junit.Test; 16 17 //使用beanutils操作javabean(即Person類)的屬性 18 //使用第三方框架beanutils 19 //beanutils的配置過程: 20 //1、新建一個開發庫文件夾lib,然后向里面添加commons-beanutils-1.8.0.jar和commons-logging.jar包 21 //2、同時選中上面的兩個jar包-右鍵-build path-add build path 22 //3、當上面的兩個jar包在Referenced Libraries(會自動生成這個文件夾)里面變為奶瓶時就可以使用beanutils操作javabean的屬性了 23 public class TestBeanUtils { 24 25 //BeanUtils類操作bean屬性 26 @Test 27 public void test1() throws Exception, Exception{ 28 Person p=new Person(); 29 //通過BeanUtils的setProperty(bean, name, value)方法設置特定的屬性的值 30 //第一個參數代表要設置的bean對象(即Person對象),第二個參數表示要設置的屬性名,第三個表示要設置的屬性值 31 BeanUtils.setProperty(p, "name", "fp");//設置bean屬性的值 32 System.out.println(p.getName()); 33 34 } 35 //BeanUtils類操作用戶通過表單提交過來的值 36 @Test 37 public void test2() throws Exception, Exception{ 38 39 //用戶通過表單提交過來的值,提交過來的都是字符串 40 String name="lgs"; 41 String password="123"; 42 String age="23"; 43 44 //把用戶提交過來的值設置到bean的屬性(即Person類的屬性)里面去,提交過來的都是字符串 45 // BeanUtils內部能夠把表單提交過來的字符串轉變為對應的八種基本數據類型,不能轉變為日期這種復雜的數據類型 46 //如果要轉換為日期就必須為BeanUtils注冊日期轉換器 47 Person p=new Person(); 48 BeanUtils.setProperty(p, "name", name);//設置bean屬性的值 49 BeanUtils.setProperty(p, "password", password);//設置bean屬性的值 50 BeanUtils.setProperty(p, "age", age);//設置bean屬性的值 BeanUtils能夠把表單提交過來的字符串轉變為對應的八種基本數據類型 51 System.out.println(p.getName()); 52 System.out.println(p.getPassword()); 53 System.out.println(p.getAge()); 54 55 56 } 57 //把用戶提交過來的字符串類型的日期 轉換為bean里面定義的日期類型(Date類型)的日期 ,自定義轉換器 58 @Test 59 public void test3() throws Exception, Exception{ 60 61 //用戶通過表單提交過來的值,提交過來的都是字符串 62 String name="lgs"; 63 String password="123"; 64 String age="23"; 65 //字符串類型的日期 66 String birthday="1995-06-06"; 67 68 //把用戶提交過來的值設置到bean的屬性(即Person類的屬性)里面去,提交過來的都是字符串 69 // BeanUtils內部能夠把表單提交過來的字符串轉變為對應的八種基本數據類型,不能轉變為日期這種復雜的數據類型 70 //如果要轉換為日期就必須為BeanUtils注冊日期轉換器 71 72 //為了讓字符串類型的日期賦給bean的birthday(Date類型屬性)屬性,我們給BeanUtils注冊一個日期轉換器 73 //ConvertUtils.register(converter, clazz); 74 //第一個參數表示要注冊的轉換器接口,第二個表示要注冊的轉換器類型 75 ConvertUtils.register(new Converter(){ 76 public Object convert(Class type, Object value){ 77 if(value==null){ 78 return null; 79 } 80 if(!(value instanceof String)){ 81 throw new ConversionException("只支持String類型的轉換"); 82 } 83 String s=(String) value; 84 if(s.trim().equals("")){ 85 return null; 86 } 87 SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");//指定要轉換的日期格式 88 try { 89 return sdf.parse(s); 90 } catch (ParseException e) { 91 // TODO Auto-generated catch block 92 //e.printStackTrace(); 93 throw new RuntimeException(e);//異常鏈e不能斷(不能為空),否則不知道拋出的是什么異常 94 } 95 96 97 } 98 }, Date.class); 99 Person p=new Person(); 100 BeanUtils.setProperty(p, "name", name);//設置bean屬性的值 101 BeanUtils.setProperty(p, "password", password);//設置bean屬性的值 102 BeanUtils.setProperty(p, "age", age);//設置bean屬性的值 BeanUtils能夠把表單提交過來的字符串轉變為對應的八種基本數據類型 103 BeanUtils.setProperty(p, "birthday", birthday);//只支持八種數據類型的轉換,所以在此之前已經為BeanUtils注冊了日期轉換器 104 System.out.println(p.getName()); 105 System.out.println(p.getPassword()); 106 System.out.println(p.getAge()); 107 System.out.println(p.getBirthday().toLocaleString()); 108 109 110 } 111 //把用戶提交過來的字符串類型的日期 轉換為bean里面定義的日期類型(Date類型)的日期 112 //使用BeanUtils已經寫好的轉換器 113 @Test 114 public void test4() throws Exception, Exception{ 115 116 //用戶通過表單提交過來的值,提交過來的都是字符串 117 String name="lgs"; 118 String password="123"; 119 String age="23"; 120 //字符串類型的日期 121 String birthday="1995-06-06"; 122 123 //注冊日期轉換器時使用BeanUtils寫好的日期轉換器 124 //既然已經寫好了日期轉換器為什么還要自己寫呢原因有2個 125 //1、寫好的日期轉換器DateLocaleConverter有bug,當轉入日期為空時,仍會轉空日期 此時會報錯 126 //2、還有一些轉換器沒有寫,這樣就需要自己來寫轉換器了 127 ConvertUtils.register(new DateLocaleConverter(birthday), Date.class); 128 129 Person p=new Person(); 130 BeanUtils.setProperty(p, "name", name);//設置bean屬性的值 131 BeanUtils.setProperty(p, "password", password);//設置bean屬性的值 132 BeanUtils.setProperty(p, "age", age);//設置bean屬性的值 BeanUtils能夠把表單提交過來的字符串轉變為對應的八種基本數據類型 133 BeanUtils.setProperty(p, "birthday", birthday);//只支持八種數據類型的轉換,所以在此之前已經為BeanUtils注冊了日期轉換器 134 System.out.println(p.getName()); 135 System.out.println(p.getPassword()); 136 System.out.println(p.getAge()); 137 System.out.println(p.getBirthday()); 138 139 140 } 141 142 //定義Map集合存放用戶提交的數據 143 @Test 144 public void test5() throws Exception, InvocationTargetException{ 145 //定義Map集合封裝用戶提交的數據 //Map的關鍵字必須與bean的屬性一致,否則不能寫入 146 Map m=new HashMap(); 147 m.put("name", "yqh"); 148 m.put("password", "123456"); 149 m.put("age", "20"); 150 m.put("birthday", "1995-12-30"); 151 152 //為BeanUtils注冊日期轉換器轉換字符串日期 153 ConvertUtils.register(new DateLocaleConverter(), Date.class); 154 Person bean=new Person(); 155 BeanUtils.populate(bean, m);//用Map集合填充bean屬性 156 System.out.println(bean.getName()); 157 System.out.println(bean.getPassword()); 158 System.out.println(bean.getAge()); 159 System.out.println(bean.getBirthday()); 160 } 161 162 }
7. 泛型
7.1 使用泛型(generic)的好處
使用泛型的好處可以進行類型安全檢查,提高了程序的可讀性和穩定性
1 package generic; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 6 import org.junit.Test; 7 8 public class TestGeneric { 9 10 //使用泛型的好處 11 @Test 12 public void test1() { 13 // TODO Auto-generated method stub 14 // 1、最原始的集合 15 List l = new ArrayList(); 16 l.add("aaa"); 17 // 此時集合中的值明顯是一個字符串,但程序員卻把字符串轉為Integer 編譯不會出錯但運行會錯,相當不安全 18 // Integer i=(Integer) l.get(0); 19 20 // 使用泛型的好處 21 // 2、定義集合時就利用泛型指定其處理的類型 這樣做提高了程序的可讀性和穩定性,同時 進行類型安全檢查 22 List<String> l1 = new ArrayList<String>(); 23 // l1.add(1);//使用泛型的好處可以進行類型安全檢查 因為指定的泛型是String,所以傳入的值必須為字符串 24 l1.add("1"); 25 System.out.println(l1.get(0)); 26 27 } 28 29 }
7.2 泛型與集合搭配使用及其注意事項
泛型是給java編譯器(javac)使用的;防止在編譯階段向集合插入非法數據,當編譯完以后,編譯后的class文件不具有泛型信息,所以不影響運行效力,這個過程稱之為“擦除”
1 package generic; 2 3 import java.util.ArrayList; 4 import java.util.HashMap; 5 import java.util.Iterator; 6 import java.util.List; 7 import java.util.Map; 8 import java.util.Map.Entry; 9 import java.util.Set; 10 11 import org.junit.Test; 12 13 public class TestGeneric { 14 15 //使用泛型的好處 16 @Test 17 public void test1() { 18 // TODO Auto-generated method stub 19 // 1、最原始的集合 20 List l = new ArrayList(); 21 l.add("aaa"); 22 // 此時集合中的值明顯是一個字符串,但程序員卻把字符串轉為Integer 編譯不會出錯但運行會錯,相當不安全 23 // Integer i=(Integer) l.get(0); 24 25 // 使用泛型的好處 26 // 2、定義集合時就利用泛型指定其處理的類型 這樣做提高了程序的可讀性和穩定性,同時 進行類型安全檢查 27 List<String> l1 = new ArrayList<String>(); 28 // l1.add(1);//使用泛型的好處可以進行類型安全檢查 因為指定的泛型是String,所以傳入的值必須為字符串 29 l1.add("1"); 30 System.out.println(l1.get(0)); 31 32 } 33 //集合的存取 34 @Test 35 public void test2() { 36 // TODO Auto-generated method stub 37 38 List<String> l1 = new ArrayList<String>(); 39 // l1.add(1);//使用泛型的好處可以進行類型安全檢查 因為指定的泛型是String,所以傳入的值必須為字符串 40 //集合的存 41 l1.add("1"); 42 l1.add("2"); 43 l1.add("3"); 44 //集合的取 45 //1、傳統方案:使用迭代器 46 System.out.println("-------1、傳統方案:使用迭代器-----"); 47 Iterator<String> it=l1.iterator(); 48 while(it.hasNext()){ 49 System.out.println(it.next()); 50 } 51 //2、增強for循環 52 System.out.println("-------2、增強for循環-----"); 53 for(String s:l1){ 54 System.out.println(s); 55 } 56 57 } 58 59 //Map集合的存取 60 @Test 61 public void test3(){ 62 Map<Integer,String> m=new HashMap<Integer,String>(); 63 //Map的存 64 m.put(1, "aa"); 65 m.put(2, "bb"); 66 m.put(3, "cc"); 67 //Map的取 68 //傳統方式1:keySet; 69 System.out.println("-------傳統方式1:keySet-------"); 70 Set<Integer> s=m.keySet(); 71 Iterator<Integer> it=s.iterator(); 72 while(it.hasNext()){ 73 int i=it.next(); 74 System.out.println(i+" "+m.get(i)); 75 } 76 77 //傳統方式2:entrySet 常用 78 System.out.println("-------傳統方式2:entrySet-------"); 79 Set<Entry<Integer, String>> se=m.entrySet(); 80 Iterator<Entry<Integer, String>> ite=se.iterator(); 81 while(ite.hasNext()){ 82 Entry<Integer, String> e=ite.next(); 83 System.out.println(e.getKey()+" "+e.getValue()); 84 } 85 86 //增強for循環 j2ee里面常用的方式(重點) 87 System.out.println("-------增強for循環-------"); 88 for(Entry<Integer, String> e:m.entrySet()){ 89 System.out.println(e.getKey()+" "+e.getValue()); 90 } 91 } 92 //使用泛型時應該注意的問題 93 @Test 94 public void test4(){ 95 //注意:當集合兩邊都使用泛型時,兩邊的泛型類型必須一致,否則會報錯 96 //但是如果只有一邊使用泛型是是可以的 97 98 //兩邊都使用泛型 99 ArrayList<String> al=new ArrayList<String>(); 100 //ArrayList<String> al=new ArrayList<Object>(); 101 //ArrayList<Object> al2=new ArrayList<String>(); 102 103 //只有一邊使用泛型 104 ArrayList<String> al3=new ArrayList(); 105 ArrayList al4=new ArrayList<String>(); 106 107 //提高階段:泛型是給java編譯器(javac)使用的;防止在編譯階段向集合插入非法數據, 108 //當編譯完以后,編譯后的class文件不具有泛型信息,所以不影響運行效力,這個過程稱之為“擦除” 109 //如l1和l2編譯成class文件以后,除了變量名稱不一樣,其他的是完全一樣的 110 List<String> l1 = new ArrayList<String>(); 111 List l2 = new ArrayList(); 112 } 113 114 }
7.3 自定義泛型
定義泛型方法:泛型遵循先聲明再使用的規則
第一種方式:常規方法
1 package generic; 2 3 //定義泛型方法 4 public class DefineGenericMetgod { 5 6 public void testaa(){ 7 aa("aa");//傳入的是字符串,就確定了泛型類型為String,就不存在類型強轉的情況(這就是泛型的真正意義) 8 } 9 //泛型遵循先聲明再使用的規則 10 public <T> void aa(T t){ 11 12 } 13 public <E, K, T> void bb(T t,K k,E e){ 14 15 } 16 17 }
第二種方式:一個泛型作用於多個方法時可以把泛型聲明在類上
1 package generic; 2 3 //定義泛型方法 4 //當一個泛型作用於多個方法時可以把泛型聲明在類上 5 public class DefineGenericMetgod2<T,K,E> { 6 7 public void testaa(){ 8 //aa("aa");//傳入的是字符串,就確定了泛型類型為String,就不存在類型強轉的情況(這就是泛型的真正意義) 9 } 10 //泛型遵循先聲明再使用的規則 11 public T aa(T t){ 12 return t; 13 14 } 15 public void bb(T t,K k,E e){ 16 17 } 18 //類上的泛型對靜態方法不起作用,要重新自定義自己的泛型,注意這個泛型T和類上的泛型T不是同一個 19 public static<T> void cc(T t){ 20 21 } 22 23 }
7.4 練習
(1) 編寫一個泛型方法,交換指定數組元素的位置,記住:一定要使用泛型T定義方法,不能使用諸如String,int子類的類型,那樣的話就只能交換一種特定類型的數組
1 public <T> void swap(T arr[], int pos1, int pos2) { 2 T temp; 3 temp = arr[pos1]; 4 arr[pos1] = arr[pos2]; 5 arr[pos2] = temp; 6 } 7 8 @Test 9 public void testSwap() { 10 Integer[] i = new Integer[] { 1, 2, 3, 4, 5 }; 11 System.out.println("-----交換之前-----"); 12 for (Integer k : i) { 13 System.out.println(k); 14 } 15 swap(i, 1, 3); 16 System.out.println("-----交換之后-----"); 17 for (Integer k : i) { 18 System.out.println(k); 19 } 20 21 }
(2) 編寫一個泛型方法,接收任意數組,然后顛倒數組里面的元素
思路:定義兩個指針,第一個指針指向數組的第一個元素,第二個指針指向數組的最后一個元素,把兩個元素交換,然后把第一個指針加1,第二個指針減1,再交換,如此進行下去知道兩個指針的值相同時不在進行交換
1 public <T> void reverse(T arr[]) { 2 int first = 0; 3 int last = arr.length - 1; 4 5 while (true) { 6 if (first >= last) { 7 break; 8 } 9 T temp; 10 temp = arr[first]; 11 arr[first] = arr[last]; 12 arr[last]=temp; 13 first++; 14 last--; 15 } 16 } 17 18 @Test 19 public void testReverse() { 20 Integer[] i = new Integer[] { 1, 2, 3, 4, 5 }; 21 System.out.println("-----顛倒之前-----"); 22 for (Integer k : i) { 23 System.out.println(k); 24 } 25 reverse(i); 26 System.out.println("-----顛倒之后-----"); 27 for (Integer k : i) { 28 System.out.println(k); 29 } 30 }
