1. 程式人生 > 實用技巧 >Java 從入門到進階之路(二十五)

Java 從入門到進階之路(二十五)

在之前的文章我們介紹了一下 Java 中的 集合框架中的Collection 的子介面 List的 增刪改查和與陣列間相互轉換的方法,本章我們來看一下 Java 集合框架中的Collection 的子介面 List 的另外一些方法。

我們在使用集合的時候難免會對其中的元素進行排序,因為 Set 集合本身是無序的,所以本章將著重講解 List 集合,如下:

 import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random; /**
* 排序集合元素
* 排序集合使用的是集合的工具類 Collections 的靜態方法 sort
* 排序僅能對 List 集合進行,因為 Set 部分實現類是無序的
* */
public class Main {
public static void main(String[] args) {
List<Integer> list = new ArrayList<Integer>();
Random random = new Random();
for(int i=0;i<10;i++){
list.add(random.nextInt(100));
}
System.out.println(list); // [49, 24, 29, 59, 56, 1, 1, 5, 49, 60] Collections.sort(list);
System.out.println(list); // [1, 1, 5, 24, 29, 49, 49, 56, 59, 60]
}
}

在上面的程式碼中,我們隨機生成了一些正數並新增到 List 集合中,我們通過 sort 方法,系統變自動按照自然數的排列方法為我們做好了排序,很是方便,那如果 List 中使我們自己定義的內容,比如說一個類,那該如何排序呢,如下:

import java.util.ArrayList;
import java.util.Collections;
import java.util.List; /**
* 排序集合元素
* 排序集合使用的是集合的工具類 Collections 的靜態方法 sort
* 排序僅能對 List 集合進行,因為 Set 部分實現類是無序的
*/
public class Main {
public static void main(String[] args) {
List<Point> list = new ArrayList<Point>();
list.add(new Point(1, 2));
list.add(new Point(2, 3));
list.add(new Point(4, 2));
list.add(new Point(2, 5));
list.add(new Point(9, 3));
list.add(new Point(7, 1));
System.out.println(list); // [(1, 2), (2, 3), (4, 2), (2, 5), (9, 3), (7, 1)]
// Collections.sort(list); // 編譯錯誤,不知道 Point 排序規則
/**
* sort 方法要求集合必須實現 Comparable 介面
* 該介面用於規定實現類事可以比較的
* 其中一個 compareTo 方法時用來定義比較大小的規則
* */
Collections.sort(list);
System.out.println(list); // [(1, 2), (2, 3), (4, 2), (2, 5), (7, 1), (9, 3)] }
} class Point implements Comparable<Point> { // 定義為泛型 T 型別
private int x;
private int y; public Point(int x, int y) {
this.x = x;
this.y = y;
} public int getX() {
return x;
} public void setX(int x) {
this.x = x;
} public int getY() {
return y;
} public void setY(int y) {
this.y = y;
} @Override
public String toString() {
return "(" + x + ", " + y + ")";
} /**
* 當實現了 Comparable 介面後,需要重寫下面的方法
* 該方法的作用是定義當前物件與給定引數物件比較大小的規則
* 返回值為一個 int 值,該值表示大小關係
* 它不關注具體的取值是多少,而關注的是取值範圍
* 當返回值 >0 時:當前物件不引數物件大
* 當返回值 <0 時:當前物件比引數物件小
* 當返回值 =0 時:兩個物件相等
*/
@Override
public int compareTo(Point o) {
/**
* 比較規則,點到原點的距離長的打
* */
int len = this.x * this.x + this.y * this.y;
int olen = o.x * o.x + o.y * o.y;
return len - olen;
}
}

在上面的程式碼中,我們跟之前一樣定義了一個 Point 類,然後例項化後存入 list 集合中,如果我們相對 Point 進行排序,如果直接呼叫 sort 方法會報錯,這是由於編譯器不知道我們定義的 Point 類的排序規則,所以我們需要通過介面 Comparable 介面來自定義排序規則,如下圖:

我們可以通過座標系中點到原點的距離來判斷 Point 的大小,即 x*x+y*y 的大小,然後通過重寫 compareTo 方法來實現 sort 。

實際上雖然能實現,但是並不理想,為了實現一個 sort 方法,要求我們的集合元素必須實現 Comparable 介面並且定義比較規則,這種我們想使用某個功能,而它要求我們修改程式的現象稱為“侵入性”。修改的程式碼越多,侵入性越強,越不利於程式的擴充套件。

我們再來看一下下面的排序:

 import java.util.ArrayList;
import java.util.Collections;
import java.util.List; public class Main {
public static void main(String[] args) {
List<String> list1 = new ArrayList<String>();
list1.add("Java");
list1.add("c++");
list1.add("Python");
list1.add("PHP");
Collections.sort(list1);
System.out.println(list1); // [Java, PHP, Python, c++] List<String> list2 = new ArrayList<String>();
list2.add("孫悟空");
list2.add("豬八戒");
list2.add("唐僧");
list2.add("六小齡童");
Collections.sort(list2);
System.out.println(list2); // [六小齡童, 唐僧, 孫悟空, 豬八戒] }
}

在上面的排序中,當我們對字母或漢字進行排序時,其實是比的第一個字的 Unicode 碼,那如果我們不使用 Comparable 的介面該如何自定義我們想要的實現規則呢?比如根據字串的長度來進行排序,其實 sort 有一個額外的過載方法來實現我們想要的結果,如下:

 import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List; public class Main {
public static void main(String[] args) {
/**
* 過載的 sort 方法要求傳入一個額外的比較器
* 該方法不再要求集合元素必須實現 Comparable 介面
* 並且不再使用集合元素資深的比較規則排序了
* 而是根據給定的這個額外的比較器的比較規則對集合元素進行排序
* 實際開發中也推薦使用這種方式進行集合元素排序
* 若集合元素是自定義的
* 建立比較器時推薦使用匿名內部類的形式
*/
List<String> list1 = new ArrayList<String>();
list1.add("Java");
list1.add("c++");
list1.add("Python");
list1.add("PHP");
MyComparator myComparator1 = new MyComparator();
Collections.sort(list1, myComparator1); // 過載 sort
System.out.println(list1); // [c++, PHP, Java, Python] List<String> list2 = new ArrayList<String>();
list2.add("孫悟空");
list2.add("豬八戒");
list2.add("唐僧");
list2.add("六小齡童");
// 匿名內部類形式建立
Comparator<String> myComparator2 = new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.length() - o2.length();
}
};
Collections.sort(list2, myComparator2); // 過載 sort
System.out.println(list2); // [唐僧, 孫悟空, 豬八戒, 六小齡童] }
} /**
* 定義一個額外的比較器
* 該方法用來定義 o1 和 o2 的比較
* 若返回值 >0:o1>o2
* 若返回值 <0:o1<o2
* 若返回值 =0:兩個物件相等
*/
class MyComparator implements Comparator<String> {
@Override
public int compare(String o1, String o2) {
/**
* 字串中字元多的大
* */
return o1.length() - o2.length();
}
}