- ベストアンサー
「ラッパークラス」の存在意義が分かりません。
「ラッパークラス」の存在意義が分かりません。 ラッパークラスの使い方などについての解説はよく目にしますが、 その意義となると、明確な説明を見たことがありません。 (本質問では、使い方を質問しているわけではありません。) どういう意味で、便利なのか、 つまり、その存在価値について、お聞きしたいのです。 これがないと乗り越えられない壁があるのでしょうか。 その壁を乗り越えるための道具として、用意されたものであるなら、 その壁というものを教えて頂きたいです。 どなたか宜しくお願い致します。
- みんなの回答 (11)
- 専門家の回答
質問者が選んだベストアンサー
個人的に納得している状況を話しますね。 プリミティブなデータ(例えばint)はそれ自体に実体が あるから、「インスタンス化」なんてしませんよね。 ということは「null」には絶対にならないわけです。 ところで、データベースからレコードを読み込み、整数型の フィールドのデータを受け取ることを想定します。 そのフィールドがnullだった場合、受け取る変数がint型で あったら、「nullであること」を表現できません。nullと 0は違いますからね。でも、Integer型の変数ならnullにする ことができます。それにtoStringで編集したりできるのも ウレシイところです。 あと、リフレクションをやると分かりますけど、実行させる メソッドに渡す変数は本体の定義がプリミティブ型でも、 オブジェクト型の配列にする必要があるので、ラッパークラスに 限られます。
その他の回答 (10)
- hatimiti
- ベストアンサー率68% (26/38)
ちょろっと調べてみましたが、あるサイトにこんなことが書かれていました。 「オブジェクト指向言語なのにプリミティブ型を残したのは,C,C++などの互換性と,メモリ節約のためである」 C,C++との互換性というのは、native キーワードを使用する際に関わってくるのでしょうかね?(私も native は使った事ないのでわかりませんが) メモリの節約というのはちょっと思っていました。無駄なものがない分、プリミティブのほうがメモリ節約になるかと思います。(int=4byte, Integer=8byte なのか?) あと、引数として扱う場合、プリミティブは値渡し、オブジェクトは参照渡しとなるという違いもあるかと思います。
お礼
大変興味深く読ませて頂きました、 「プリミティブ型の存在意義」 についてのお話を。笑 CやC++との互換性(言語習得者への配慮的互換性といったところでしょうか)については、 その互換性は、本当に必要だったのか、と思えますけどね。 (もし、言語習得とは関係のない互換性、というのがあるのだとしたら、教えて頂けますでしょうか。CとJavaを連結?させてプログラムを組むなんて場合?の互換性?) 互換性の意味を取り違えると、せっかくのお話を誤解したままになってしまうので、 少々わざとらしく騒いでみました。笑 一方、そのあとに記述されていた、「メモリ節約のため」という所は、 私もその通りだと思います。この効果は言語設計の際、意図されていただろうと思います。 また、値渡し、参照渡しの件は、 むしろ、どちらかに統一されていた方が混乱が少なくて済むのではないかなと思えるので、 すべてをオブジェクトにし、渡し方もすべて参照渡しにする、 という方が良かったのではないか、という気もします。 以上、色々と考えさせられる回答でした。 大変参考になりました、ありがとうございます。
- Tacosan
- ベストアンサー率23% (3656/15482)
ちょろっと #7 に書いたんだけど, それをいうと「だったら最初から全部オブジェクトにしておけばいいじゃん」って突っ込まれそうな気がする>#9. 実際, 「純粋なオブジェクト指向言語」 (例えば Smalltalk) では「全てのものがオブジェクト」というきれいな世界を実現していたりしますし. で, こう考えると質問とは逆に「プリミティブ型の存在意義ってなんだろう」となってしまうわけでした. ああ, 質問に全く答えてないよ....
お礼
確かに、そうですよね、 プリミティブ型の方が、Javaの世界では異端児であり、 この異端児の存在を許したせいで、 ラッパークラスなるものを存在させることになってしまった、 と考えると、 「プリミティブ型の存在意義ってなんだろう」 こう考える方が、自然と言えば自然のような気がしますね。 私はJavaの前に、PHPというオブジェクト指向なしでも扱える言語を使っていたため、 このJavaの世界において、プリミティブ型を基準に、 オブジェクト型という謎なヤツと格闘してきましたが、 このJavaの世界では、逆にプリミティブ型って何やねん、なんですね。笑 PHPから渡ってきた私からすると、 Javaのオブジェクト指向度は凄まじいと感じましたが、Smalltalkを知ると、 Javaはプリミティブ型というのを残している点で、 ちょこっとオブジェクト指向型としては、不完全なわけですね。 大変よくわかりました。 ちょっと賢くなりました。
- PecoPlus
- ベストアンサー率76% (144/188)
#3です。 また、抽象的な説明になりつつありますが、お許しを。 透過的に扱う例として、比べるというものがあるかもしれません。 int i = 1; String str = "文字列"; この二つは、比べることができません。 if (i == str) もだめですし、 if (str.equals(i)) も、だめです。 (オートボクシングについては、とりあえず忘れてください) false が出てほしいのに、コンパイルエラーで、比べることすら許されません。 しかし、 Integer i = Integer.valueOf(1); String str = "文字列"; if (str.equals(i)) これは、可能で、ちゃんと、 false になります。 仮に、配列にプリミティブ型とオブジェクト型が混在できたとしましょう。 その中から、あるデータと同じものを探すというのは、ありそうなことです。 そんな時はいったいどうしましょう? プリミティブ型とオブジェクト型の型検査ができたとしても(Java では無理ですが) 1. 配列からデータを一つ取り出す。 2. プリミティブ型かオブジェクト型かを調べる。 3. プリミティブ型なら、比べるデータとさらに型があっているかどうか調べ、違うならfalse。 4. 同じなら、改めて、比べる こんな複雑なことをするくらいなら、最初からラッパークラスに包んで、すべて equals メソッドで比べた方が、透過的で、シンプルです。
お礼
文字修飾情報の例で、さらに詰めて補足して頂けるものと期待しておりましたが、 今度はちょっと角度を変え、equals()に着目した例でした。 複数(例としてここでは2つ)の変数のデータ比較をする際、 それら複数の変数の型が、それぞれプリミティブ型より、それぞれオブジェクト型である方が、 都合が良い、ということですよね? オブジェクト型どうしの比較であれば、 equals()を使うことができ、これを使うことで簡単に比較結果を得られるからです。 比較対象にある複数の変数がそれぞれ、 プリミティブ型かつ同一の型(intどうしとか)ならば、 わざわざラッパークラスを出すまでもないのでしょうが、 このような、かなり限定されたケースは珍しく、 より汎用的に、複数の変数を比較することを考えた場合には、 ラッパークラスでもって、equals()を使い、目的を果たす方が楽、 ということなのでしょう。 データを、プリミティブ型からオブジェクト型に昇格(?笑)させることで、 より複雑な扱い方が可能になる、とも言えますでしょうか。 できることが広がったという意味で複雑になったように思いますが、 それを使うことで、単純な方法で、したいことができるようになったわけで、 そこに、このラッパークラスの真価(存在意義)があるのでしょう。 バラバラなプリミティブ型のデータを、 皆、オブジェクト型にラップすることで、 共通した扱い方が可能となる、そんなイメージがわいてきました。 プリミティブ型と、オブジェクト型がそれぞれどういう仕様で、 また、両者がどう異なるのか、を理解することが、 もしかしたら、本問の解決の近道なのかもしれません。 いやはや、おかげさまで、ゴールは近そうです。笑
- PecoPlus
- ベストアンサー率76% (144/188)
#3です。 長々と書いてしまいましたが、どちらかというと、 > プリミティブ型とオブジェクト型、型が違うからと言って、 >「文字の色」「太字か否か」「大きさ」などを別々の場所に >格納するのはおかしな話です。 > すべてをオブジェクト型にしてしまえば、これらの意味情報を >同列に扱うことでできるのです。 こっちを言いたかったわけです。 「文字の色」「太字」「大きさ」、これらは、文字列を修飾する情報という点で仲間です。 できるなら、「文字列修飾情報」という一つの袋にまとめて入れておきたいわけです。 それなのに、 「文字の色はColorクラスなのでオブジェクト袋に入れて、太字はboolean袋に入れて、大きさはinteger袋に入れよう」 なんて事をやっていると、情報がバラバラになってしまいます。 重要なのはデータの意味であって、型ではありません。 すべてをオブジェクト型として、情報を透過的かつシンプルに扱うというのは、オブジェクト指向では、重要なのです。 似たような考え方として、抽象クラスやインターフェースが存在します。 これらも、なくてもプログラムは作れますが、使いこなせば、同じ意味を持つ違うクラスを透過的かつシンプルに扱えるようになります。
お礼
>どちらかというと、(中略)こっちを言いたかったわけです。 そっちでしたか、すみません。笑 >文字列修飾情報という一つの袋にまとめて入れておきたい >なんて事をやっていると、情報がバラバラになってしまいます。 そういった概念をまず、頭に入れておきます。言わんとすることはよく分かります。 例えば、PHPという言語の配列では、データ型関係なく、 値を配列に格納していけます。 つまり、 arr = array(); arr[0] = 5; arr[1] = "たこやき"; arr[2] = TRUE; ということができます。 この場合、配列arr の中には、数値も文字列も真偽値も入っていることになります。 もし、このようなことができるのであれば、 arr[0] = 1; arr[1] = "red"; arr[2] = "bold"; arr[3] = "24pt"; という風にすれば、 このarr1つで、文字列修飾情報を1箇所にまとめられたことになります。 で、これをJavaでするなら、 ラッパークラスを使うと便利ですよ、ということでしょうか? ちなみに、 >すべてをオブジェクト型にしてしまえば、これらの意味情報を同列に扱うことでできるのです。 とありましたが、 この「同列に扱う」とは、どういった意味でしょうか? プリミティブ型(int):ID情報 プリミティブ型(String):色情報 プリミティブ型(int):太さ情報 プリミティブ型(int):サイズ(pt)情報 ↓ オブジェクト型(object):ID情報 オブジェクト型(object):色情報 オブジェクト型(object):太さ情報 オブジェクト型(object):サイズ情報 こうすることで、何か良いことがあるのでしょうか? (私は何か勘違いをしてそうですが、誤解を恐れずに質問させて頂きました。笑) あえて、誇張して書いている部分もありますが、 それは問題箇所を明確にするためだったりします。(ほんとか。笑) また宜しければ、アドバイスをお願い致します。
- Tacosan
- ベストアンサー率23% (3656/15482)
まあ確かに「ラッパクラスの意義」って難しいと思う. 逆に考えれば「プリミティブ型を含めてすべて『オブジェクト』としておけば『ラッパクラス』そのものが不要」なので.... そういう意味では「最初の『アレ』な設計を覆い隠す」というのが意義なのかもしれない.
お礼
またしてもありがとうございます。 皆さんからアドバイスを受けてきて、今思うことは、 私の疑問というのは、つまり、 プリミティブ型を、オブジェクト型に変換する意義、 が分からん、ということなのでしょうね。 どうして、プリミティブ型のままじゃダメなのさー!! え、なになにっ、 オブジェクト型じゃないと、受け付けないメソッド野郎が存在するからだと? また、 オブジェクト型にすることで、便利なメソッドが使えるようになり、 プリミティブ型ではできなかったことが、できるようになるだって?? それは本当か! というオチで、大雑把には、よろしいでしょうか。 と、今、どなたかに質問したいと思っているのですが…。 なお、もしまだ、隠されている意義が他にもあるようでしたら、 追加して頂けると嬉しいです。
- PecoPlus
- ベストアンサー率76% (144/188)
#3です。 ArrayListじゃあ納得できませんか。 では、もっと、具体的に。 サンプルコードをみてください。 public class Test extends JFrame { JTextPane textPane; DefaultStyledDocument document; public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { public void run() { Test frame = new Test(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(400, 300); frame.setVisible(true); } }); } public Test() { document = new DefaultStyledDocument(); textPane = new JTextPane(document); try { //属性情報を作成 SimpleAttributeSet attribute = new SimpleAttributeSet(); //属性情報の文字色に赤を設定 attribute.addAttribute(StyleConstants.Foreground, Color.RED); //属性情報に太字を設定 attribute.addAttribute(StyleConstants.Bold, Boolean.TRUE); //属性情報に文字サイズ20を設定 attribute.addAttribute(StyleConstants.FontSize, Integer.valueOf(20)); //ドキュメントにその属性情報つきの文字列を挿入 document.insertString(0, "あいうえお\n", attribute); } catch (BadLocationException ex) { ex.printStackTrace(); } add(textPane, BorderLayout.CENTER); } } 属性情報の作成部分をみてください。 文字色を赤、太字、サイズを設定しています。 太字とサイズの第2引数に注目してみてください。 ラッパークラスです。 どうしてでしょう? それは、このメソッドの第2引数がObject型しか受け付けないから、致し方なくラッパークラスにせざるを得ません。 「いやいや、こんなのメソッドオーバーロードで対処可能でしょう。このメソッドを作った人が手抜きです」 と、言うかもしれませんが、そんなに単純ではありません。 SimpleAttributeSet クラスは、内部では Hashtable を使ってこれらの情報を格納しますので、結局、最終的にはラッパークラスにせざるを得なくなります。 プリミティブ型とオブジェクト型、型が違うからと言って、「文字の色」「太字か否か」「大きさ」などを別々の場所に格納するのはおかしな話です。 すべてをオブジェクト型にしてしまえば、これらの意味情報を同列に扱うことでできるのです。
お礼
わざわざ、私のために長いコードを書いて説明下さり、誠にありがとうございます。 こんなにして頂いたにも関わらず、 なんと、私はそれでもまだよく分からない状態なのです。苦笑 回答をまとめますと、 要するに、 「このメソッドの第2引数がObject型しか受け付けないから、致し方なくラッパークラスにせざるを得ません」 ということですよね。 つまり、オブジェクト型しか受け付けないメソッドがこの世には存在し、 そういう時には、プリミティブ型でデータを渡すことはできないので、 ラッパークラスで、そのプリミティブ型のデータをオブジェクト型に変換する必要がある、 ということなのでしょう。 nda23さんの回答にあったような意味合いですよね?、おそらく。 さて、具体例を書いて頂きましたが、 本件は、「もう、これでもかというほど、単純なコード」では、説明不可能な事例なのでしょうか。 もっとこう、なんと言いますか、 「すぱっ、うわっ、そっか! なるほどー。どひゃー。」的なコードを 実はこっそり期待しております。 もしよろしければ、また教えてください。^^
- mtaka2
- ベストアンサー率73% (867/1179)
ラッパークラスは、既存のライブラリを流用するときに力を発揮します。 似たような機能を提供するクラスAとクラスBがあり、 提供する機能の違いとかの理由で、 この二つのクラスを使い分けしたい場合を考えます。 (例えば、特殊な画像フォーマットに対する読み書きを行いたい場合とかで、 全形式を網羅するライブラリが無いから、画像フォーマットごとに複数のライブラリを使い分ける必要がある、とか) ここでAとBは機能は似てますが、メソッド名などはてんでバラバラだったら… そうなると、Aを使うコードとBを使うコードは別個に書く必要が出てきます。 そういうとき、同じインターフェースを持つラッパークラスを作り、 それを通してAとBを使うようにすると、 利用するコード側は共通化できますので、無駄がなくなりシンプルにできます。
お礼
うぬぉ? 今までの回答と、何か違うぞ。。。と思いながら、最後まで読み進めましたところ、 これは、自作ラッパークラスの意義、についての説明ということが分かりました。 誠に申し訳ありません。 そういうものもあるのですね、、、。 ここでは、ライブラリにある、 なんといいますか、プリミティブ型をオブジェクト型に変換する、 あの例のラッパークラスというやつについて、質問していたのでした。 しかし、頂いた回答は、それはそれで、いつかお役に立てたいと思います。 私のために回答下さり、ありがとうございました。
- PecoPlus
- ベストアンサー率76% (144/188)
こんにちは。 >こんな私に、端的な例として、何か挙げて下さると >大変有り難く思います。最も単純な例で結構です。 int n = 1; ArrayList list = new ArrayList(); 「ああ、ArrayListは、Object型しか入らない。どうしよう」 「えーい、包んじゃえー」 list.add(new Integer(n));
お礼
私にもう少し力があれば、おそらく、言わんとすることは理解できるのだと思います。 ここで理解を阻む壁となっているのは、ArrayListですね。 ArrayListなしの、端的な別の例を挙げて頂けると有り難いです。 この例ですと、 オブジェクト型のInteger(n)を使う前提で、 それを入れるのに、ArrayListを使っているように思えてしまいました。 つまり、ArrayListの方に目が行ってしまったのです。 ちょっとバカなことをここで書きますが、 int n = 1; をオブジェクト型にしないで、 そのまま、int型で、配列にでも入れて使えば良いのでは? と思えてしまうのです。 たぶんこのように書くと、 いやいや、きみ、そうではなくて、 この int型のnをだね、オブジェクト型にして、使いたいのだよ。 だから、Integer(n)としているのではないか。 と言われてしまいそうなのですが、 そこがそもそも、違っていて、 私が知りたいのは、 「この int型のnをだね、オブジェクト型にして、使いたいのだよ。」 の理由なんです。 なぜ、オブジェクト型に変換(つまり、ラッパークラスの利用)をしたいのか、 ということです。 その具体例で良さそうなものが、もし、ありましたら教えて下さい。
- D-Matsu
- ベストアンサー率45% (1080/2394)
ラッパー(wrapper)、要は「包む」ことですね。 何を包んでいるのかというと、「面倒な手続き一切合財」であるものがほとんどです。 ある機能を実現するのに必要な手続きを全てラッパー関数内に押し込めて、使う人はその関数を呼ぶだけにしておけば非常に楽ですし、間違いも起こりにくいですよね? これについては、使う方よりも使わない方に壁がある事が多いです。 ないと面倒、ってところから来ているので。
お礼
「ないと面倒、ってところから来ている」 無いとどのくらい面倒なのでしょうね? (有るとどのくらい楽なのでしょうね?) JAVA超初心者の私からすると、 何が便利なのか、さっぱり分からないのです。 こんな私に、端的な例として、何か挙げて下さると大変有り難く思います。 最も単純な例で結構です。 もし可能でしたら、また色々と教えて下さい。宜しくお願い致します。
- chie65536(@chie65535)
- ベストアンサー率44% (8741/19839)
存在意義は「あると楽」というだけ。 言わば「ライブラリと同じ」です。 ライブラリを一切使わなくとも、ハナから全部自分で書けば、文字列を数値に変換したり、その逆も可能です。 それと同じで、ラッパークラスを一切使わなくとも、ハナから全部自分で書けば、ラッパークラスで出来る事は全部出来ます。 でも「ハナから全部自分で書くのは面倒」だし「誰かが同じようなモノをクラス化して用意してくれれば、みんなが使う」でしょう? で「みんなが使う」には「統一規格」になっていた方が便利だから「統一化して標準化」って事になりますよね? そして「統一化して標準化」した結果「今あるラッパークラス」が存在します。 乗り越えられない壁がある訳じゃないけど、人間ってのは「徒歩よりも自転車」「自転車よりもバイク」「バイクよりも自動車」「自動車よりもタクシー(自分で運転しない分、楽)」と「出来る限りラクをしたいイキモノ」なので「ラクできると言う事実が存在意義になり得る」のです。
お礼
「こういうものが使えると楽だろう、だから作ったのです」 といった性質のものなのですね。 よく分かりました。 で、肝心の、 「具体的に、どう楽になったのか」 について、お聞きしたいのですが、もしお分かりでしたら教えて下さい。 つまり、 これがないと、どう不便なのか、 もっと言うと、 「これがないと、どういった面倒な作業を強いられるのか、 そして、 これがあることで、それがどう楽になるのか」 について、大変興味があります。 「ラッパークラスがあることで、 このラッパークラスを使うと、こういう作業をすることになります。」 という作業はある程度、目にしてきましたが、 「ラッパークラスがないと、 こういったことをしたいときに、こんな大変な作業を強いられます。」 といった、具体的コード例を示した形での記述は見たことがありません。 もちろん、こうした事は他のライブラリについても同様に言えることだと思うのですが、 ここでは特に、このラッパークラスについて、 私はその利便性(の具体的内容)を知りたく思い、今回、質問させて頂きました。 もし宜しければ、また色々と教えてください。
お礼
こちらの回答を読み、また一歩、理解が深まりました。 核心に触れた回答をありがとうございます。 ・プリミティブなデータ型では、nullを受け取れない。 ・オブジェクトならば、toStringメソッドで編集ができる。 (つまり、ラッパークラス付属の各メソッドが使える。 もっとも、そのメソッドの中に、どんな便利なものがあるのかが、 具体例として、ここでは知りたいわけですが。) ・リフレクションのことはまだ分かりませんが、このリフレクションの分野において、 プリミティブなデータをオブジェクト型に変換する必要性があり、その際に、 ラッパークラスのようなものがあると便利、ということですね。 以上、ざっくりとではありますが、ラッパークラスの意義が見えてきました。 大枠が掴めてきた、といった感じです。