Java学習記録(中級)-[3]、収集フレームワーク

まず、コレクションフレームワークの簡略図を見てみましょう。↓↓↓ 

(1)、コレクションインターフェイス

コレクションはListSetQueue(first in first out queue)Deque(double linked list)、およびその他のインターフェースの親インターフェースです

[注:コレクションとマップの間に関係はありません。コレクションにはオブジェクトが1つずつ含まれ、マップにはキーと値のペアが含まれます。]
[注:DequeはQueueを継承し、間接的にCollectionを継承します]

(2)、コレクションクラス

コレクションはクラスであり、コンテナのツールクラスです。アレイがアレイのツールクラスであるのと同様に、コンテナに対していくつかの操作を実行することもできます。

メソッド名のキーワード 特徴
逆行する 逆行する
シャッフル 混乱(注文の混乱)
ソート ソート
スワップ 指定された添え字位置でデータを交換します
回転する コレクション内のデータを、指定した単位の長さだけ右にスクロールします
同期リスト スレッドセーフでないコレクションをスレッドセーフコレクションに変換する
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class CollectionsTest {

	public static void main(String[] args) {
		// 初始化List
		List<Integer> list = new ArrayList<>();
		for (int i = 0; i < 10; i++) {
			list.add(i+1);
		}
		// 原List
		System.out.println("原list:\t\t\t" + list);
		
		
		
		System.out.println("******************************");
		
		
		
		// 反转
		Collections.reverse(list);
		System.out.println("反转后的list:\t\t" + list);
		
		
		
		System.out.println("******************************");
		
		
		
		// 混淆
		Collections.shuffle(list);
		System.out.println("混淆后的list:\t\t" + list);
		
		
		
		System.out.println("******************************");
		
		
		
		// 排序
		Collections.sort(list);
		System.out.println("排序后的list:\t\t" + list);
		
		
		
		System.out.println("******************************");
		
		
		
		// 交换两个位置的数据
		Collections.swap(list, 0, 1);
		System.out.println("交换0和1下标的数据后的list:\t" + list);
		
		
		
		System.out.println("******************************");
		
		
		
		// 先恢复原list
		Collections.swap(list, 0, 1);
		System.out.println("恢复后的list:\t\t" + list);
		// 滚动
		Collections.rotate(list, 3);
		System.out.println("向右滚动3个单位后的list:\t" + list);
		
		
		
		System.out.println("******************************");
		
		
		
		// 线程安全化
		List<Integer> newList = Collections.synchronizedList(list);
		// 把原来不是线程安全的list转换为了现在线程安全的newList
		
	}
	
}

出力結果:

(3)リストインターフェイスとArrayListクラス

Listコレクション内のオブジェクトは特定の順序で配置され、内部のコンテンツを繰り返すことができます。

Listインターフェイスによって実装されるクラスは、ArrayList(動的配列を実現するため)Vector(動的配列を実現するため)LinkedList(リンクリストを実現するため)Stack(スタックを実現するため)です。

[1]、アレイの使用の制限

複数のオブジェクトを保存する場合は、配列を使用できますが、配列には制限があります。

例:長さが10の配列を宣言すると、未使用の配列は無駄になり、10を超える数は収まりません!

[2]、ArrayList

配列の制限を解決するために、コンテナクラスの概念が導入されています。最も一般的なコンテナクラスは次のとおりです。ArrayList 
コンテナの容量「容量」は、オブジェクトが増加すると自動的に増加します。

[3] ArrayListの一般的なメソッド

メソッド名のキーワード 特徴
含まれています 存在するかどうかを確認します
追加 オブジェクトを追加
全て追加する 別のコンテナにすべてのオブジェクトを追加します
削除する オブジェクトを削除する
晴れ 空の
セットする 特定の位置でオブジェクトを置き換える(再割り当て)
取得する 指定された場所でオブジェクトを取得します
の指標 オブジェクトの場所を取得します
toArray 配列に変換
サイズ サイズを取得

[4]、イテレータートラバーサル

Iteratorを使用してコレクション内の要素をトラバースします。原則は次のとおりです。↓↓↓ 

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class IteratorTest {

	public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        
        for (int i = 0; i < 5; i++) {
			list.add("String " + i);
		}
        System.out.println("最初的list为:" + list);
        
        // 获取List的迭代器
        Iterator<String> iterator = list.iterator();
        
        //从最开始的位置判断"下一个"位置是否有数据
        //如果有就通过next取出来,并且把指针向下移动
        //直到"下一个"位置没有数据
        
        System.out.println("--------使用while的iterator-------");
        // 利用while循环遍历
        while(iterator.hasNext()) {
        	String str = iterator.next();
        	System.out.println(str);
        }
        
        System.out.println("--------使用for的iterator-------");
        // 利用for循环遍历
        for (Iterator<String> it = list.iterator(); it.hasNext(); ) {
			String str = it.next();
			if(str.equals("String 2")) {
				it.remove();
				System.out.println(str + "(当字符串为“String 2”时从迭代器中删除它)");
			}else {
				System.out.println(str);
			}
		}
        System.out.println("删除“String 2”后的list为:" + list);
        
         
    }

}

出力結果:

イテレーターを使用して、リスト内の要素を削除できます。

(4)、LinkedList

シーケンスは次のように分けられます。ファーストインファーストアウトFIFOファーストインラストアウトFILO 
FIFOは
Javaではキューとも呼ば れ、FILOはJavaではスタックとも呼ばれます。

[1] ArrayListと同様に、LinkedListもListインターフェイスを実装しています。

[2]しかし同時に、LinkedListはListインターフェースを実装するだけでなく、二重にリンクされたリスト構造Dequeも実装します。これにより、最初と最後にデータを簡単に挿入および削除できます。

import java.util.LinkedList;
import java.util.List;

public class CollectionsTest {
	
	public static void main(String[] args) {
        
        //LinkedList是一个双向链表结构的list
        LinkedList<String> list =new LinkedList<>();
         
        //所以可以很方便的在头部和尾部插入数据
        //在最后插入新的字符串
        list.addLast("String 1");
        list.addLast("String 2");
        list.addLast("String 3");
        System.out.println("加入数据后的list:\t\t" + list);
         
        //在最前面插入新的字符串
        list.addFirst("String X");
        System.out.println("最前面插入新的字符串后的list:\t" + list);
         
        //查看最前面的字符串
        System.out.println("最前面的字符串:\t\t " + list.getFirst());
        //查看最后面的字符串
        System.out.println("最后面的字符串:\t\t " + list.getLast());
         
        //查看不会导致元素被删除
        System.out.println("再次查看list:\t\t" + list);
        //取出最前面的字符串
        System.out.println("取出来的最前面的字符串:\t " + list.removeFirst());
         
        //取出最后面的字符串
        System.out.println("取出来的最后面的字符串:\t " + list.removeLast());
         
        //取出会导致元素被删除
        System.out.println("再次查看list:\t\t" + list);
         
    }
	
}

出力結果:

[3] ListとDequeの実装に加えてLinkedListはQueueインターフェイス(queue)も実装します。

キューは、ファーストインファーストアウトのキューFIFOであり、一般的に使用される方法は次のとおりです。

offer        在最后添加元素
poll         取出第一个元素
peek         查看第一个元素
import java.util.Deque;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;

public class CollectionsTest {

	public static void main(String[] args) {

		// 和ArrayList一样,LinkedList也实现了List接口
		List<String> list = new LinkedList<>();

		// 同时,LinkedList还实现了Deque接口
		// Deque代表双向链表
		Deque<String> deque = new LinkedList<>();

		// 同时,LinkedList也实现了Queue这个接口
		// Queue代表FIFO 先进先出的队列
		Queue<String> queue = new LinkedList<>();

		for (int i = 0; i < 2; i++) {
			queue.offer("String " + i); // 在最后添加元素
		}
		for (int i = 0; i < 3; i++) {
			queue.add("String " + (i + 2)); // 与offer()同样的效果,添加元素
		}    //
		System.out.println("利用offer()方法或add()方法添加元素。");
		System.out.println("添加元素后的queue为:\t" + queue);
		System.out.println();

		String first = queue.peek();    //
		System.out.println("利用peek()方法查看第一个元素。");
		System.out.println("查看第一个元素:\t\t " + first);
		System.out.println();

		queue.poll();    //
		System.out.println("利用poll()方法取出第一个元素。");
		System.out.println("取出第一个元素......");
		System.out.println("第一个元素取出后的queue为:\t" + queue);

	}

}

出力結果:

(5)バイナリツリー

バイナリツリーはさまざまなノードで構成されています。バイナリツリー
特徴:
       各ノードは、左の子ノード、右の子ノード、および値を持つことができます。

public class Node {
    // 左子节点
    public Node leftNode;
    // 右子节点
    public Node rightNode;
    // 值
    public Object value;
}

[1]、バイナリツリー-データの挿入-原則:

次の10個のランダムな数字がバイナリツリー
67、7、30、73、10、0、78、81、10、74
でソートされているとします。ソートの最初のステップは、データをバイナリツリーに
挿入することです挿入基本的なロジックは小さいです。 、左側の同じ場所が、右側の大きい
ルートノード1. 67
2. 7が67未満である、67の左ノードである
3. 30が67未満である、67の左ノードが発見され、そして30は、7以上であります
7の右側のノードを配置します。4。73は67より大きい、67の右側のノードを配置します。5。10は
67より小さい、67の左側のノードを見つける、10は7より大きい、7の右側のノードを見つける、30、10は30より小さい30の左側のノードに配置します。
...
...
9.10 67未満で左ノードを見つける677,10 7より大きい7、30の右ノード7を見つける、10 30時間以上で、左ノード30を10、10、10と同じ大きさで見つける左側に置く

public class Node {

	/**
	 * 左子节点
	 */
	public Node leftNode;
	/**
	 * 右子节点
	 */
	public Node rightNode;
	/**
	 * 值
	 */
	public Object value;

	/**
	 * 插入数据
	 * @param v
	 */
	public void add(Object v) {
		// 如果当前节点没有值,就把数据放在当前节点上
		if (value == null) {
			value = v;
		} else { // 如果当前节点有值,就进行判断,新增的值与当前的值的大小关系
			// 新增的值,比当前值小或者相同
			if ((Integer) value - (Integer) v >= 0) {
				if (leftNode == null) {
					leftNode = new Node();
				}
				leftNode.add(v);
			}
			// 新增的值,比当前值大
			else {
				if (rightNode == null) {
					rightNode = new Node();
				}
				rightNode.add(v);
			}
		}
	}

	public static void main(String[] args) {

		int randoms[] = new int[] { 67, 7, 30, 73, 10, 0, 78, 81, 10, 74 };
		Node roots = new Node();
		for (int number : randoms) {
			roots.add(number);
		}

	}

}

[2]、バイナリツリートラバーサル:

前のステップの挿入動作により、データは実際にソートされます。次に行うことは、これらのソートされたデータを確認し、一般的に使用されるリストまたは配列形式にトラバースすることです。バイナリツリートラバーサルは、1次、ミドルオーダー、および2次[1次]に分けられますつまり、トラバース後のミドルナンバーです。左側に配置[ミドルオーダー]:ミドルナンバーをトラバースして中央に配置[ポストオーダー]:ミドルナンバーをトラバースして右側に配置




import java.util.ArrayList;
import java.util.List;

public class Node {

	/**
	 * 左子节点
	 */
	public Node leftNode;
	/**
	 * 右子节点
	 */
	public Node rightNode;
	/**
	 * 值
	 */
	public Object value;

	/**
	 * 插入数据
	 * @param v
	 */
	public void add(Object v) {
		// 如果当前节点没有值,就把数据放在当前节点上
		if (value == null) {
			value = v;
		} else { // 如果当前节点有值,就进行判断,新增的值与当前的值的大小关系
			// 新增的值,比当前值小或者相同
			if ((Integer) value - (Integer) v >= 0) {
				if (leftNode == null) {
					leftNode = new Node();
				}
				leftNode.add(v);
			}
			// 新增的值,比当前值大
			else {
				if (rightNode == null) {
					rightNode = new Node();
				}
				rightNode.add(v);
			}
		}
	}

	// 先序遍历所有的节点
	public List<Object> valuesOfLeft() {
		
		List<Object> values = new ArrayList<>();
		
		// 当前节点
		values.add(value);
		
		// 左节点的遍历结果
		if (leftNode != null) {
			values.addAll(leftNode.valuesOfLeft());
		}
		
		// 右节点的遍历结果
		if (rightNode != null) {
			values.addAll(rightNode.valuesOfLeft());
		}
		
		return values;
		
	}

	// 中序遍历所有的节点
	public List<Object> valuesOfCenter() {
		
		List<Object> values = new ArrayList<>();
		
		// 左节点的遍历结果
		if (leftNode != null) {
			values.addAll(leftNode.valuesOfCenter());
		}
		
		// 当前节点
		values.add(value);
		
		// 右节点的遍历结果
		if (rightNode != null) {
			values.addAll(rightNode.valuesOfCenter());
		}
		
		return values;
		
	}

	// 后序遍历所有的节点
	public List<Object> valuesOfRight() {
		
		List<Object> values = new ArrayList<>();
		
		// 左节点的遍历结果
		if (leftNode != null) {
			values.addAll(leftNode.valuesOfRight());
		}
		
		// 右节点的遍历结果
		if (rightNode != null) {
			values.addAll(rightNode.valuesOfRight());
		}
		
		// 当前节点
		values.add(value);
		
		return values;
		
	}

	public static void main(String[] args) {

		int randoms[] = new int[] { 67, 7, 30, 73, 10, 0, 78, 81, 10, 74 };
		Node roots = new Node();
		for (int number : randoms) {
			roots.add(number);
		}

		System.out.println("先序遍历的二叉树:\t" + roots.valuesOfLeft());
		System.out.println("中序遍历的二叉树:\t" + roots.valuesOfCenter());
		System.out.println("后序遍历的二叉树:\t" + roots.valuesOfRight());

	}

}

出力結果:

(6)、HashMap

HashMapがデータを保存する方法は-キーと値のペア

HashMapの場合、キーは一意であり、繰り返すことはできません。 
したがって、同じキーを使用してマップに異なる値を挿入すると、古い要素が上書きされ、最後に挿入された要素のみが残ります。 
ただし、対応するキーが異なる限り、同じオブジェクトを値としてマップに挿入できます。

(7)、ハッシュセット

セット内の要素を繰り返すことはできません

[1]、注文なし

セット内の要素には順序がありません。 
厳密に言えば、

HashSetの特定の順序は、要素の挿入の順序ではなく、挿入の順序でもハッシュコードの順序でもありません。

つまり、HashSetに0〜9を挿入することも同じであり、JVMのバージョンによって表示の順序が異なります。

import java.util.HashSet;

public class HashSetTest {

	public static void main(String[] args) {

		HashSet<String> set = new HashSet<>();
		
		set.add("hello");
		set.add("world");
		set.add("!!!");
		
		System.out.println(set);
		
	}

}

動作結果:

[2]、トラバース

セットには、指定された位置にある要素を取得するためにget()は提供されません 
ので、イテレータや拡張forループ横断のために必要とされます

[3] HashSetとHashMapの関係

HashSetのソースコードを観察すると、HashSet自体には独立した実装はありませんが、Mapがカプセル化されている
ことがわかります
。HashSetはMapのキーとして存在し
、値はPRESENTという名前の静的オブジェクトオブジェクトです。クラス属性なので、1つだけになります。

private static final Object PRESENT = new Object();
package collection;

import java.util.AbstractSet;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;

public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, java.io.Serializable {
	// HashSet里封装了一个HashMap
	private HashMap<E, Object> map;

	private static final Object PRESENT = new Object();

	// HashSet的构造方法初始化这个HashMap
	public HashSet() {
		map = new HashMap<E, Object>();
	}

	// 向HashSet中增加元素,其实就是把该元素作为key,增加到Map中
	// value是PRESENT,静态,final的对象,所有的HashSet都使用这么同一个对象
	public boolean add(E e) {
		return map.put(e, PRESENT) == null;
	}

	// HashSet的size就是map的size
	public int size() {
		return map.size();
	}

	// 清空Set就是清空Map
	public void clear() {
		map.clear();
	}

	// 迭代Set,就是把Map的键拿出来迭代
	public Iterator<E> iterator() {
		return map.keySet().iterator();
	}

}

(8)、セット

HashSet
UnorderedLinkedHashSet挿入順序
TreeSetに従って小さいものから大きいものへと並べ替えます

import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.TreeSet;

public class HashSetTest {
	
	public static void main(String[] args) {

        HashSet<String> numberSet1 =new HashSet<>();
        //HashSet中的数据不是按照插入顺序存放
        numberSet1.add("bbbbb");
        numberSet1.add("aaaaa");
        numberSet1.add("ccccc");
        System.out.println(numberSet1);
          
        LinkedHashSet<String> numberSet2 =new LinkedHashSet<>();
        //LinkedHashSet中的数据是按照插入顺序存放
        numberSet2.add("bbbbb");
        numberSet2.add("aaaaa");
        numberSet2.add("ccccc");
        System.out.println(numberSet2);

        TreeSet<String> numberSet3 =new TreeSet<>();
        //TreeSet 中的数据是进行了排序的
        numberSet3.add("bbbbb");
        numberSet3.add("aaaaa");
        numberSet3.add("ccccc");
        System.out.println(numberSet3);
          
    }

}

動作結果:

(9)ArrayListとLinkedListの違い

ArrayListは、[シーケンスリスト]、[データの高速検索]、[データの挿入と削除が遅い
]の構造です。LinkedListは[リンクリスト]構造、[データの検索が遅い]、[データの挿入と削除が高速]です。

(10)ArrayListとHashSetの違い

ArrayListには順序があり、データを繰り返すことができます
。HashSetには順序がなく、データを繰り返すことはできません。

HashSetの繰り返しの判断基準は、
最初にハッシュコードが同じかどうかを確認します。
ハッシュコードが異なる場合は、異なるデータと見なされます。
ハッシュコードが同じ場合は、等しいと比較します。等しい場合は同じデータです。それ以外の場合は、異なるデータです。

(11)HashMapとHashTableの違い

 

HashMapとHashtableはどちらもMapインターフェイスを実装しており、どちらもデータを格納するためのキーと値のペアです。
違い1: 
HashMapはnull値を
格納できHashtableはnull値を格納できません。
違い2:
HashMapはスレッドセーフクラスではありません
Hashtableはスレッドセーフクラスです

import java.util.HashMap;
import java.util.Hashtable;

public class MapTableTest {

	public static void main(String[] args) {

		// HashMap 可以存放 null 值
		HashMap<String, Integer> map = new HashMap<>();
		map.put("first", null);
		System.out.println(map);

		// Hashtable 不能存放null 值
		Hashtable<String, Integer> table = new Hashtable<>();
		table.put("first", null);
		System.out.println(table);

	}

}

動作結果:

(12)HashCodeの原則

[1]、効率の比較

HashCodeによってもたらされる違いは次のとおりです。

[2]、HashCodeの原則

たとえば、英語-中国語辞書で単語の対応する中国語の意味を検索する場合、その単語がLengthdaryであると仮定し、最初に555ページのディレクトリでLengthdaryを検索します。 

次に、555ページを参照してください。このページには単語が1つしかないだけでなく、量も非常に少ないので、1つずつ比較して、目的の単語の長さをすばやく見つけます。

555は、Lengendaryに対応するハッシュコードに相当します

[3]、HashMapの優れたパフォーマンスの理由を分析します

-----
ハッシュコードの概念-----すべてのオブジェクトには対応するハッシュコード(ハッシュ値)があります。たとえば
、文字列「gareen」は1001に対応します(実際にはそうではありません。ここでは、仮想値を理解するのに便利な値です)。 )たとえば
、文字列「temoo」は1004に対応します。
たとえば、文字列「db」は1008に対応します。
たとえば、文字列「annie」は1008に対応し

ます。-----データを保存します-----
長さが次の配列を準備します。2000、特別なハッシュコードアルゴリズムを設定して、すべての文字列に対応するハッシュコード
が0〜999になるようにします。名前が「gareen」のヒーローを保存するには、ヒーローと名前がキーと値のペアを形成し、
名前が「temoo」のヒーローを配列の位置1001に格納するには、ヒーローを配列の位置1004に格納します。
名前が「db」のヒーローを格納するには、ヒーローを配列の位置1008に格納します。
名前が「annie」であるが、「annie」のハッシュコード1008に対応する場所にすでにdbヒーローが存在するヒーローを保存するには、ここにリンクリストを作成し、dbヒーローの後にannieを保存し

ます-----データの検索- ---たとえば
、gareenを見つけるには、最初に「gareen」のハッシュコードを1001と計算し、1001の添え字に従って配列内で見つけます(配列の添え字に従って見つけるのは非常に高速です)。1001の位置は1つだけであることがわかります。ヒーロー、そしてヒーローはガリーンです。
たとえば、アニーを見つけるには、最初に「アニー」のハッシュコードを1008と計算します。1008の添え字に従って、配列内を見つけて、位置1008に2人のヒーローがいることを確認し、2人のヒーローの名前を1つずつ比較します(等しい) 、現時点で比較する量がはるかに少なく、ターゲットヒーローをすぐに見つけることができるためです。
これはクエリにハッシュマップを使用するため、非常に高速です。


これは時間に空間を使う考え方です

åæHashMapæ§è½åè¶çåå 

[4]、HashSetはそれが繰り返されるかどうかを判断します

HashSetのデータを繰り返すことはできません。同じデータを一緒に保存することはできません。繰り返されるかどうかを判断するにはどうすればよいですか。
HashSetとHashMapの関係によると、HashSetには独自の実装がなく、代わりにHashMapをカプセル化するため、基本的にHashMapのキーが重複しているかどうかを判断することがわかりました。

前の学習ステップでは、キーが繰り返される
かどうかは、ハッシュコードが同じかどうか、ハッシュ
        コードが異なる
        場合は別のピットにあるか、ハッシュコードが同じ場合は同じピットにあるかという2つのステップで判断されます。また、
                等しいものを比較する必要があります。等しいものが同じである場合、それは重複データです。
                等しいものが同じでない場合、それは異なるデータです。

(13)コンパレータ

Collections.sort()メソッドは、コレクション内の要素を並べ替えることができます

ただし、コレクションがある場合、その中の要素はすべてPersonタイプのオブジェクトであり、その属性には、並べ替える属性に応じて、名前、年齢、住所などが含まれます。

これにはコンパレータが必要です!

[1]、方法1

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Random;

public class ComparatorTest {

	public static void main(String[] args) {

		Random r = new Random();
		List<Person> persons = new ArrayList<>();

		for (int i = 0; i < 10; i++) {
			persons.add(new Person("张" + i, r.nextInt(20) + 20, "西安"));
		}
		System.out.println("初始化后的集合:");
		System.out.println(persons);

		// 直接调用sort会出现编译错误,因为Person有各种属性
		// 到底按照哪种属性进行比较,Collections也不知道,不确定,所以没法排
		// Collections.sort(persons);

		// 引入Comparator,指定比较的算法
		Comparator<Person> c = new Comparator<Person>() {
			@Override
			public int compare(Person p1, Person p2) {
				// 按照hage进行排序
				if (p1.age >= p2.age)
					return 1; // 正数表示p1比hp2要大
				else
					return -1;
			}
		};
		Collections.sort(persons, c);
		System.out.println("按照年龄排序后的集合:");
		System.out.println(persons);

	}

}

class Person {
	public String name;
	public int age;
	public String address;

	public Person(String name, int age, String address) {
		this.name = name;
		this.age = age;
		this.address = address;
	}

	@Override
	public String toString() {
		return "\n" + "Name : " + name + "\tAge : " + age + "\tAddress : " + address;
	}

}

結果:

[2]、方法2

PersonクラスにComparableインターフェイスを実装させます
。クラスに比較アルゴリズム
Collections.sortを提供して、ソートに十分な情報を取得します。追加のコンパレータComparatorを提供する必要はありません。

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Random;

public class ComparatorTest {

	public static void main(String[] args) {

		Random r = new Random();
		List<Person> persons = new ArrayList<>();

		for (int i = 0; i < 10; i++) {
			persons.add(new Person("张" + i, r.nextInt(20) + 20, "西安"));
		}
		System.out.println("初始化后的集合:");
		System.out.println(persons);

		// 直接调用sort会出现编译错误,因为Person有各种属性
		// 到底按照哪种属性进行比较,Collections也不知道,不确定,所以没法排
		// Collections.sort(persons);

		// 引入Comparator,指定比较的算法
		Comparator<Person> c = new Comparator<Person>() {
			@Override
			public int compare(Person p1, Person p2) {
				// 按照hage进行排序
				if (p1.age >= p2.age)
					return 1; // 正数表示p1比hp2要大
				else
					return -1;
			}
		};
		
		//Person类实现了接口Comparable,即自带比较信息。
        //Collections直接进行排序,无需额外的Comparator
		Collections.sort(persons);
		System.out.println("按照年龄排序后的集合:");
		System.out.println(persons);

	}

}

class Person implements Comparable<Person> {
	public String name;
	public int age;
	public String address;

	public Person(String name, int age, String address) {
		this.name = name;
		this.age = age;
		this.address = address;
	}

	@Override
	public String toString() {
		return "\n" + "Name : " + name + "\tAge : " + age + "\tAddress : " + address;
	}

	@Override
	public int compareTo(Person o) {
		if (age > o.age) {
			return 1;
		}
		return -1;
	}

}

動作結果:

おすすめ

転載: blog.csdn.net/qq_37164975/article/details/82688248