本篇內容源于本人一個好友sgPRo提供的java學習例子,現拿出來給大家分享。
此例子非常直觀的通過代碼講解了java泛型的用法和好處,是筆者一直珍藏的最好的泛型學習筆記。
我們先從求最大值開始講起。
在面向過程的編程世界里,我們是這樣求最大值的
1 package _00_OP; 2 /** 3 * 求若干個數的較大的一個 4 * 5 * 不使用重載,面向過程的年代。 6 * 7 * @author sgpro 8 * 9 */10 class MaxNumber {11 12 /*求兩個int類型數據的最大值*/13 public static int max2ForInteger(int a, int b) {14 return a > b? a : b;15 }16 17 /*求兩個char類型數據的最大值*/18 public static char max2ForChar(char a, char b) {19 return a > b? a : b;20 }21 22 /*求三個char類型數據的最大值,通過兩次調用max2ForChar來實現*/23 public static int max3ForIneger(int a, int b, int c) {24 return max2ForInteger(a, max2ForInteger(b, c));25 }26 }
從上面的代碼可以看到,在面向過程的世界里,如果要想取最大值要考慮
1.數據類型,多少種類型就要多少個方法
2.數據數量,數量越多,算法就越復雜,例子中是使用遞歸的方法實現3個數據求max的。
總之,很麻煩
方法重載:
通過參數個數不同或者參數類型不同實現相同的方法名得到不同的結果
還是求取最大值的例子
1 package _01_Overload; 2 3 /** 4 * 求若干個數的較大的一個 5 * 6 * 方法重載 7 * 通過參數個數不同或者參數類型不同實現相同的方法名得到不同的結果 8 * 9 * @author sgpro10 *11 */12 13 class MaxNumber {14 15 /*求兩個int類型數據的最大值*/16 public static int max(int a, int b) {17 return a > b? a : b;18 }19 20 /*求兩個char類型數據的最大值*/21 public static char max(char a, char b) {22 return a > b? a : b;23 }24 25 /*求三個int類型數據的最大值,通過兩次調用max來實現*/26 public static int max(int a, int b, int c) {27 return max(a, max(b, c));28 }29 }
我們可以看到,相對面向過程的代碼,我們實現了方法名的統一。
當然,代碼依然很復雜,不方便。
關于方法模板幾個注意
1. java的模板類的模板參數只能是參數類型,成員變量類型等,模板名是確定的。
2. 運行期,模板參數會被當作Object來處理
3. 使用模板類的類型安全,只是利用編譯器的類型檢查,來自動保證運行期的類型強轉的正確與安全。
1 package _02_Template; 2 3 /** 4 * 求若干個數的較大的一個 5 * 6 * 通過模板來實現,java 不支持純粹的 “方法模板”,此列事實上就是泛型的前奏了 7 * 8 * @author sgpro 9 *10 */11 12 class MaxNumber {13 14 public static <T extends Object> T max(T a, T b) {15 16 T ret = null;17 /*18 * java不支持純粹的方法模板,具體的比較處理中需要對類型進行判斷。19 */20 if (a instanceof Integer) {21 ret = (Integer)a > (Integer)b ? a : b; 22 } else if (a instanceof Character) {23 ret = (Character)a > (Character)b ? a : b;24 }25 26 return ret;27 }28 29 30 public static <T extends Object> T max(T a, T b, T c) {31 return max(a, max(b, c));32 }33 34 35 36 }
由于java不支持純粹的方法模板,所以具體的比較器處理中還需要對類型進行判斷。
首先我們知道,int類型可以自動裝箱為Integer,char類型可以自動裝箱為Charactor,而Integer類型和Charactor類型都已經實現了Comparable接口
因此,我們可以采用泛型來實現實現maxNumber
1 package _03_Generic; 2 3 /** 4 * 求若干個數的較大的一個 5 * 6 * 泛型實例 一,靜態方式, 無差異提供者。 7 * 8 * @author sgpro 9 *10 */11 12 class MaxNumber<T extends Comparable<T>> { //T的上限是Comparable<T> T必須實現了Comparable<T>接口13 14 public T max(T a, T b) {15 if (a != null && b != null) {16 return a.compareTo(b) > 0? a : b; 17 } else {18 throw new IllegalArgumentException("參數有誤,空對象不能比較");19 }20 } 21 22 public T max(T a, T b, T c) {23 return max(a, max(b, c));24 }25 26 }
java的泛型是偽泛型,使用前我們需要確定具體的類型
MaxNumber<Character> forChar = new MaxNumber<Character>() ; MaxNumber<Integer> forInteger = new MaxNumber<Integer>() ;
System.out.println(forChar.max('x', 'z')); System.out.println(forInteger.max(100, 200)); System.out.println(forInteger.max(200, 800, 400));
我們看到上面的maxNumber類的參數T要求實現comparable接口。那么只要是實現了comparable接口的對象都可以使用maxNumber來求最大值。
comparable:顧名思義,就是可以比較的。實現了這個接口,就可以使用><來進行對象間的比較。
舉個例子:我們實現一個Country類,實現了Comparable接口的compareTo了方法,兩個Country對象比大小,population大的大
1 package _03_Generic; 2 3 public class Country implements Comparable<Country> { 4 5 public long getPopulation() { 6 return population; 7 } 8 9 public void setPopulation(long population) {10 this.population = population;11 }12 13 public long getGdp() {14 return gdp;15 }16 17 public void setGdp(long gdp) {18 this.gdp = gdp;19 }20 21 public long getTz() {22 return tz;23 }24 25 public void setTz(long tz) {26 this.tz = tz;27 }28 29 private long population;30 private long gdp;31 private long tz;32 private String name;33 34 public Country(String name, long population, long gdp, long tz) {35 super();36 this.population = population;37 this.gdp = gdp;38 this.tz = tz;39 this.name = name;40 }41 42 public String getName() {43 return name;44 }45 46 public void setName(String name) {47 this.name = name;48 }49 50 public Country() {51 // TODO Auto-generated constructor stub52 }53 54 55 @Override56 public int compareTo(Country o) {57 // TODO Auto-generated method stub58 return population > o.population ? 1 : -1;59 }60 61 @Override62 public String toString() {63 // TODO Auto-generated method stub64 return name;65 }66 67 }
然后我們還是使用maxNumber類來取最大值:“中國,俄羅斯,美國三個國家比較,比的是人口”
1 Country china = new Country("中國", 1300000000L, 3000, 8);2 Country russia = new Country("俄羅斯", 100000000L, 8000, 1);3 Country america = new Country("美國", 400000000L, 32000, -5);4 5 MaxNumber<Country> forCountry = new MaxNumber<Country>();6 7 System.out.println(forCountry.max(russia, america));8 System.out.println(forCountry.max(china, russia, america));
我們可以在maxNumber泛型類中加入一個比較器——Comparator
1 package _04_Generic; 2 3 import java.util.Comparator; 4 5 /** 6 * 求若干個數的較大的一個 7 * 8 * 泛型實例 二,動態方式,開放差異提供者,支持默認比較器,釋放比較器 9 * 10 * @author sgpro11 *12 */13 14 15 class MaxNumber<T extends Comparable<T>> {16 17 public MaxNumber(Comparator<T> comp) {18 super();19 this.comp = comp;20 }21 22 private Comparator<T> comp = null;23 24 public MaxNumber() {25 }26 27 28 public Comparator<T> getComp() {29 return comp;30 }31 32 public void setComp(Comparator<T> comp) {33 this.comp = comp;34 }35 36 public T max(T a, T b) {37 if (a != null && b != null) {38 if (comp == null) {39 return a.compareTo(b) > 0? a : b;40 } else {41 return comp.compare(a, b) > 0? a : b; 42 }43 } else {44 throw new IllegalArgumentException("參數有誤,空對象不能比較");45 }46 }47 48 public T max(T a, T b, T c) {49 return max(a, max(b, c));50 }51 52 }
然后在實例化maxNumber之后,setComp設置比較器comparator
1 Country china = new Country("中國", 1300000000L, 3000, 8); 2 Country russia = new Country("俄羅斯", 100000000L, 8000, 1); 3 Country america = new Country("美國", 400000000L, 32000, -5); 4 5 System.out.println(forCountry.max(russia, america)); 6 System.out.println(forCountry.max(china, russia, america)); 7 8 forCountry.setComp(new Comparator<Country>() { 9 10 @Override11 public int compare(Country o1, Country o2) {12 // TODO Auto-generated method stub13 return o1.getGdp() > o2.getGdp()? 1 : -1;14 }15 });16 17 System.out.println(forCountry.max(russia, america));18 System.out.println(forCountry.max(china, russia, america));
我們需要再對maxNumber做好排序,
1 package _05_Generic; 2 3 import java.util.Comparator; 4 5 /** 6 * 求若干個數的較大的一個 7 * 8 * 泛型實例 三,進一步抽象算法,可以比較N個,比較器動態化,支持默認比較器 9 * 10 * @author sgpro11 * 12 */13 14 class MaxNumber<T extends Comparable<T>>{15 16 public MaxNumber(Comparator<T> comp) {17 super();18 this.comp = comp;19 }20 21 private Comparator<T> comp = null;22 23 public MaxNumber() {24 }25 26 public Comparator<T> getComp() {27 return comp;28 }29 30 public void setComp(Comparator<T> comp) {31 this.comp = comp;32 }33 34 public T max(T... list) {35 T ret = null;36 if (list != null && list.length != 0) {37 ret = list[0];38 if (comp == null) {39 for (T o : list) {40 ret = o != null && o.compareTo(ret) > 0 ? o : ret;41 }42 }43 else {44 for (T o : list) {45 ret = o != null && comp.compare(o, ret) > 0 ? o : ret;46 }47 }48 }49 else {50 throw new IllegalArgumentException("參數有誤,比較元素序列為空");51 }52 return ret;53 }54 }
然后還是一樣,實例化maxNumber,設置comparator比較器進行比較。
下面還是使用Country的例子,分別按照默認(人口)、GDP、人均GDP,對中國、俄羅斯、日本、美國四個國家進行全方面的比較。
1 Country china = new Country("中國", 13, 13000, 8); 2 Country russia = new Country("俄羅斯", 2, 5000, 1); 3 Country japan = new Country("日本", 2, 30000, 9); 4 Country america = new Country("美國", 4, 100000, -5); 5 6 7 /** 8 * 默認人口 9 */10 System.out.println(s.max(china, russia, japan, america));11 12 /**13 * GDP14 */15 s.setComp(new Comparator<Country>() {16 17 @Override18 public int compare(Country o1, Country o2) {19 // TODO Auto-generated method stub20 return o1.getGdp() > o2.getGdp()? 1 : -1;21 }22 });23 24 System.out.println(s.max(china, russia, japan, america));25 26 /**27 * 人均GDP28 */29 Comparator<Country> avgGDPComp = new Comparator<Country>() {30 31 @Override32 public int compare(Country o1, Country o2) {33 // TODO Auto-generated method stub34 return o1.getGdp() / o1.getPopulation() > o2.getGdp() / o2.getPopulation()? -1 : 1; 35 }36 };37 38 s.setComp(avgGDPComp);39 40 System.out.println(s.max(china, russia, japan, america));
參考資料:sgpro的java泛型學習例子
新聞熱點
疑難解答