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

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

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

Genericsはパラメトリックなポリモーフィズムの形態であり、.NET やJavaなど、様々な言語に実装されています。C++のテンプレートと同等の機能を持ち合わせています。

Java

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

Eclipse

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

Q&A

解決済

1回答

13387閲覧

ジェネリクスをraw型にしたときの警告がよくわからない。

退会済みユーザー

退会済みユーザー

総合スコア0

Generics

Genericsはパラメトリックなポリモーフィズムの形態であり、.NET やJavaなど、様々な言語に実装されています。C++のテンプレートと同等の機能を持ち合わせています。

Java

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

Eclipse

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

0グッド

0クリップ

投稿2020/03/22 17:26

前提

Javaの初心者です。よろしくお願いします。
Eclipseでコンパイル、実行しています。

問題点

コレクションなどのジェネリクスを実装したクラスを

Java

1List list1 = new ArrayList();

とraw型で用いるとListと**ArrayList()の部分で「型の不一致が起きる可能性があるから総称型にしたほうがいいよ」という警告が出るのは分かるのですが、
以下のコードのようにコンストラクタだけraw型にすると
ArrayList()**で「型の安全性: 型 ArrayList の式は、未検査の型変換を使用して List<String> に準拠するようにする必要があります」という警告が出ました。

Java

1List<String> list1 = new ArrayList();

2つ目のコードの変数の型は「要素はString型しか扱わないList型」になっているので変数に入るオブジェクトがraw型だったとしても、String型の要素しか扱うことができないため要素を取り出す際に型の不一致が起きる可能性が無いはずです。なぜ2つ目のようなコードでも警告が出るのでしょうか。
また、そもそもArrayList型をList<String>型に代入できること自体おかしいのではないかと思ってしまいました。

自分の考え

以下のようにダウンキャストでList型に代入できるため、後々型の不一致が起こる可能性も考えて警告がでているのではないかと考えました。

Java

1List<String> list1 = new ArrayList(); 2List list2 = list1;

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

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

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

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

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

guest

回答1

0

ベストアンサー

ジェネリクスによる型の制限は、コンパイル時点までの問題であり、実際の型には影響がありません。
ArrayList,ArrayList<String>,ArrayList<Integer>などは、実際はすべて全く同じクラスファイルに基づく、全く同じものです。
内部での要素管理は実質Object型となり、型情報はすべて消えます。
簡単に言うなら、事実上ArrayListとArrayList<String>は全く同じ型であり、List<String>はその親の型であるため、

java

1List<String> list1 = new ArrayList();

という「代入」は当然文法上問題ないものになります。

ではジェネリクスは何のためにあるのか?
これはコンパイル時に型の制限をする機能なのです。
List<String>型の変数に対するaddメソッドは、仮引数型がStringであるかのように扱い、
String以外を引数にしようとした際に、コンパイラがエラーとして弾くようにします。
さらに同じ変数に対してgetしようとした場合、裏方の仕事としてStringにキャストして返却します。
raw型で使う場合に自分でやる必要のあったキャストを、プログラムとしてやってくれているようなものです。

2つ目のコードの変数の型は「要素はString型しか扱わないList型」になっているので変数に入るオブジェクトがraw型だったとしても、String型の要素しか扱うことができないため要素を取り出す際に型の不一致が起きる可能性が無いはずです。なぜ2つ目のようなコードでも警告が出るのでしょうか。

という疑問に対してですが、raw型で扱う場合、入れるほうの型の制限を入れられないため、次の場合に問題が起こります。

java

1ArrayList list = new ArrayList(); 2list.add(1); 3List<String> list2 = list;

変数をコンストラクタでしか初期化できないというのであれば問題はなかったでしょうが、当然そんなことはないため、このような書き方も成立します。
このlist2から要素を取り出そうとすると、IntegerをStringにキャストしようとして、例外が発生してしまいます。
「入るとき」も制限されているからこそこのジェネリクスの仕組みが成立するので、ジェネリクスで宣言した変数なら、入れるものもジェネリクス使ったものじゃないと合わなくなる恐れがありますよ、ということで警告を吐いているのです。

投稿2020/03/22 20:00

swordone

総合スコア20669

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

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

退会済みユーザー

退会済みユーザー

2020/03/23 03:53

swordone さん ジェネリクスの基礎から丁寧に解説していただきありがとうございます。 具体例が分かりやすく、警告がなぜ出るのか理解できました。 >内部での要素管理は実質Object型となり、型情報はすべて消えます。 ということですが、 「ArrayList<String> list1 = new ArrayList<Integer>();」 とした場合はなぜコンパイルエラーになるのでしょうか。 ArrayList<String>とArrayList<Integer>は内部での要素管理はどちらもObject型ですが、ジェネリクスで要素の型に制限がされているためコンパイルエラーが起きるということですか?
swordone

2020/03/23 05:37

そうです。それらを違う型として扱おうというのがジェネリクスの役割です。
退会済みユーザー

退会済みユーザー

2020/03/23 05:43

swordone さん 回答ありがとうございました。 ジェネリクスについての理解が深まりました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問