使用comparable接口對(duì)非數(shù)字類型數(shù)組排序
/**
* 使用comparable接口對(duì)數(shù)組排序
* 數(shù)組元素不是數(shù)字類型時(shí) 通過(guò)實(shí)現(xiàn)comparable接口重寫規(guī)定比較方法 依據(jù)比較方法進(jìn)行Arrays.sort()
*/
public class TestComparable implements Comparable{
? ?//實(shí)現(xiàn)Comparable接口
? ?private int id;
? ?private int age;
? ?private String name;
? ?//每個(gè)對(duì)象三個(gè)屬性 設(shè)想通過(guò)比較age來(lái)對(duì)對(duì)象排序
? ?public TestComparable(){}
? ?public TestComparable(int id, int age, String name) {
? ? ? ?this.id = id;
? ? ? ?this.age = age;
? ? ? ?this.name = name;
? ?}
? ?@Override
? ?public int compareTo(Object o) {
? ? ? ?//重寫實(shí)現(xiàn)compareTo()方法
? ? ? ?TestComparable t = (TestComparable)o;
? ? ? ?//將形參強(qiáng)制轉(zhuǎn)型 形參o必須和接口的方法一致 形參類型改變的話不構(gòu)成重寫
? ? ? ?//重寫的方法名、形參列表必須相同
? ? ? ?if (age<t.age){
? ? ? ? ? ?return -1;
? ? ? ?} else if (age>t.age) {
? ? ? ? ? ?return 1;
? ? ? ?}
? ? ? ?return 0;
? ?}
????@Override
????public String toString() {
? ?????return ""+age;
????? ?//使打印對(duì)象println(TestComparable)時(shí)默認(rèn)打印對(duì)象的age屬性
????????//不能直接返回age 重寫方法的返回值類型只能小于等于原返回值類型 int和String是????????不相干的兩種類型 不能更改成int
????????//沒(méi)法更改返回值類型就必須將age前面加""變成字符串
????}
? ?public static void main(String[] args) {
? ? ? ?TestComparable[] t = {
? ? ? ? ? ? ? ?new TestComparable(1,10,"Jack"),
? ? ? ? ? ? ? ?new TestComparable(2,12,"Jim"),
? ? ? ? ? ? ? ?new TestComparable(3,9,"Tom")
? ? ? ?};
? ? ? ?//太長(zhǎng)了 換行將結(jié)構(gòu)變明顯
? ? ? ?Arrays.sort(t);
? ? ? ?//sort()調(diào)用compareTo()方法 根據(jù)返回值決定是否調(diào)換處于比較中的兩個(gè)元素的位置 反復(fù)調(diào)整后按順序排好元素
? ? ? ?System.out.println(Arrays.toString(t));
????????//靜態(tài)方法Arrays.toString(t)會(huì)返回String.valueOf(t[i])
????????//String.valueOf(t[i]) 判斷如果元素為null就返回"null" 否則返回Object.toString
????????// 這里因?yàn)橹貙懥藅oString 實(shí)際調(diào)用的是 t[i].toString 返回age 結(jié)果[9,10,12]
? ?}
}
//模擬sort()方法調(diào)用compareTo()排序的過(guò)程
interface a1{
? ?//定義接口a1模擬Comparable接口
? ?int bi(Object o);
? ?//接口的抽象方法 先有接口后有實(shí)現(xiàn)類 現(xiàn)階段沒(méi)有寫實(shí)現(xiàn)類 所以形參只能寫Object類或a1 因?yàn)樗蓄惗紝儆贠bject類 這樣構(gòu)成了多態(tài)
? ?//返回值int的用法是 返回正數(shù)就認(rèn)為在排序中this>o 返回負(fù)數(shù)就認(rèn)為在排序中this<o 最后按照大小來(lái)排序
? ?//這樣規(guī)定的結(jié)果是排序方法不需要自己評(píng)判兩個(gè)元素哪個(gè)大哪個(gè)小 只需要調(diào)用bi()方法 bi()會(huì)返回正數(shù)或負(fù)數(shù)告訴排序方法this大還是o大
? ?// 排序方法看到正數(shù)就交換兩個(gè)元素 看到負(fù)數(shù)就保持現(xiàn)狀
? ?//排序方法只負(fù)責(zé)根據(jù)bi()返回結(jié)果對(duì)順序進(jìn)行調(diào)整 具體如何大小如何評(píng)判由實(shí)現(xiàn)類來(lái)規(guī)定bi()
? ?// 這樣每個(gè)類都能有自己的評(píng)判標(biāo)準(zhǔn) 只需要按照接口和排序方法的要求格式寫好bi()就能調(diào)用排序方法了
? ?//接口負(fù)責(zé)注釋通過(guò)bi()評(píng)判大小的思路 排序方法負(fù)責(zé)根據(jù)評(píng)判結(jié)果進(jìn)行排序 實(shí)現(xiàn)類根據(jù)自己的情況選擇各自的參數(shù)(年齡、身高、體重等等)作為bi()評(píng)判的標(biāo)準(zhǔn)
}
class a2{
? ?public static void pai(a1[] a){
? ?//模擬Arrays類的sort()方法 通過(guò)調(diào)用bi()的正負(fù)值來(lái)對(duì)元素排序 思路是如果返回正數(shù)即this>o就交換兩個(gè)元素 返回負(fù)數(shù)即this<o順序正確保持現(xiàn)狀
? ? ? ?//排序方法會(huì)對(duì)數(shù)組本身進(jìn)行更改 所以運(yùn)行完方法時(shí)實(shí)參數(shù)組已經(jīng)改變了 不需要再特意返回更改的實(shí)參結(jié)果
? ? ? ?//用static修飾 是因?yàn)橐判虻臄?shù)組是本類a2以外的類的數(shù)組 不是a2[]類型 沒(méi)有必要在進(jìn)行排序時(shí)先new一個(gè)a2對(duì)象 再通過(guò)對(duì)象調(diào)用排序方法 這個(gè)對(duì)象的生成多此一舉
? ? ? ?//直接指明是調(diào)用a2類的方法a2.pai()對(duì)數(shù)組進(jìn)行排序 靜態(tài)方法屬于類
? ? ? ?// 靜態(tài)方法內(nèi)不能使用this this是用于對(duì)象名.方法(){方法體里面指代對(duì)象名的} 靜態(tài)方法不屬于對(duì)象沒(méi)有對(duì)象所以不能用this
? ?//對(duì)數(shù)組進(jìn)行排序的話肯定要把數(shù)組傳參進(jìn)方法中 因?yàn)殪o態(tài)方法不能通過(guò)對(duì)象名.pai()的this來(lái)指代數(shù)組 所以傳參只能通過(guò)(括號(hào)內(nèi)的形參) 即用形參列表表示要排序的數(shù)組
? ? ? ?// 具體評(píng)判大小交給bi()方法來(lái)評(píng)判 所以形參一定是實(shí)現(xiàn)了a1接口的實(shí)現(xiàn)類 形參類型寫接口名構(gòu)成多態(tài) 以后所有a1的實(shí)現(xiàn)類都能用pai()方法排序
? ?//排序方法中不考慮實(shí)現(xiàn)類怎么實(shí)現(xiàn)的接口 只需要認(rèn)為bi()已經(jīng)被按要求實(shí)現(xiàn)了
? ?//具體如何實(shí)現(xiàn)等到定義實(shí)現(xiàn)類時(shí) 按照排序方法的需求再進(jìn)行設(shè)計(jì)
? ? ? ?//這里排序的思路是利用.bi(o)的返回值來(lái)判斷大小 排序按由小到大 this比o大就返回正數(shù) if(正數(shù))就將this和o交換
? ? ? ?// 不考慮bi()方法具體怎么比較和比較了什么 只規(guī)定返回正數(shù)就是this比o大 要交換 返回負(fù)數(shù)就是this比o小不換位置
? ? ? ?for (int i = 0; i<a.length-1;i++){
? ? ? ? ? ?//排序從index=0開(kāi)始
? ? ? ? ? ?for (int j = i+1;j<a.length;j++){
? ? ? ? ? ? ? ?//將index元素和后面所有元素逐一比較 返回正數(shù)即比后面的元素大就交換位置
? ? ? ? ? ? ? ?if (a[i].bi(a[j])>0) {
? ? ? ? ? ? ? ? ? ?a1 aa = a[i];
? ? ? ? ? ? ? ? ? ?a[i] = a[j];
? ? ? ? ? ? ? ? ? ?a[j] = aa;
? ? ? ? ? ? ? ?}
? ? ? ? ? ?}
? ? ? ?}
// ? ? ? ?//另一種方式 冒泡法 思路:從左開(kāi)始依次比較相鄰兩個(gè)元素 左大于右即交換 比較一輪 一輪結(jié)束最右側(cè)就是最大的 下一輪再運(yùn)算出第二大的 循環(huán)直至排序完成
// ? ? ? ?boolean ready;
// ? ? ? ?//優(yōu)化 設(shè)置一個(gè)狀態(tài)值
// ? ? ? ?for (int i =0; i<a.length; i++){
// ? ? ? ? ? ?ready = true;
// ? ? ? ? ? ?for (int j = 0;j<a.length-i-1;j++){
// ? ? ? ? ? ? ? ?if (a[j].bi(a[j+1])>0){
// ? ? ? ? ? ? ? ? ? ?a1 aa = a[j];
// ? ? ? ? ? ? ? ? ? ?a[j] = a[j+1];
// ? ? ? ? ? ? ? ? ? ?a[j+1] =aa;
// ? ? ? ? ? ? ? ? ? ?ready = false;
// ? ? ? ?//如果發(fā)生了交換 即左邊比右邊大 說(shuō)明當(dāng)前排序可能還沒(méi)完全捋順
// ? ? ? ? ? ? ? ?}
// ? ? ? ? ? ? ? ?if (ready)break;
? ? ? ?//如果在這一次for(j)循環(huán)中沒(méi)有交換,即每一個(gè)左邊元素都比右邊元素小 比如下標(biāo)0比下標(biāo)1小 下標(biāo)1比下標(biāo)2小 那么下標(biāo)0一定比下標(biāo)2小
? ? ? ?//每一個(gè)左邊都比右邊小 意味著數(shù)組整體從左往右從小到大排好了 break省略剩余的循環(huán)
// ? ? ? ? ? ?}
// ? ? ? ?}
? ?}
? ?public static void main(String[] args) {
? ? ? ?a3[] x = {new a3(2),new a3(1),new a3(3)};
? ? ? ?//實(shí)現(xiàn)類a3的聲明放在下面了? 這里靜態(tài)初始化了a3[]數(shù)組x
? ? ? ?pai(x);
? ? ? ?//對(duì)數(shù)組進(jìn)行排序
? ? ? ?System.out.println(x[0].id);
? ? ? ?System.out.println(x[1].id);
? ? ? ?System.out.println(x[2].id);
? ? ? ?//結(jié)果 1 2 3
? ?}
}
class a3 implements a1{
? ?//類a3 實(shí)現(xiàn) 接口a1
? ?int id;
? ?public a3(int id) {
? ? ? ?this.id = id;
? ?}
? ?public int bi(Object a){
? ? ? ?//重寫接口的方法 思路是通過(guò).id的值來(lái)定大小
? ? ? ?//重寫的方法名、形參列表要保持一致 返回值類型小于等于原類型
? ? ? ?a3 _a = (a3)a;
? ? ? ?//因?yàn)樾螀⒘斜肀仨毐3忠恢?所以即便知道比的對(duì)象是a3類也要用Object引用 再?gòu)?qiáng)轉(zhuǎn)成a3類
? ? ? ?if (id<_a.id){
? ? ? ? ? ?//實(shí)現(xiàn)的思路是比較兩個(gè)對(duì)象id的值 this.id比_a.id小的話就認(rèn)為this小于_a返回負(fù)數(shù) 在pai()方法中負(fù)數(shù)就不換位置
? ? ? ? ? ?return -1;
? ? ? ?}
? ? ? ?return 1;
? ? ? ?//this大于等于_a返回正數(shù) pai()中定義如果返回正數(shù)就將兩個(gè)元素交換
? ? ? ?//因?yàn)閜ai()方法設(shè)定為if(返回正數(shù))就交換位置 可以通過(guò)更改bi()的返回值實(shí)現(xiàn)排序由大到小或由小到大
? ? ? ?// 上面的結(jié)果是由小到大 將if(id<_a.id)改為return 1 下面改為-1就變成了由大到小
????????//返回值為正數(shù)就交換 所以如果想讓左邊小于右邊時(shí)候交換 就if(左<右)return 1 讓左小于右的情況返回正數(shù) 就會(huì)實(shí)現(xiàn)從大到小的排序了
? ?}
}