JAvaベース-listコレクションcontainsメソッド(最下位呼び出しequalsメソッド)を使用して再評価する問題について

4412 ワード

前言:今日は集合クラスを再学習し、練習中にリスト集合のcontainsメソッドに疑問を抱き、後で類似の疑問が発生しないように記録しました.
まず、練習のテーマとして、キーボード入力Person情報には名前と年齢が含まれている.入力名がexitと入力ときに入力2を終了する.Personオブジェクトをコレクションに格納名前と年齢が同じ人を同一人物と見なす場合は1つのオブジェクトのみを格納する(重さを除く).3つの方法で集合を巡回して集合中のPersonの名前と年齢を取得して出力する
まず、オブジェクト属性の格納と取得に使用するPerson JavaBeanを作成する必要があります.
class Person
{
	private String name;
	private int age;
	Person(){}
	Person(String name,int age){
		this.name = name;
		this.age = age;
	}
	public String getName(){
		return name;
	}
	public int getAge(){
		return age;
	}
	public String toString(){
		return "["+name+","+age+"]";
	
	}
}

出力オブジェクトのプロパティをフォーマットするためのtoStringメソッドも書き換えられています.
次に必要なのは、複数のオブジェクトを繰り返し作成してコレクションに格納することです.ループの方法で、タイトルの要求に応じてキーボード入力を実現し、「exit」を入力するとオブジェクトの作成を終了する必要があります.そのため、もう1つのデッドサイクルでオブジェクトの繰り返し作成と格納を行うことができます.ユーザーの入力値がexitであるかどうかを判断してループを飛び出します.
Scanner sc = new Scanner(System.in);
		List list = new ArrayList();
		for(;;){
			String name = sc.next();
			
			if(name.equals("exit")){
				break;
			}else{
				int age = sc.nextInt();
				list.add(new Person(name,age));//  
			}	
		}

ここでは集合に汎用型を指定するのではなく,ついでに多態の部分を練習する.
オブジェクトの格納が完了すると、格納されたオブジェクトの再処理が行われます.この問題を一目で見ると,まずループを用いて重複情報があるか否かを判断し,さらに重複情報を削除することを考えた後,集合のAPIをよく見てみると,contains法のような方法で重複除去の操作を完了できることが分かった.
containsメソッドの文字通りの意味は、1つの集合に指定された要素が存在するかどうかを判断する役割を果たすことを意味します.そのため、問題を解く構想が現れました.私たちは新しい集合を作成することができます.その中の要素は重複要素がありません.次に、反復器または他の遍歴方法によって元の集合の各要素を取得し、要素を遍歴するたびに新しい集合でcontainsメソッドを呼び出して、新しい集合にその要素が含まれているかどうかを判断し、含まれている場合はその要素をスキップし、遍歴を継続する.含まない場合は、新しいコレクションに追加します.実装コードは次のとおりです.
public static ArrayList getSingle(List list){
		ArrayList newList = new ArrayList();
		Iterator it = list.iterator();
		while(it.hasNext()){
			Object obj = it.next();
			if(!(newList.contains(obj))){
				newList.add(obj);
			}
		}
		return newList;
	}

これで方法が書き終わり、メインメソッドで直接呼び出せばいいです.しかし,メソッドを呼び出して新しい配列を取得すると,出力後,繰返し要素は除去されていないことが分かった.これはなぜですか.問題はcontainsメソッドにあるはずなので、この疑問を持ってcontainsメソッドのソースコードを見に行きました.ソースコードは以下の通りです.
    public boolean contains(Object o) {
        return indexOf(o) >= 0;
    }
 
   /*
     * Returns the index of the first occurrence of the specified element
     * in this list, or -1 if this list does not contain the element.
     * More formally, returns the lowest index i such that
     * (o==null ? get(i)==null : o.equals(get(i))),
     * or -1 if there is no such index.
*/
     
    public int indexOf(Object o) {
        if (o == null) {
            for (int i = 0; i < size; i++)
                if (elementData[i]==null)
                    return i;
        } else {
            for (int i = 0; i < size; i++)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }

containsメソッドが呼び出されるとindexOfメソッドが呼び出され、indexOfメソッドではまず入力された要素が空であるかどうかを判断し、空であれば呼び出しメソッドの集合の中で空の要素として探し、角標を返す.空でなければ,入力要素がある要素と等しいか否かをループ的に判断すると,equals法に基づいて判断されることが分かる.やはり問題はここで,ここでのequalsメソッドの場合の親のequalsメソッドは,デフォルトでは両者のアドレス値を比較する.呼び出しメソッドの集合と受信した要素のアドレス値は異なるに違いない.したがってcontainsメソッドはfalseに戻り、再操作が完了しません.では、原因が分かったら、どうすればいいのでしょうか.我々のPersonのデフォルトの親はObjectであり,Personオブジェクトを格納する際の配列要素はObjectタイプであり,親参照が子オブジェクトを指すことに相当し,Personクラスでequalsメソッドを書き換えると多態を形成する3つの前提条件に合致し,containsがequalsメソッドを呼び出して判断する場合,サブクラス書き換えのequalsメソッドがデフォルトで呼び出され、受信オブジェクトのプロパティ値の比較が完了します.では次はequalsメソッドを書き換えることです.
public boolean equals(Object obj){
		if(!(obj instanceof Person)){
			return false;
		}
		Person p = (Person)obj;
		//return this.getName().equals(p.getName())&&this.getAge()==p.getAge();
		//    String           ==  ,    equals  
		//  ,==     String   
		return this.getName().equals(p.getName())&&this.getAge()==p.getAge();
	}

注意コードのコメント部分の内容を書き換えます.
ここまでで、重量除去の作業が完了しました.次の3つの遍歴方法は簡単ですが、
//     
	public static void printList(List list){
		Iterator it = list.iterator();
		while(it.hasNext()){
			Person p = (Person)it.next();
			System.out.print(p.toString());
		}
		System.out.println();
	}
	//  for  
	public static void printList2(List list){
		for(int i = 0;i

完了します.removeメソッドもこの機能を完成させ、自分で拡張することができます.