- PR -

キャストについて

投稿者投稿内容
OZ
常連さん
会議室デビュー日: 2006/02/27
投稿数: 45
投稿日時: 2006-03-31 10:59
皆様、お世話になっております。

引用:

引用:

coasmさんの書き込み (2006-03-31 01:12) より:

objの要素が実際にはどんなデータ型なのかは斟酌されません。


スレ主以外の方は、みんなわかってらっしゃいますよ。
コンパイル時にはまったく問題はない。
しかし、実行時にキャストなどを伴う場合には、相応の対処が必要です。

それにしてもスレ主さん、腰が低くてまじめそうに見えますが、どの程度素直なのやら。
ご自身の先入観(オレ的オブジェクト理論)に固執して、
他の方の意見を選り好みしているように見えるのは、私の気のせいですか?




そのようなつもりはないのですが、そう感じさせるような書き方をしたのでしたら申し訳なく思います。
これだけ助言を頂きながらすんなりと理解できない自分に腹が立っています。

もう一度初めから見直して何とか来週までには理解しようかと思います。
未記入
会議室デビュー日: 2006/03/31
投稿数: 1
投稿日時: 2006-03-31 11:19
//コードだけではわかりにくかったので説明をつけました。
//それぞれの瞬間の配列変数の状態を確認してください。

Object[] obj = new Object[2];
// obj 型:Object[] ---> |Object|Object| memory上にObjectを指し示す為の変数配列の領域を確保
// obj[0] 型:Object --> null それぞれのobjはnullを参照
// obj[1] 型:Object --> null


obj[0] = "a" ;
obj[1] = "b";
// obj ---> |Object|Object| この時点でそれぞれはStringインスタンスを参照
// obj[0] 型:Object --> "a" 型:Stringのインスタンス
// obj[1] 型:Object --> "b" 型:Stringのインスタンス


obj = new String[2];
// obj 型:String[] ---> |String|String| この時点で変数はStringに。参照はnull
// obj[0] 型:String --> null 変数の型はStringだがそれぞれのobjはnullを参照
// obj[1] 型:String --> null
String[] strAry1 = (String[]) obj; // この時点では変数がString配列なのでキャスト可


obj[0] = "c";
obj[1] = "d";
// obj ---> |String|String| それぞれの変数にインスタンスを代入
// obj[0] 型:String --> "c"
// obj[1] 型:String --> "d"
strAry1 = (String[]) obj; // 配列内の変数はStringのままなのでもちろんキャスト可


obj = new Object[2];
obj[0] = new Object();
obj[1] = new String("abcde");
// obj ---> |Object|Object| もう一度Object型の配列を代入
// obj[0] 型:Object --> Objectインスタンス
// obj[1] 型:Object --> "abcde"
// 配列それぞれに違う型のインスタンスをいれても|Object|String|とはならない
Object o1 = (String) obj[0]; // ClassCastException発生
Object o2 = (String) obj[1]; // こっちは可能

obj[0] = "zzzz";
// obj ---> |Object|Object| この時点でも配列の型は両方Object
// obj[0] 型:Object --> "zzzz"
// obj[1] 型:Object --> "abcde"
// 両方にStringを代入しても、|String|String|とはならない。
// 但し、それぞれのobjが指し示しているインスタンスの型はString
strAry1 = (String) obj // ClassCastException発生

Object[] objAry = new String[2];
objAry[0] = obj[0];
objAry[1] = (String) obj[1];
strAry1 = (String) objAry; // これなら可能


// キャストは変数の型どうしで行われる



[ メッセージ編集済み 編集者: 未記入 編集日時 2006-03-31 14:30 ]

[ メッセージ編集済み 編集者: 未記入 編集日時 2006-03-31 14:34 ]
assa
会議室デビュー日: 2005/11/26
投稿数: 19
投稿日時: 2006-03-31 13:39
継承の問題は逆で、
ObjectはStringを継承していないってことでは?

Object[] objs = new Object[3]; //Object配列を宣言

String[] strs = (String[]) objs; //Objectでnewされてるのだから当然出来ない

配列だと中身は関係ないんでは?
配列管理のインスタンスObject[]と実際のObjectは違うと思ってますが。
管理クラスのObject[]は普遍で中身にStringを入れても、
入れ物はObject[]なのでString[]に出来ないのは当然かと。
ぶさいくろう
ぬし
会議室デビュー日: 2005/11/22
投稿数: 1232
お住まい・勤務地: 川崎市(は俺も含めてロクな人間が住んでないよw)
投稿日時: 2006-03-31 13:57
ことでは?って、なんでやねん・・・orz
途中の『脳内化学反応五段活用』の部分がもっさり抜けてるので意味わかりません・・・はい。

それと我々のいった『中身』の解釈をまちがってる人が多いみたいですな。
ややこしい言い方をしたのが悪いかもしれませんが、変数という名の箱の中身であるインスタンスを指しているのであって、配列の『要素』のことなど指していないのでいいかげんよろしく。
それを混同しているのはきっと質問者のみと先ほどから何度も書かれている。

まあ俺が悪いだけかもしれんけど、俺以外の人も言われてるしな・・・orz

[ メッセージ編集済み 編集者: ぶさいくろう 編集日時 2006-03-31 14:02 ]
Edosson
ぬし
会議室デビュー日: 2004/04/30
投稿数: 675
投稿日時: 2006-03-31 14:40
いや、もともとは配列のキャストの話だったし。
で、その配列の『要素』についても、『箱』と『中身』があるわけで、
その混同が、スレ主さんの誤解の原因じゃないですかね。
こんな投稿してるし。
引用:

投稿日時: 2006-03-29 20:41

従って、配列を要素毎に行うのも一気に行うのも同じと思っていたのですが、
(1)を
=============================================
Object[] obj = new String[3];
=============================================
に変更すると上手く行くという事は、実際には(2)でString型のインスタンスが
作成されている訳ではないのでしょうか?


変更前のスレ主さんのコードでは、配列objはObject[]型で生成されていたわけで、
その場合は、配列objの要素の型は、あくまでもObject型。
String型のインスタンスへの参照を代入したところで、
配列objの要素の型が変わる訳じゃない。
[追記]
今さらだけど、何人もの人が同じ事書いているし・・・。
「インターフェースについて勉強しよう」の方が早いのかな。

[ メッセージ編集済み 編集者: Edosson 編集日時 2006-03-31 14:42 ]
t_yamo
常連さん
会議室デビュー日: 2006/02/16
投稿数: 21
投稿日時: 2006-03-31 15:31
直接の回答ではありませんが、ひとまず仕様を見てみるのも良いかと。

10章の冒頭の「配列の構成要素型が T ならば,その配列自体の型をT[] とする」とか、15章4節の箇条書きの上から4つめの「SがTのサブ型ならば配列型S[]をT[]のサブ型として扱うことを許可する」あたりを見るとひょっとすると合点がいくのかも?

原文ではありませんが、以下、10章と15章。
http://www.y-adagio.com/public/standards/tr_javalang/10.doc.htm
http://www.y-adagio.com/public/standards/tr_javalang/15.doc.htm#79422

以下、原文。
http://java.sun.com/docs/books/jls/second_edition/html/j.title.doc.html
Cafe
会議室デビュー日: 2005/09/10
投稿数: 12
投稿日時: 2006-04-01 12:04
失礼します。

配列についてですが、要はその型の値を沢山入れられる箱の事です。
int型配列ならint型の値、String型の配列ならString型の値、Object型の配列ならObject型の値が格納できます。

次にObjectクラスと他のクラスの関係ですが、全てのクラスはObjectクラスを継承しています。つまり、Object型という箱はクラス型の中では一番大きい箱になります。

もう一つ、以下のようなコードを記述した場合、両方の配列の値が同一の場所を参照するようになる事を覚えておいて下さい。(参照渡し)
コード:

String[] s1 = new String[3];
String[] s2 = new String[10];
s1 = s2; // 参照渡し
s2[0] = "Hello";
System.out.println(s1[0]);




では、本題です。
コード:

Object[] obj = new Object[3];
obj[0] = new String("Hello");
obj[1] = new ArrayList();
obj[2] = new HashMap();


Object型配列の値が上記のようになっていたとしても、String配列に変換できると思いますか?

配列ではなく単体であれば実体は一つなので、以下のようにキャストできますが、
コード:

Object obj = new Object();
obj = "Hello";
String str = (String) obj;


配列という時点で、どこにどんなObjectが入っているかは保障されません。(Object配列には、どんなObjectも格納出来る・・という事です)
当然、String配列にString以外のObjectは入れられません。
なので、結果的にObject配列で生成したものを、String配列にキャストする事はできません。


# 投稿した後で気が付いたのですが、皆さん同じような事言ってますね。(^^;;;
# 偉そうに投稿しておいて、纏めただけになっちゃってます…。スミマセン…

[ メッセージ編集済み 編集者: Cafe 編集日時 2006-04-01 12:11 ]
ゴングラッチェ
常連さん
会議室デビュー日: 2006/03/03
投稿数: 36
投稿日時: 2006-04-03 16:45
すごいことになってますね。

さまざまなサンプルソースが掲載され実際に実行されたことと思います。ここまでくると、ソースの理解と実行を繰り返すことで理解できる見込みは薄いようです。読み返して理解する際に、「絵にしてみる」ことをお勧めします。
ここに回答をされている方々のほとんどは、キャストが行われる状況をソースで考えてはいないと思います。ほとんどは頭のなかでイメージ(絵、アニメーション)をしていて、それをソースとして記述していることと思います。
もし、OZさんがソースコードを必死に追って理解しようとされているのであれば、絵にしましょう。ObjectとStringの継承の関係、Objectに対するポインタ(変数)にStirngのインスタンスを指定するという行為、配列と要素の関係などなど。
絵にすることで、わからない場所が目に見える形で現れます。そこを補間する回答が、これまでの回答のどこかにあるはずです。それを絵に書き込みましょう。時には理屈が通らない箇所もあるかもしれません。そこがきっとOZさんの認識の誤りの箇所です。他の回答者が紹介されている解説サイトについても、絵にしてみることをお勧めします。

キャスト(オブジェクト指向におけるキャスト)についてイラストやアニメーションで解説がなされているサイトがあれば一発なんでしょうが・・・見つからないですねぇ。

スキルアップ/キャリアアップ(JOB@IT)