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

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

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

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

Q&A

解決済

4回答

2791閲覧

Java:インスタンスの並び替えの仕組みについて

karakorum

総合スコア20

Java

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

0グッド

1クリップ

投稿2020/03/08 13:07

前提

javaの基礎を本で勉強中の初心者です。
下のコードは、ある入門書のサンプルコードを少し変えたものです。
インスタンスをnumberで並び替えています。
下記のコードでエラーはありませんでした。

●環境
・java version 13.0.2
・Atom 1.44.0
・script 3.25.0
・jdk 13.0.2
●OS :windows10

###質問内容
Question.javaの下から6行目の
①Collections.sort(list);

Account.javaの下から10行目の
②public int compareTo(Account obj){
の関係、というか繋がりがよく分かりません。
①のCollectionsクラスのsort()メソッドは、()内の順番を入れ替えてくれる。
②のComparableインターフェースから継承されたcompareTo()メソッドは、大小関係を比較してくれる。
そこまでは分かるのですが、②の引数(Account obj)は、どこで渡されたのでしょうか?
Collections.sort(list); から public int compareTo(Account obj){
までの過程、引数の受け渡しの流れがどれだけ考えても理解ができませんでした。

そこで、collectionsクラスとComparableクラス、その他関連したソースコードを読んでみたのですが、分からないクラスを調べていたら、さらに分からないクラスが出てきて、そこでもさらに分からないクラスが出てきて・・・、と頭がパンクしてしまいました。

ソースコードくらい読めないとこれからやっていけない、という意見はごもっともなのですが、とりあえずの基礎学習としては、ここはさらっと流した次に行った方がいいのでしょうか?それともきちんと根本まで理解してから次に進んだ方がいいのでしょうか?
また、もし①②の関係も説明していただけたら幸いです。
ご回答、よろしくお願いします。

該当のソースコード

Question.java(mainのソースコード)

java

1import static java.lang.System.out; 2import java.util.*; 3 4public class Question{ 5 public static void main(String[]args){ 6 List<Account> list=new ArrayList<Account>(); 7 Account a=new Account(); 8 Account b=new Account(); 9 Account c=new Account(); 10 Account d=new Account(); 11 Account e=new Account(); 12 a.setAccountNo("First"); 13 b.setAccountNo("Second"); 14 c.setAccountNo("Third"); 15 d.setAccountNo("Fourth"); 16 e.setAccountNo("Fifth"); 17 a.setNumber(5); 18 b.setNumber(4); 19 c.setNumber(1); 20 d.setNumber(2); 21 e.setNumber(3); 22 list.add(a); 23 list.add(b); 24 list.add(c); 25 list.add(d); 26 list.add(e); 27 Collections.sort(list); //質問したい部分 28 for(Account f:list){ 29 out.println(f.getAccountNo()+" "+f.getNumber()); 30 } 31 } 32}

Account.java

java

1import static java.lang.System.out; 2 3public class Account implements Comparable<Account>{ 4 private String accountNo; 5 private int number; 6 7 public void setAccountNo(String accountNo){ 8 this.accountNo=accountNo; 9 } 10 11 public String getAccountNo(){ 12 return this.accountNo; 13 } 14 15 public void setNumber(int number){ 16 this.number=number; 17 } 18 19 public int getNumber(){ 20 return this.number; 21 } 22 23 public boolean equals(Object o){ 24 if(this==o){ 25 return true; 26 } 27 if(o instanceof Account){ 28 Account a=(Account) o; 29 if(this.accountNo.equals(a.accountNo)){ 30 return true; 31 } 32 } 33 return false; 34 } 35 36 public int compareTo(Account obj){  //質問したい部分 37 if(this.number<obj.number){ 38 return -1; 39 } 40 if(this.number>obj.number){ 41 return 1; 42 } 43 return 0; 44} 45} 46

実行結果

Third 1 Fourth 2 Fifth 3 Second 4 First 5

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

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

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

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

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

guest

回答4

0

ベストアンサー

Collections.sort(List<T> list) の仕組みを知るには”インターフェース”と”ジェネリクス”の仕組みについて学習する必要があります。

Collections.sort() はインターフェース、ジェネリクスの仕組みを知るのにとても良い教材ですが、これをいきなり知ろうとすると難しいかもしれません。しかし頑張って説明してみます。

Javaの入門書を読んでいるとのことですが、クラスの説明の章に入る前に関数的なメソッドのプログラミング例を見てきたことと思います。その中に整数配列の並び替えのプログラムはありませんでしたか?

Java

1public static void sort(int[] target) 2{ 3 int count = target.length; 4 for(int i=0; i<count; i++) 5 { 6 /* 7 * i ~ (count - 1) の間で最小値のインデックスを探索 8 */ 9 int idxMin = i; 10 for(int j=(i+1); j<count; j++) 11 { 12 if(target[idxMin] > target[j]) 13 { 14 idxMin = j; 15 } 16 } 17 18 // 最小値のインデックス idxMin の値と i を交換 19 int tmp = target[i]; 20 target[i] = target[idxMin]; 21 target[idxMin] = tmp; 22 } 23}

上記は選択ソートと呼ばれる並び替えアルゴリズムです。Collections.sort() は上記とは違うソートアルゴリズムですが、とりあえず上記のような処理をしているとしましょう。この例では整数配列を並び替える処理ですから、sort() の引数が int[] であればどんなデータであってもOKです。このメソッドは立派なソート共通ライブラリとして公開できます。

今度はAccountリストの並び替えを上記に倣って書き換えてみましょう。

Java

1public static void sort(List<Account> list) 2{ 3 int count = list.size(); 4 for(int i=0; i<count; i++) 5 { 6 int idxMin = i; 7 for(int j=(i+1); j<count; j++) 8 { 9 Account min = list.get(idxMin); 10 Account another = list.get(j); 11 if(min.getNumber() > another.getNumber()) 12 { 13 idxMin = j; 14 } 15 } 16 17 // 最小値のインデックス idxMin の値と i を交換 18 Account tmp = list.get(i); 19 list.set(i, list.get(idxMin)); 20 list.set(idxMin, tmp); 21 } 22}

これで出来上がりです。しかしこれをソート共通ライブラリとして公開できるでしょうか? できませんよね。なぜならこのメソッドは Account クラスのリストでないと並び替えが不可だからです。公開しようと思えば Account クラス以外でも並び替える必要があります。そこでジェネリクスによって、どんなクラスでも並び替えできるようにしましょう。

Java

1public static <E> void sort(List<E> list) 2{ 3 int count = list.size(); 4 for(int i=0; i<count; i++) 5 { 6 int idxMin = i; 7 for(int j=(i+1); j<count; j++) 8 { 9 E min = list.get(idxMin); 10 E another = list.get(j); 11 if(min.getNumber() > another.getNumber()) // ← getNumber() では比較できない! 12 { 13 idxMin = j; 14 } 15 } 16 17 // 最小値のインデックス idxMin の値と i を交換 18 E tmp = list.get(i); 19 list.set(i, list.get(idxMin)); 20 list.set(idxMin, tmp); 21 } 22}

ジェネリクスにまだ慣れていないならば、クラス型"E"はObjectと読み替えてください。
ほとんどの処理はそのまま流用できますが、getNumber() で比較している個所だけはコンパイル・エラーです。なぜならクラス型"E"は、ここでは具体的な型が分からないため(Accountクラスかもしれないし、それ以外のクラスかもしれない)、Object型と同じと見なされ、Objectクラスで定義されているメソッドしか呼び出せません。

さて、比較処理において、”どちらが小さく、どちらが大きいか”が分かれば良いのですが、sort() メソッドはどのクラス型の比較なのか分からないため、比較のしようがありません。この比較方法を知っているのは誰かと言うと… 当然呼び出し側となりますよね。だって呼び出す側は何のクラス型か、を知っている訳ですから。

Java

1List<Account> list = Arrays.asList(new Account("First", 3), new Account("Second", 1), new Account("Third", 2)); 2Sorter.sort(list); // ← ソートメソッドの呼び出し

呼び出し側が Account クラスで並び替えることを知っていて、更に number で比較したい、と考えている訳です。つまり2つのAccountオブジェクトをどう比較すればよいか、を知っているのです。で、あれば比較処理だけ呼び出し側に任せよう、となるのです。
このように共通処理のある処理だけを切り出して呼び出し側に任せる仕組みがインターフェースです。

この比較処理を担うインターフェースが Comparable であり、その比較処理は compareTo() です。ではこの Comparable を組み込んでみましょう。

Java

1public static <E extends Comparable<E>> void sort(List<E> list) 2{ 3 int count = list.size(); 4 for(int i=0; i<count; i++) 5 { 6 int idxMin = i; 7 for(int j=(i+1); j<count; j++) 8 { 9 E min = list.get(idxMin); 10 E another = list.get(j); 11 if(min.compareTo(another) > 0) // ← compareTo() が返す値で比較! 12 { 13 idxMin = j; 14 } 15 } 16 17 // 最小値のインデックス idxMin の値と i を交換 18 E tmp = list.get(i); 19 list.set(i, list.get(idxMin)); 20 list.set(idxMin, tmp); 21 } 22}

事前に Account クラスは Comparable インターフェースを実装しているものとします。そしてクラス型"E"はこれまでの Object 型扱いではなく、Comparable 型で扱えるよう、"E extends Comparable<E>" としました。これで "E" は compareTo() を呼び出せるようになります。

比較処理に注目してください。min はクラス型 "E" として扱われるので、compareTo() を呼び出すことができます。そしてこの compareTo() は、まさにあなたが Account クラスで実装した compareTo() なのです!

…とは言え、まだボヤッとしか見えてないかもしれません。焦らないでください。インターフェースを1から理解すれば、いずれ分かることです。

以下の本がインターフェースの理解につながると思います。私自身、とても助かりましたのでお勧めします。道は長いですが、頑張れば必ずプログラミングの考え方に広がりが持てますので。では!

「先輩、Javaのインターフェースって何ですか?」の答えに窮した時に読む本

投稿2020/03/08 16:44

編集2020/03/08 16:47
Mirko_Mug_Cup

総合スコア56

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

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

karakorum

2020/03/09 02:59

おおまかには理解できましたが、まだ随所わからない部分もあるので、ゆっくり考えていきたいと思います。 紹介してもらった本は、基礎学習が終わったら読んでみようと思います。 ありがとうございました。
Mirko_Mug_Cup

2020/03/09 04:28

私も以前、なぜ compareTo() を実装しただけなのに並び替えができてしまうのか不思議でした。 多分、ネットで調べても分からない疑問だろうと思います。ソースを調べてまで知ろうとする姿に昔の自分を思い出しし、思わず頑張って書いてしまいました… 他の方も仰るように、この並び替えの詳細の理解は後回しでいいと思います。また紹介した本は仰る通り、ある程度Javaプログラムに慣れてからの方が良いでしょう。最初の内は分からなくても、何度も読み返せば理解できるようになると思いますよ。
karakorum

2020/03/09 06:55

最初に言い忘れていましたが、とてもたくさんのコードを丁寧に書いていただき、とても助かりました! 分からないところは考えて、あまりにも難しかったら割り切って進めていきたいと思います。 色々とありがとうございました!
guest

0

ソートアルゴリズムは数あれど、やっていることは基本的に2つの値を比較して、どちらが大きいかを判定し、それをもとに入れ替えなどを行うことです。基本的にソートアルゴリズムの説明をするところでは数値の比較・並べ替えを行うものがほとんどだと思いますが、数値でなくてもこの大小比較さえできれば、同様のアルゴリズムでソートができることになります。
ソートのメソッドsortの実行中、この大小比較が必要な時に、compareToメソッドを呼び出して、大小比較をすることになります。
例えばクイックソートの場合、基準値よりも大きいか小さいか、というチェックが入りますが、このチェック時に、数値を不等号で比較する代わりに、compareToを呼び出し、その結果から大小を判断します。

投稿2020/03/08 13:22

swordone

総合スコア20669

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

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

karakorum

2020/03/09 02:48

単純な数値などはsortで比較ができるが、インスタンスの比較など、数値以外の大小関係を比較するときに、compareToが呼び出される、ということなんですね。 ありがとうございます。
guest

0

あくまで私の考えと前置きしつつ、
javaの基礎を本で勉強中の初心者です。って人が現場に来たとして、
Collectionのソースコードくらい読めないとこれからやっていけない、とは思わないので安心してください。
なのでさらっと流したほうがいいと思います。

しかし、ソースから読めなくとも使い方がわかっている必要はあります。
Java13の日本語が見当たらなかったので、日本語がいい場合は8の方を参考にしてください。
Java13ドキュメント
Java8ドキュメント

ドキュメントを参考にすると、
・Listをソートしたい時にはsortを使う
・sortを使うためにはListの要素すべてにComparableを実装していなくてはいけない
・Accountにimplements Comparable<Account>とするとcompareTo()メソッドを実装しなくてはいけない
・compareTo()で順位付けを定義しているため
ぐらいのことをドキュメントなりから調べて使えば問題ないと思います。

また、Collectionの中でもよく使うものはしっかり使い方を押さえておきましょう。(List,Map,Setなど)

経験を積んで勉強していけばそのうち読めるようになるので、今は表面的に理解してい

投稿2020/03/08 15:57

junzi

総合スコア279

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

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

karakorum

2020/03/09 02:57

Listでソートをしてから、compareToまでのおおまかな流れがつかめました! ありがとうございます。
guest

0

sort と compareTo メソッドの関係、確かにややこしい部分ではありますね。

まず compareTo メソッドを考えます。これは二つのオブジェクトの大小関係を調べるメソッドです。
せっかく a, b, c, d, e の 5 つのオブジェクトを作ってるので、これらの大小関係を表示してみましょう。

Java

1 System.out.println("a vs b: " + a.compareTo(b)); 2 System.out.println("b vs c: " + b.compareTo(c)); 3 System.out.println("c vs d: " + c.compareTo(d)); 4 System.out.println("d vs e: " + d.compareTo(e)); 5 System.out.println("e vs e: " + e.compareTo(e));

実行結果

a vs b: 1 b vs a: -1 c vs d: -1 d vs c: 1 e vs e: 0

次に、二つのオブジェクトが入った配列を並べ替えるメソッドを考えます。例えば二つの整数なら、

Java

1 public static void sort2int(int[] array) { 2 if (array[0] > array[1]) { 3 int tmp = array[0]; 4 array[0] = array[1]; 5 array[1] = tmp; 6 } 7 }

ですが、二つの Account オブジェクトの場合は、compareTo メソッドを使って

Java

1 public static void sort2(Account[] array) { 2 if (array[0].compareTo(array[1]) > 0) { 3 Account tmp = array[0]; 4 array[0] = array[1]; 5 array[1] = tmp; 6 } 7 }

となります。Collections.sort() の中ではこんな風に compareTo メソッドが使われています。

投稿2020/03/08 14:06

hoshi-takanori

総合スコア7901

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

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

karakorum

2020/03/09 02:53

配列ではなく、インスタンスを比較するためにsortを使う場合は、compareToメソッドを呼び出し、上のような操作が行われている、ということなんですね。 ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問