🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Java

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

Eclipse

Eclipseは、IBM社で開発された統合開発環境のひとつです。2001年11月にオープンソース化されました。 たくさんのプラグインがあり自由に機能を追加をすることができるため、開発ツールにおける共通プラットフォームとして位置づけられています。 Eclipse自体は、Javaで実装されています。

Q&A

解決済

1回答

960閲覧

Java:オーバライドの優先順位の規則について

karakorum

総合スコア20

Java

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

Eclipse

Eclipseは、IBM社で開発された統合開発環境のひとつです。2001年11月にオープンソース化されました。 たくさんのプラグインがあり自由に機能を追加をすることができるため、開発ツールにおける共通プラットフォームとして位置づけられています。 Eclipse自体は、Javaで実装されています。

0グッド

0クリップ

投稿2020/11/29 05:19

#ソースコード

package test; import java.util.ArrayList; import java.util.List; import java.util.stream.Stream; public class Sub{ public static void main(String[] args) { // List<Integer> list=Arrays.asList(1,2,3,4,5); // list.stream().filter(i->i%2==0).forEach(i->System.out.println(i)); List<Integer> list=Arrays.asList(1,2,3,4,5); Stream<Integer> stream=list.stream(); Stream<Integer> stream2=stream.filter(i->i%2==0); stream2.forEach(i->System.out.println(i)); } }

実行結果

2 4

#概要
JavaのStreamAPIの内部的な動きが知りたかったので、上記ソースコードでコメントアウトしているstreamを分解して、一つ一つEclipseのデバッグ機能でソースコードを辿っていきました。
すると、一ヶ所、腑に落ちない部分がありました。

まず、ArraysクラスのasListメソッドを呼び出し、そのの戻り値であるArrayList<Integer>クラスのインスタンスをList<Integer>型のlist変数に代入します。
その次に、そのlist変数を参照して、streamメソッドを呼び出しています。
この部分をeclipseでブレークポイントに設定し、デバッグ機能を使うと、下記メソッドが呼び出されていました。

public interface Collection<E> extends Iterable<E> { : : default Stream<E> stream() { return StreamSupport.stream(spliterator(), false); } : : }

処理として、StreamSupportクラスのstreamメソッドの第一引数として、spliteratorメソッドの戻り値が第一引数として引き渡されています。
このメソッドはListインターフェース、ArrayListクラス、それぞれで宣言されています。
List<Integer>型のlist変数には、ArrayListインスタンスが代入されているので、オーバライドの優先順位の規則から、ArrayListインスタンスのspliteratorメソッドが呼び出されると思っていました。
しかし、実際に辿ってみると、Arraysクラスのspliteratorメソッドが呼び出されていました。
ArraysクラスとCollectionインターフェース・Listインターフェース・ArrayListクラス、それぞれ継承関係も実装関係もありません。そのため、List型の変数に代入されいてるArrayListインスタンスのメソッド内にて、参照先を指定しない方法でのメソッド呼び出し(spliterator())で、Arraysクラスのメソッドが呼び出される可能性はありません。
(なぜなら、非staticなメソッド内で参照先を指定しないメソッド呼び出しをした場合、自インスタンスのメソッドが呼び出されることになるから。)

public class Arrays { : : public Spliterator<E> spliterator() { return Spliterators.spliterator(a, Spliterator.ORDERED); } : : }

また、ArraysクラスのasListメソッドの内部的な処理でArrayListクラスのインスタンスが生成されていることも確認済みのため、今回のような状況でArraysクラスのspliteratorメソッドが呼ばれる理由が分かりません。

public class Arrays { : : public static <T> List<T> asList(T... a) { return new ArrayList<>(a); } : : }

また、最初のソースコードのArrayListインスタンス化を下記のように変更して、同じようにデバッグ機能を用いると、ちゃんとArrayListクラスのspliteratorメソッドが呼び出されていました。

package test; import java.util.ArrayList; import java.util.List; import java.util.stream.Stream; public class Sub{ public static void main(String[] args) { List<Integer> list=new ArrayList<Integer>(); list.add(1); list.add(2); list.add(3); list.add(4); list.add(5); Stream<Integer> stream=list.stream(); Stream<Integer> stream2=stream.filter(i->i%2==0); stream2.forEach(i->System.out.println(i)); } }
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable { : : public Spliterator<E> spliterator() { return new ArrayListSpliterator<>(this, 0, -1, 0); } : : }

個人的には、Eclipseのデバッグ機能はソースコードを逆コンパイル?によってclassファイルから無理やり作っているものなので、その不備かと思っているのですが、
Javaの文法的に説明できる方がいましたら、ご回答いただきたいです。
よろしくお願いします。

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

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

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

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

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

guest

回答1

0

ベストアンサー

まず、ArraysクラスのasListメソッドを呼び出し、そのの戻り値であるArrayList<Integer>クラスのインスタンスをList<Integer>型のlist変数に代入します。

このArrayListは、我々が普段使っているjava.util.ArrayListではなく、Arraysクラスの内部で宣言されたクラスです。asListメソッドの少し下で宣言されていたと記憶しています。これは、まさにメソッド名の通り配列を「Listとして」扱えるようにラップするクラスになります。
したがって、あなたが「Arraysクラスのメソッドを呼び出した」ように見えたspliteratorメソッドは、そ「Arraysクラス内で宣言されたArrayListクラス」で実装されたspliteratorメソッドである可能性が高いです。Eclipse上で見る場合、確かにArraysクラスを開く形になりますしね。

投稿2020/11/29 05:44

編集2020/11/29 06:10
swordone

総合スコア20669

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

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

karakorum

2020/11/29 05:59

Eclipseで確認したら、確かにArraysクラスでネストクラスとして、privateなArrayListクラスが宣言されていました・・・。 全く気が付きませんでした。 当たり前のことですが、パッケージが異なれば、他のパッケージと同名のクラスやインターフェースも宣言できる、ということが完全に抜けており、混乱していました。 ありがとうございました。
KoichiSugiyama

2020/11/29 06:10

蛇足かもしれませんが、オラクルのサイトにあるArrays.asListのリファレンス(https://docs.oracle.com/javase/jp/8/docs/api/java/util/Arrays.html#asList-T...-)を見ると、「指定された配列に連動する固定サイズのリストを返します。返されたリストへの変更は、そのまま配列に書き込まれます。」とありますので、そういう仕組みにしているんでしょうね。
swordone

2020/11/29 06:12

全く同名なのでややこしいところなんですよね。 ちなみに、ArrayListのコンストラクタで引数を渡していますが、java.util.ArrayListのコンストラクタで配列(可変長引数)をとるものはありません。この点でも判別できます。
karakorum

2020/12/01 14:06

追記していただき、ありがとうございます! 理解が深まりました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問