質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.37%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Q&A

解決済

3回答

31599閲覧

クラスリストの比較でcontainsが動作してくれない

isacRu

総合スコア64

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

0グッド

0クリップ

投稿2016/11/23 02:47

containsを用いて2つのクラスリストを比較したいのですが、うまく動作してくれません。

java

1class Order{ 2 public int id; 3 public String name; 4 public Order(int id,String name){ 5 this.id = id; 6 this.name = name; 7 } 8} 9class Food{ 10 public int id; 11 public String name; 12 public Food(int id,String name){ 13 this.id = id; 14 this.name = name; 15 } 16} 17 18public class App { 19 public static void main(String[] args) { 20 21 List<Order> orderList = new ArrayList<>(); 22 List<Food> foodList = new ArrayList<>(); 23 24 orderList.add(new Order(1,"アップル")); 25 orderList.add(new Order(2, "バナナ")); 26 orderList.add(new Order(3, "綿菓子")); 27 28 foodList.add(new Food(1,"アップル")); 29 foodList.add(new Food(2, "バナナ")); 30 31 for (int i = 0; i < orderList.size(); i++) { 32//比較してくれない 33 if(!foodList.contains(orderList.get(i).name)){ 34 System.out.println(orderList.get(i).name); 35 } 36 37 } 38 }

foodListとorderListを比較し、foodListにないものを参照しようとしています。なぜかうまく比較してくれないので、疑問でした。なぜうまく比較してくれないのか、また解決策を教えてください。

ちなみに整数型リストは比較してくれました。

java

1public class App { 2 public static void main(String[] args) { 3 List<Integer> lst1 = new ArrayList<>(); 4 List<Integer> lst2 = new ArrayList<>(); 5 6 lst1.add(0); 7 lst1.add(1); 8 9 lst2.add(0); 10 lst2.add(1); 11 lst2.add(2); 12 13 for (int index = 0;index < lst2.size();index++) { 14//ちゃんと比較してくれた 15 if(!lst1.contains(lst2.get(index))){ 16 System.out.println(lst2.get(index)); 17 } 18 } 19 }

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

equalをオーバーライドした解決策

java

1import java.util.*; 2 3class Order{ 4 5public boolean equals(Object o){ 6 7if((o instanceof Food) && (((Food)o).id==this.id) && (((Food)o).name.equals(this.name))){ 8return true; 9 10}else return false; 11} 12 13 public int id; 14 public String name; 15 public Order(int id,String name){ 16 this.id = id; 17 this.name = name; 18 } 19} 20class Food{ 21 22 23 24 25 public int id; 26 public String name; 27 public Food(int id,String name){ 28 this.id = id; 29 this.name = name; 30 } 31} 32 33public class App { 34 public static void main(String[] args) { 35 36 List<Order> orderList = new ArrayList<>(); 37 List<Food> foodList = new ArrayList<>(); 38 39 orderList.add(new Order(1,"アップル")); 40 orderList.add(new Order(2, "バナナ")); 41 orderList.add(new Order(3, "綿菓子")); 42 43 foodList.add(new Food(1,"アップル")); 44 foodList.add(new Food(2, "バナナ")); 45 for (int i2 = 0; i2 < orderList.size(); i2++) { 46 47//比較してくれない 48 if(!(foodList.contains(orderList.get(i2)))){ 49 System.out.println(orderList.get(i2).name); 50 } 51 52 } 53 } 54}

反射性等が問題になるという旨指摘がありましたので現在訂正した部分までを下記に記載しておきます
再訂正

java

1 2    import java.util.*; 3 4class Order{ 5public boolean equals(Object o){ 6if((o instanceof Food) && (((Food)o).id==this.id) && (((Food)o).name.equals(this.name))){ 7return true; 8 9} 10else if((o instanceof Order) && (o.hashCode()==this.hashCode())){ 11return true; 12 13} 14return false; 15} 16public int hashCode(){ 17 18 19char[] cA = name.toCharArray(); 20 21int ch=0; 22 23for(char t:cA){ 24int g=(int)t; 25 26 27ch+=g; 28 29} 30 31 32return id*1000+ch; 33 34} 35 36public int id; 37public String name; 38public Order(int id,String name){ 39this.id = id; 40this.name = name; 41} 42} 43class Food{ 44 45 46public int hashCode(){ 47 48 49char[] cA = name.toCharArray(); 50 51int ch=0; 52 53for(char t:cA){ 54 55int g=(int)t; 56ch+=g; 57 58} 59 60 61return id*1000+ch; 62 63} 64 65 66 67public int id; 68public String name; 69public Food(int id,String name){ 70this.id = id; 71this.name = name; 72} 73} 74 75public class App { 76public static void main(String[] args) { 77 78List<Order> orderList = new ArrayList<>(); 79List<Food> foodList = new ArrayList<>(); 80 81orderList.add(new Order(1,"アップル")); 82orderList.add(new Order(2, "バナナ")); 83orderList.add(new Order(3, "綿菓子")); 84 85foodList.add(new Food(1,"アップル")); 86foodList.add(new Food(2, "バナナ")); 87for (int i2 = 0; i2 < orderList.size(); i2++) { 88 89//比較してくれない 90if(!(foodList.contains(orderList.get(i2)))){ 91System.out.println(orderList.get(i2).name); 92} 93 94 95 96} 97Order o = new Order(1, "アップル"); 98Food f = new Food(1, "アップル"); 99System.out.println(o.hashCode() +" :" + f.hashCode()); 100System.out.println("o.equals(o) = " + o.equals(o)); 101 102System.out.println("f.equals(o) = " + f.equals(o)); 103System.out.println("o.equals(f) = " + o.equals(f)); 104 105System.out.println("o.hashCode() = " + o.hashCode()); 106System.out.println("f.hashCode() = " + f.hashCode()); 107Order o2 = new Order(1, "アップル"); 108Order p2 = new Order(1, "パップル"); 109 110 Food f2 = new Food(1, "アップル"); 111System.out.println(p2.hashCode()+" :" +o2.hashCode()+" :" +f2.hashCode()); 112System.out.println("p2.equals(o2) = " + p2.equals(o2)); 113 System.out.println("o2.equals(f2) = " + o2.equals(f2)); 114 System.out.println("p2.equals(f2) = " + p2.equals(f2)); 115 116 117} 118}

投稿2016/11/23 03:57

編集2016/11/24 13:56
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

isacRu

2016/11/23 04:29

ありがとうございます。勉強になりました。
KiyoshiMotoki

2016/11/23 10:55

この実装は、以下の理由により不適切です。 ・equals メソッドの一般契約のうち、「反射性」および「対称性」に違反している  http://docs.oracle.com/javase/jp/7/api/java/lang/Object.html#equals(java.lang.Object)  > 反射性 (reflexive): null 以外の参照値 x について、x.equals(x) は true を返します。  > 対称性 (symmetric): null 以外の参照値 x および y について、y.equals(x) が true を返す場合に限り、x.equals(y) は true を返します。 ・hashCode メソッドを適切にオーバーライドしていない  http://docs.oracle.com/javase/jp/7/api/java/lang/Object.html#hashCode()  > equals(Object) メソッドに従って 2 つのオブジェクトが等しい場合は、2 つの各オブジェクトに対する hashCode メソッドの呼び出しによって同じ整数の結果が生成される必要があります。 例 :  // Orderクラスおよび Foodクラスの実装は省略  public class App {    public static void main(String[] args) {      Order o = new Order(1, "アップル");      Food f = new Food(1, "アップル");      System.out.println("o.equals(o) = " + o.equals(o));      System.out.println("f.equals(o) = " + f.equals(o));      System.out.println("o.equals(f) = " + o.equals(f));      System.out.println("o.hashCode() = " + o.hashCode());      System.out.println("f.hashCode() = " + f.hashCode());    }  } 実行結果 :  o.equals(o) = false  f.equals(o) = false  o.equals(f) = true  o.hashCode() = 1335080452  f.hashCode() = 1788012908 このコードは回答で示したケースで【のみ】うまく動作しますが、 それ以外の equalsメソッドや hashCode メソッドに基づいて動作するコード(※)では、 うまく動かない可能性があります。 ※ 例えば、Listインターフェースの indexOfメソッドや HashSetクラスを使用する場合など。
退会済みユーザー

退会済みユーザー

2016/11/23 14:34

以下のコードではnameが1000文字以下の場合は equalsがfalseでハッシュコードが同じ場合はあっても equalsがtrueの場合ハッシュコードは同じになり オーバーライドで従うべき規則に従っていることになります nameが1000文字以上になると規則から外れうるので完全ではないでしょうが 今回使われると思しき文字数の範囲だと規則に従えると思います import java.util.*; class Order{ public int hashCode(){ return id*1000+name.length(); } public boolean equals(Object o){ if((o instanceof Food) && (((Food)o).id==this.id) && (((Food)o).name.equals(this.name))){ return true; } else if((o instanceof Order) && (o.hashCode()==this.hashCode())){ return true; } return false; } public int id; public String name; public Order(int id,String name){ this.id = id; this.name = name; } } class Food{ public int hashCode(){ return id*1000+name.length(); } public int id; public String name; public Food(int id,String name){ this.id = id; this.name = name; } } public class App { public static void main(String[] args) { List<Order> orderList = new ArrayList<>(); List<Food> foodList = new ArrayList<>(); orderList.add(new Order(1,"アップル")); orderList.add(new Order(2, "バナナ")); orderList.add(new Order(3, "綿菓子")); foodList.add(new Food(1,"アップル")); foodList.add(new Food(2, "バナナ")); for (int i2 = 0; i2 < orderList.size(); i2++) { //比較してくれない if(!(foodList.contains(orderList.get(i2)))){ System.out.println(orderList.get(i2).name); } /* } Order o = new Order(1, "アップル"); Food f = new Food(1, "アップル"); System.out.println("o.equals(o) = " + o.equals(o)); System.out.println("f.equals(o) = " + f.equals(o)); System.out.println("o.equals(f) = " + o.equals(f)); System.out.println("o.hashCode() = " + o.hashCode()); System.out.println("f.hashCode() = " + f.hashCode());*/ } }
KiyoshiMotoki

2016/11/24 01:31 編集

今度は推移性に違反しています。 http://docs.oracle.com/javase/jp/7/api/java/lang/Object.html#equals(java.lang.Object) > 推移性 (transitive): null 以外の参照値 x、y、および z について、x.equals(y) が true を返し、y.equals(z) が true を返す場合、x.equals(z) は true を返します。  public class App {   public static void main(String[] args) {   Order o = new Order(1, "アップル");   Order p = new Order(1, "パップル");   Food f = new Food(1, "アップル");   System.out.println("p.equals(o) = " + p.equals(o));   System.out.println("o.equals(f) = " + o.equals(f));   System.out.println("p.equals(f) = " + p.equals(f));   }  } 実行結果 :  p.equals(o) = true  o.equals(f) = true  p.equals(f) = false
swordone

2016/11/24 01:39 編集

別に外部に公開するクラスというわけでもないので、そこまで厳密性を求める必要はないのでは… まあそもそも、継承関係も共通するインタフェースもない別のクラスのオブジェクトが等しいと判定すること自体無理があるのですが。
KiyoshiMotoki

2016/11/24 04:14

swordone様 > 別に外部に公開するクラスというわけでもないので、そこまで厳密性を求める必要はないのでは… 自分のプログラムに組み込むだけなら、私も仰る通りだと思います。 ただ、QAサイトの回答に載っているコードは 広義の意味で「外部に公開」していると言えるのではないでしょうか? この回答を参考にコードを書こうとする方もいると思いますので。 > まあそもそも、継承関係も共通するインタフェースもない別のクラスのオブジェクトが等しいと判定すること自体無理があるのですが。 ですよねw
退会済みユーザー

退会済みユーザー

2016/11/24 13:55 編集

回答へ
swordone

2016/11/24 12:42

回答編集で訂正願います。
guest

0

containsの判定にはequalsを使います。デフォルトでは「同じオブジェクト」の時だけtrueとなるので、現状等しいオブジェクトを見つけられません。
equalsをオーバーライドして、等しいの定義付けをする必要があります。

ここからは構成上の話になりますが、FoodクラスとOrderクラスというのは不自然です。「食べ物」を意味するクラスFoodがあり、そのFoodが「注文されたもの」か「在庫にあるもの」かという色づけがされるわけです。

率直に考えればこうなります。

java

1class Food{ 2 public int id; 3 public String name; 4 public Food(int id,String name){ 5 this.id = id; 6 this.name = name; 7 } 8 9 public boolean equals(Object o) { 10 if (o == this) return true; 11 if (o.getClass() != this.getClass()) return false; 12 Food f = (Food)o; 13 return this.id == f.id && this.name.equals(f.name); 14 } 15 //hashcodeの実装は省略 16} 17 18public class App { 19 public static void main(String[] args) { 20 21 List<Food> orderList = new ArrayList<>(); 22 List<Food> foodList = new ArrayList<>(); 23 24 orderList.add(new Food(1,"アップル")); 25 orderList.add(new Food(2, "バナナ")); 26 orderList.add(new Food(3, "綿菓子")); 27 28 foodList.add(new Food(1,"アップル")); 29 foodList.add(new Food(2, "バナナ")); 30 31 for (int i = 0; i < orderList.size(); i++) { 32 if(!foodList.contains(orderList.get(i))){ 33 System.out.println(orderList.get(i)); 34 } 35 36 } 37 }

投稿2016/11/23 03:05

編集2016/11/23 15:19
swordone

総合スコア20669

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

swordoneさんのおっしゃっている通りですが、

foodList.contains(orderList.get(i).name)

では、例えば、Food(1,"アップル")とString("アップル")とを比較することになり、containsメソッドが呼び出す
"アップル".equals(Food(1,"アップル")) // 注意:説明のためJavaの文法に不正確
はfalseを返します。

よって、正しく比較させるためには、Foodクラスのインスタンスと正しく比較できるequalsメソッドをOrderクラスでオーバーライドする必要があります。

投稿2016/11/23 04:27

naomi3

総合スコア1105

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

isacRu

2016/11/23 04:31

ありがとうございます。その方法で試したら成功しました!
swordone

2016/11/23 08:47

いや、文法上なにも間違っていませんよ。
swordone

2016/11/23 10:18

あ、失礼。この回答の「説明のためJavaの文法に不正確」という部分に対するコメントでした。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.37%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問